$npx -y skills add DanWahlin/github-azure-agentic-journeys --skill grafana-azureDeploy Grafana OSS to Azure Container Apps. Use when deploying Grafana for metrics, logs, and traces visualization with optional PostgreSQL backend.
| 1 | # Grafana Azure Deployment Skill |
| 2 | |
| 3 | Deploy Grafana OSS to Azure Container Apps using Bicep and Azure Developer CLI (azd). |
| 4 | |
| 5 | > **Reproducibility Verified**: This deployment has been tested multiple times from scratch. Deploy time: ~2 minutes. |
| 6 | |
| 7 | ## Overview |
| 8 | |
| 9 | Grafana is an open-source observability platform for metrics, logs, and traces visualization. This skill deploys Grafana OSS (not Azure Managed Grafana) to Azure Container Apps. |
| 10 | |
| 11 | ## Prerequisites and Portability |
| 12 | |
| 13 | Require Azure CLI, Azure Developer CLI 1.28.0 or later, and Node.js 24 LTS or later for portable verification. Don't require OpenSSL, Bash command substitution, or host-specific shell scripts. See `../../../docs/tool-installation.md`. |
| 14 | |
| 15 | ## Critical: Infrastructure Generation |
| 16 | |
| 17 | This skill provides Grafana-specific configuration only. Infrastructure (Bicep, azure.yaml) should be generated fresh each time by the official `azure-prepare` → `azure-validate` → `azure-deploy` pipeline. Do NOT rely on pre-existing infra code. |
| 18 | |
| 19 | ## Critical: Subscription Context |
| 20 | |
| 21 | **ALWAYS set AZURE_SUBSCRIPTION_ID explicitly before running `azd up`.** Read it with `az account show --query id -o tsv`, then pass the returned value to `azd env set AZURE_SUBSCRIPTION_ID <subscription-id>`. |
| 22 | |
| 23 | Without this, azd and Azure MCP tools will fail silently or produce incomplete deployments. The `azure_deploy_app_logs` tool also requires subscription context. |
| 24 | |
| 25 | ## Critical: Bicep Output Naming |
| 26 | |
| 27 | Bicep outputs MUST use SCREAMING_SNAKE_CASE (e.g., `GRAFANA_URL`, `GRAFANA_FQDN`) for azd to map them into environment values. Without this, `azd env get-value` returns "key not found". |
| 28 | |
| 29 | ## Architecture |
| 30 | |
| 31 | ```mermaid |
| 32 | graph TB |
| 33 | subgraph RG["Azure Resource Group"] |
| 34 | LA["Log Analytics Workspace"] |
| 35 | subgraph CAE["Container Apps Environment"] |
| 36 | GF["Grafana Container App<br/>Port 3000 · SQLite (default)<br/>Scale 0-3 replicas"] |
| 37 | end |
| 38 | end |
| 39 | |
| 40 | LA -->|logs & metrics| CAE |
| 41 | ``` |
| 42 | |
| 43 | ## Quick Start (Verified) |
| 44 | |
| 45 | ```text |
| 46 | # 1. Register providers (one-time per subscription) |
| 47 | az provider register --namespace Microsoft.App |
| 48 | az provider register --namespace Microsoft.OperationalInsights |
| 49 | |
| 50 | # 2. Create environment |
| 51 | azd env new my-grafana-env |
| 52 | |
| 53 | # 3. Set required variables (replace placeholders) |
| 54 | azd env set AZURE_SUBSCRIPTION_ID "<subscription-id>" |
| 55 | azd env set AZURE_LOCATION "westus" |
| 56 | azd env set GRAFANA_ADMIN_PASSWORD "<securely-generated-secret>" |
| 57 | |
| 58 | # 4. Deploy (~2 minutes) |
| 59 | azd up |
| 60 | |
| 61 | # 5. Access Grafana |
| 62 | azd env get-value GRAFANA_URL |
| 63 | # Login: admin / <your GRAFANA_ADMIN_PASSWORD> |
| 64 | ``` |
| 65 | |
| 66 | **Deployment time breakdown:** |
| 67 | - Resource Group: ~4s |
| 68 | - Log Analytics: ~25s |
| 69 | - Container Apps Environment: ~38s |
| 70 | - Grafana Container App: ~10s |
| 71 | - **Total: ~2 minutes** |
| 72 | |
| 73 | ## Environment Variables |
| 74 | |
| 75 | Grafana is configured via environment variables in the Container App: |
| 76 | |
| 77 | | Variable | Description | Value | |
| 78 | |----------|-------------|-------| |
| 79 | | `GF_SECURITY_ADMIN_USER` | Admin username | From parameter | |
| 80 | | `GF_SECURITY_ADMIN_PASSWORD` | Admin password | From secret | |
| 81 | | `GF_SERVER_HTTP_PORT` | HTTP port | 3000 | |
| 82 | | `GF_SERVER_ROOT_URL` | Public URL | Auto-configured | |
| 83 | | `GF_AUTH_ANONYMOUS_ENABLED` | Anonymous access | false | |
| 84 | |
| 85 | See [config/environment-variables.md](config/environment-variables.md) for full list. |
| 86 | |
| 87 | ## Health Probes |
| 88 | |
| 89 | | Type | Path | Port | Interval | |
| 90 | |------|------|------|----------| |
| 91 | | Liveness | /api/health | 3000 | 30s | |
| 92 | | Readiness | /api/health | 3000 | 10s | |
| 93 | | Startup | /api/health | 3000 | 10s (30 failures allowed) | |
| 94 | |
| 95 | ## Outputs |
| 96 | |
| 97 | After deployment: |
| 98 | - **GRAFANA_URL**: Public HTTPS URL |
| 99 | - **GRAFANA_FQDN**: Container App FQDN |
| 100 | - **GRAFANA_ADMIN_USER**: Admin username |
| 101 | |
| 102 | ## Verification |
| 103 | |
| 104 | Run the checked-in verifier from the repository root: |
| 105 | |
| 106 | ```text |
| 107 | node .github/scripts/verify-grafana.mjs |
| 108 | ``` |
| 109 | |
| 110 | The verifier reads `GRAFANA_URL` through `azd`, requires HTTP 200 from `/api/health`, asserts `database: "ok"`, and prints the deployment URL. Verify authenticated browser login separately with the deployed admin credentials. Retrieve a generated password only in a private terminal, and never print or paste it into the agent session or shared logs. |
| 111 | |
| 112 | ## Scaling |
| 113 | |
| 114 | - **Min replicas**: 0 (scale to zero when idle) |
| 115 | - **Max replicas**: 3 |
| 116 | - **Scaling rule**: HTTP concurrent requests (10 per replica) |
| 117 | |
| 118 | ## Storage Considerations |
| 119 | |
| 120 | By default, Grafana uses SQLite which stores data in the container. For production: |
| 121 | 1. Add Azure Files for persistent storage |
| 122 | 2. Or use PostgreSQL/MySQL backend |
| 123 | |
| 124 | ## Tear Down |
| 125 | |
| 126 | ```bash |
| 127 | azd down --force --purge |
| 128 | ``` |
| 129 | |
| 130 | **Note:** Teardown takes 3-5 minutes (Container Apps environment deletion is slow). |
| 131 | |
| 132 | ## Azure MCP Tools |
| 133 | |
| 134 | Use these Azure MCP Server tools for Grafana deployments: |
| 135 | |
| 136 | | Tool | When to Use | |
| 137 | |------|-------------| |
| 138 | | `azure_bicep_schema` | Get latest schemas for `Microsoft.App/containerApps` and `Microsoft.App/managedEnvironments` | |
| 139 | | `a |