This guide describes how to deploy the example Go application to Azure Kubernetes Service (AKS) with Dapr and Azure SQL Database as the state store.
- Azure CLI (
az) logged in kubectlconfigured for your AKS cluster- Dapr installed on the cluster (
dapr init -k) - Azure SQL Database created and accessible from the cluster
See architecture.md for Mermaid diagrams.
The app uses a Dapr State Store component (Kubernetes Component resource) to persist state in Azure SQL. The Dapr sidecar reads the component config and connects to Azure SQL; the app never talks to the database directly.
- Logs: The app uses slog and writes JSON logs to stdout. Container logs are collected by Promtail, Fluent Bit, Datadog Agent, or similar, and sent to Grafana Loki or Datadog Logs. No app configuration needed.
- Traces and metrics: The app emits OpenTelemetry traces and metrics for HTTP requests when
OTEL_EXPORTER_OTLP_ENDPOINTis set. Data flows to an OTLP-compatible backend:
| Backend | OTLP endpoint example |
|---|---|
| Grafana (Alloy + Tempo + Prometheus) | http://alloy:4318 |
| Datadog Agent | http://datadog-agent:4318 |
-
Create a resource group and SQL server (if not exists):
az sql server create --name <server-name> --resource-group <rg> --location <location> \ --admin-user <admin> --admin-password <password>
-
Create the database:
az sql db create --resource-group <rg> --server <server-name> --name daprstate
-
Configure firewall to allow AKS egress IPs or use Private Endpoint for production.
Create a Kubernetes secret with the connection string. Keep the entire connection string on one line—newlines will break DNS resolution (e.g. lookup example-sqlserver2.database.windows.net: no such host):
kubectl create secret generic azuresql-secret --from-literal=connectionString='Server=tcp:<server>.database.windows.net,1433;Database=<database>;User ID=<user>;Password=<password>;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'Apply the Dapr component:
kubectl apply -f docs/dapr-component.yamlSee dapr-component.yaml for the full example.
For Azure AD authentication (recommended for production), use useAzureAD: true and configure the component with Managed Identity or service principal.
Option A: Use pre-built image from GitHub Container Registry
Images are built automatically on push to main. Pull the latest:
docker pull ghcr.io/miguelmartens/example-go-dapr-otel:latestOption B: Build and push to your own registry (ACR, Docker Hub, etc.)
docker build -f build/package/Dockerfile -t <registry>/example-go-app:latest .
docker push <registry>/example-go-app:latestApply the deployment manifest. See kubernetes-deployment.yaml for the example.
The deployment includes Kubernetes health probes using /livez and /readyz (Kubernetes API health endpoint convention):
- Startup probe (
/readyz): Allows up to 60s for the app and Dapr sidecar to initialize. - Readiness probe (
/readyz): Removes the pod from Service endpoints when not ready to accept traffic. - Liveness probe (
/livez): Restarts the container when unrecoverable; uses a higherfailureThresholdthan readiness to avoid premature restarts.
Update the image reference and any environment variables, then:
kubectl apply -f docs/kubernetes-deployment.yamlkubectl get pods -l app=example-go-app
kubectl logs -l app=example-go-app -c example-go-app -fTo access the app from your machine, port-forward the Service to localhost:
kubectl port-forward svc/example-go-app 8080:80Then test the API at http://localhost:8080:
# Save state
curl -X POST http://localhost:8080/api/v1/state/mykey -d '{"value":"hello"}'
# Get state
curl http://localhost:8080/api/v1/state/mykey
# Delete state
curl -X DELETE http://localhost:8080/api/v1/state/mykey
# Health check
curl http://localhost:8080/healthPress Ctrl+C to stop the port-forward.
- Logs: The app writes JSON logs to stdout. Deploy a log collector (Promtail, Fluent Bit, Grafana Alloy, or Datadog Agent) to ship container logs to Grafana Loki or Datadog Logs. No app configuration needed.
- Traces and metrics: Set
OTEL_EXPORTER_OTLP_ENDPOINTto your OTLP receiver:- Grafana: Deploy Grafana Alloy or similar OTLP receiver; expose an OTLP HTTP endpoint (default port 4318). Point the app to it (e.g.
http://alloy.monitoring:4318). - Datadog: Deploy the Datadog Agent with OTLP enabled; use the agent service (e.g.
http://datadog-agent.datadog:4318).
- Grafana: Deploy Grafana Alloy or similar OTLP receiver; expose an OTLP HTTP endpoint (default port 4318). Point the app to it (e.g.
Add the env vars to your Deployment (see kubernetes-deployment.yaml for commented examples).
To deploy via GitOps, create an ArgoCD Application. See argocd-application.yaml for an example.
Ensure your Kubernetes manifests are in a Git repository, then apply the Application:
kubectl apply -f docs/argocd-application.yaml| Resource | Purpose |
|---|---|
Dapr Component (statestore) |
Configures Azure SQL as the state store backend for Dapr |
| Dapr Sidecar | Connects to Azure SQL via the component; app uses Dapr client for state |
| Logs (slog) | App writes JSON logs to stdout; collected by Promtail/Fluent Bit/Datadog Agent → Loki/Datadog Logs |
| OpenTelemetry | App emits traces/metrics to OTLP when OTEL_EXPORTER_OTLP_ENDPOINT is set |
| Grafana / Datadog | OTLP backends for traces/metrics; Loki/Datadog Logs for logs |
| Variable | Default | Description |
|---|---|---|
APP_PORT |
8080 |
HTTP server port |
STATESTORE_NAME |
statestore |
Dapr state store component name |
OTEL_EXPORTER_OTLP_ENDPOINT |
(none) | OTLP endpoint for traces/metrics |
OTEL_SERVICE_NAME |
example-go-app |
Service name for telemetry |
- Dapr sidecar not starting: Check pod annotations (
dapr.io/enabled,dapr.io/app-id,dapr.io/app-port). - State operations fail: Verify the Dapr component is applied and the Azure SQL secret exists. Check Dapr sidecar logs:
kubectl logs <pod> -c daprd. - No traces/metrics: Ensure
OTEL_EXPORTER_OTLP_ENDPOINTis set and the OTLP receiver (Grafana Alloy, Datadog Agent, etc.) is reachable from the pod. - Connection refused to Dapr: Ensure the app listens on the port specified in
dapr.io/app-port.
Remove Kubernetes resources:
# Deployment and Service
kubectl delete -f docs/kubernetes-deployment.yaml
# Dapr component
kubectl delete -f docs/dapr-component.yaml
# Azure SQL secret
kubectl delete secret azuresql-secretTo remove Azure SQL resources (database, server, resource group):
az sql db delete --resource-group <rg> --server <server-name> --name daprstate --yes
az sql server delete --resource-group <rg> --name <server-name> --yes
# Optionally delete the resource group:
# az group delete --name <rg> --yes --no-wait