> ## Content Index
> Fetch the complete content index at: https://www.azurebrasil.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Azure Managed Grafana + Prometheus no AKS: alertas, multi-cluster e troubleshooting - Parte 2
- URL: https://www.azurebrasil.cloud/blog/azure-managed-grafana-prometheus-no-aks-alertas-multi-cluster-e-troubleshooting-parte-2/
- Published: 2026-06-22T12:37:12.000Z
- Updated: 2026-06-22T12:37:12.000Z
- Author: Ricardo Martins

Na [Parte 1](https://markdownonline.org/azure-managed-grafana-prometheus-aks-parte-1-setup-metricas-dashboards.md?ref=azurebrasil.cloud), provisionamos toda a infraestrutura de observabilidade — Azure Monitor workspace, Managed Grafana e Prometheus no AKS — além de configurar scrape de métricas customizadas e construir dashboards avançados com PromQL. Agora, vamos avançar para Recording Rules, Alerting Rules, monitoramento multi-cluster, dashboards como código, instrumentação de aplicações e troubleshooting dos problemas mais comuns em produção.

## Recording Rules e Alerting Rules

Recording rules pré-computam queries complexas para performance, e alerting rules disparam notificações quando condições são atendidas. Ambas usam PromQL.

### Recording Rules

Recording rules são executadas periodicamente e salvam o resultado como uma nova série temporal. Útil para queries caras que seriam lentas em dashboards.

```yaml
# prometheus-rules.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ama-metrics-prometheus-config
  namespace: kube-system
data:
  recording-rules: |
    groups:
    - name: kubernetes_resource_usage
      interval: 60s
      rules:
      - record: namespace:container_cpu_usage:sum_rate5m
        expr: |
          sum by (namespace) (
            rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])
          )

      - record: namespace:container_memory_working_set:sum
        expr: |
          sum by (namespace) (
            container_memory_working_set_bytes{container!="", container!="POD"}
          )

      - record: node:cpu_utilization:ratio
        expr: |
          1 - avg by (instance) (
            rate(node_cpu_seconds_total{mode="idle"}[5m])
          )

    - name: api_slis
      interval: 30s
      rules:
      - record: api:http_request_error_rate:ratio_rate5m
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m]))
          /
          sum(rate(http_requests_total[5m]))

      - record: api:http_request_latency_p99:seconds
        expr: |
          histogram_quantile(0.99,
            sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
          )

```

### Alerting Rules com Azure Managed Prometheus

Alerting rules no Azure Managed Prometheus são configuradas como **Prometheus Rule Groups** via Azure Resource Manager, não via ConfigMap. Isso é diferente do Prometheus self-hosted e pega muita gente de surpresa.

```bash
# Criar regra de alerta via CLI
az monitor account rule-group create \
  --name "kubernetes-critical-alerts" \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --cluster-name $AKS_CLUSTER \
  --scope $MONITOR_WORKSPACE_ID \
  --interval PT1M \
  --rules '[
    {
      "alert": "PodCrashLooping",
      "expression": "increase(kube_pod_container_status_restarts_total[1h]) > 5",
      "for": "PT10M",
      "severity": 2,
      "labels": {
        "team": "sre",
        "severity": "critical"
      },
      "annotations": {
        "summary": "Pod {{ $labels.namespace }}/{{ $labels.pod }} está em crash loop",
        "description": "O pod {{ $labels.pod }} no namespace {{ $labels.namespace }} reiniciou mais de 5 vezes na última hora."
      }
    },
    {
      "alert": "NodeMemoryPressure",
      "expression": "100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 90",
      "for": "PT5M",
      "severity": 1,
      "labels": {
        "team": "infra",
        "severity": "critical"
      },
      "annotations": {
        "summary": "Node {{ $labels.instance }} com memória acima de 90%",
        "description": "O node {{ $labels.instance }} está usando {{ $value }}% de memória há mais de 5 minutos."
      }
    },
    {
      "alert": "HighErrorRate",
      "expression": "api:http_request_error_rate:ratio_rate5m > 0.05",
      "for": "PT5M",
      "severity": 2,
      "labels": {
        "team": "backend",
        "severity": "warning"
      },
      "annotations": {
        "summary": "Taxa de erros HTTP acima de 5%",
        "description": "A taxa de erros HTTP 5xx está em {{ $value | humanizePercentage }} nos últimos 5 minutos."
      }
    }
  ]'

```

### Integrando alertas Prometheus com Action Groups

Para que os alertas disparem notificações reais (email, Teams, PagerDuty, webhook), você precisa conectar os Prometheus alerts com Azure Monitor Action Groups:

```bash
# Criar Action Group
az monitor action-group create \
  --name "ag-sre-oncall" \
  --resource-group $RESOURCE_GROUP \
  --short-name "SRE" \
  --email-receiver name="sre-lead" email-address="sre@empresa.com" \
  --webhook-receiver name="pagerduty" uri="https://events.pagerduty.com/integration/XXXX/enqueue"

# Criar Alert Processing Rule que conecta alertas Prometheus ao Action Group
az monitor alert-processing-rule create \
  --name "route-prometheus-alerts" \
  --resource-group $RESOURCE_GROUP \
  --rule-type AddActionGroups \
  --scopes $MONITOR_WORKSPACE_ID \
  --action-groups "/subscriptions/{sub-id}/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Insights/actionGroups/ag-sre-oncall"

```

## Cenário avançado: Monitoramento multi-cluster

Um dos maiores benefícios do Azure Managed Prometheus sobre o self-hosted é o monitoramento multi-cluster nativo. Com Prometheus self-hosted, você precisaria de Thanos ou Cortex para agregar métricas de vários clusters. Com Azure Managed Prometheus, basta apontar todos os clusters para o mesmo workspace.

### Arquitetura multi-cluster

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2026/05/grafana-prometheus-multi-cluster.svg)

### Configurando um segundo cluster

```bash
# Segundo cluster — mesmo workspace, mesmo Grafana
az aks update \
  --name "aks-staging-brazil" \
  --resource-group "rg-staging" \
  --enable-azure-monitor-metrics \
  --azure-monitor-workspace-resource-id $MONITOR_WORKSPACE_ID \
  --grafana-resource-id $GRAFANA_ID

```

### Queries multi-cluster em PromQL

Cada cluster adiciona um label `cluster` às métricas. Isso permite queries que comparam ou agregam entre clusters:

**Uso de CPU por cluster:**

```promql
avg by (cluster) (
  1 - rate(node_cpu_seconds_total{mode="idle"}[5m])
) * 100

```

**Pods com problema em todos os clusters:**

```promql
sum by (cluster, namespace) (
  kube_pod_status_phase{phase=~"Failed|Pending|Unknown"}
)

```

**Comparação de latência entre ambientes:**

```promql
histogram_quantile(0.95,
  sum by (le, cluster) (
    rate(http_request_duration_seconds_bucket{app="api-pedidos"}[5m])
  )
)

```

## Dashboards como código com Terraform

Para times que praticam GitOps, gerenciar dashboards manualmente pelo browser é inaceitável. Dashboards devem viver no repositório, versionados e deployados via pipeline.

### Provisionamento com Terraform

```hcl
# main.tf

resource "azurerm_monitor_workspace" "prometheus" {
  name                = "amw-prometheus-prod"
  resource_group_name = azurerm_resource_group.observability.name
  location            = azurerm_resource_group.observability.location
}

resource "azurerm_dashboard_grafana" "grafana" {
  name                = "grafana-prod"
  resource_group_name = azurerm_resource_group.observability.name
  location            = azurerm_resource_group.observability.location
  sku                 = "Standard"
  zone_redundancy_enabled = true

  azure_monitor_workspace_integrations {
    resource_id = azurerm_monitor_workspace.prometheus.id
  }

  identity {
    type = "SystemAssigned"
  }
}

# Role assignment para o Grafana ler métricas do workspace
resource "azurerm_role_assignment" "grafana_monitoring_reader" {
  scope                = azurerm_monitor_workspace.prometheus.id
  role_definition_name = "Monitoring Reader"
  principal_id         = azurerm_dashboard_grafana.grafana.identity[0].principal_id
}

# Role assignment para SREs acessarem o Grafana
resource "azurerm_role_assignment" "sre_grafana_editor" {
  scope                = azurerm_dashboard_grafana.grafana.id
  role_definition_name = "Grafana Editor"
  principal_id         = data.azuread_group.sre_team.object_id
}

# Habilitar Prometheus metrics no AKS
resource "azurerm_monitor_data_collection_rule" "prometheus" {
  name                = "dcr-prometheus-aks"
  resource_group_name = azurerm_resource_group.observability.name
  location            = azurerm_resource_group.observability.location

  destinations {
    monitor_account {
      monitor_account_id = azurerm_monitor_workspace.prometheus.id
      name               = "MonitoringAccount"
    }
  }

  data_flow {
    streams      = ["Microsoft-PrometheusMetrics"]
    destinations = ["MonitoringAccount"]
  }

  data_sources {
    prometheus_forwarder {
      name    = "PrometheusDataSource"
      streams = ["Microsoft-PrometheusMetrics"]
    }
  }
}

resource "azurerm_monitor_data_collection_rule_association" "aks_prometheus" {
  name                    = "dcra-prometheus-aks"
  target_resource_id      = azurerm_kubernetes_cluster.aks.id
  data_collection_rule_id = azurerm_monitor_data_collection_rule.prometheus.id
}

```

### Exportando e versionando dashboards

```bash
# Exportar dashboard existente do Grafana
az grafana dashboard show \
  --name $GRAFANA_NAME \
  --resource-group $RESOURCE_GROUP \
  --dashboard "AKS Cluster Overview" \
  -o json > dashboards/aks-cluster-overview.json

# Importar dashboard a partir de arquivo versionado
az grafana dashboard create \
  --name $GRAFANA_NAME \
  --resource-group $RESOURCE_GROUP \
  --definition @dashboards/aks-cluster-overview.json \
  --overwrite

```

## Instrumentando sua aplicação

Para que métricas de negócio apareçam no Grafana, suas aplicações precisam expor um endpoint `/metrics` no formato Prometheus. Aqui estão exemplos para as linguagens mais comuns no ecossistema Azure.

### Python (FastAPI + prometheus-client)

```python
# metrics.py
from prometheus_client import Counter, Histogram, Gauge, generate_latest
from fastapi import FastAPI, Request, Response
import time

app = FastAPI()

# Métricas de negócio
REQUEST_COUNT = Counter(
    'http_requests_total',
    'Total de requisições HTTP',
    ['method', 'endpoint', 'status']
)

REQUEST_LATENCY = Histogram(
    'http_request_duration_seconds',
    'Latência de requisições HTTP em segundos',
    ['method', 'endpoint'],
    buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
)

ACTIVE_CONNECTIONS = Gauge(
    'http_active_connections',
    'Conexões HTTP ativas'
)

ORDERS_PROCESSED = Counter(
    'orders_processed_total',
    'Total de pedidos processados',
    ['status']  # success, failed, cancelled
)

@app.middleware("http")
async def metrics_middleware(request: Request, call_next):
    ACTIVE_CONNECTIONS.inc()
    start_time = time.time()

    response = await call_next(request)

    duration = time.time() - start_time
    REQUEST_COUNT.labels(
        method=request.method,
        endpoint=request.url.path,
        status=response.status_code
    ).inc()
    REQUEST_LATENCY.labels(
        method=request.method,
        endpoint=request.url.path
    ).observe(duration)
    ACTIVE_CONNECTIONS.dec()

    return response

@app.get("/metrics")
async def metrics():
    return Response(
        content=generate_latest(),
        media_type="text/plain"
    )

@app.post("/orders")
async def create_order(order: dict):
    try:
        # lógica de negócio
        result = process_order(order)
        ORDERS_PROCESSED.labels(status="success").inc()
        return {"status": "created", "id": result.id}
    except Exception as e:
        ORDERS_PROCESSED.labels(status="failed").inc()
        raise

```

### .NET (ASP.NET Core + prometheus-net)

```csharp
// Program.cs
using Prometheus;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

// Middleware para métricas HTTP automáticas
app.UseHttpMetrics(options =>
{
    options.AddCustomLabel("host", context => context.Request.Host.Host);
});

app.MapControllers();

// Endpoint /metrics
app.MapMetrics();

// Métricas customizadas de negócio
var ordersProcessed = Metrics.CreateCounter(
    "orders_processed_total",
    "Total de pedidos processados",
    new CounterConfiguration
    {
        LabelNames = new[] { "status" }
    });

var orderProcessingDuration = Metrics.CreateHistogram(
    "order_processing_duration_seconds",
    "Tempo de processamento de pedidos",
    new HistogramConfiguration
    {
        Buckets = Histogram.ExponentialBuckets(0.01, 2, 10)
    });

app.Run();

```

## Troubleshooting: os problemas mais comuns

Depois de ajudar dezenas de times a implementar essa stack, estes são os problemas que mais consomem tempo e como resolvê-los.

### Problema 1: Métricas não aparecem no Grafana

**Checklist de diagnóstico:**

```bash
# 1. Verificar se o agente ama-metrics está rodando
kubectl get pods -n kube-system -l rsName=ama-metrics

# 2. Verificar logs do agente
kubectl logs -n kube-system -l rsName=ama-metrics -c prometheus-collector --tail=50

# 3. Verificar se o agente está conseguindo fazer scrape
kubectl logs -n kube-system -l rsName=ama-metrics -c prometheus-collector | grep "scrape"

# 4. Verificar ConfigMap de configuração
kubectl get configmap ama-metrics-prometheus-config -n kube-system -o yaml

# 5. Verificar se o endpoint /metrics da aplicação está acessível
kubectl port-forward svc/api-pedidos 8080:8080 -n production
curl http://localhost:8080/metrics

```

**Causa mais comum**: O namespace da aplicação não está incluído no ConfigMap de scrape. Por padrão, o agente só coleta métricas de `kube-system` e targets pré-configurados.

### Problema 2: High cardinality - custos explodindo

Métricas com muitos labels únicos (alta cardinalidade) inflam o volume de ingestão e os custos. Exemplos perigosos:

```promql
# RUIM: user_id como label (milhares de valores)
http_requests_total{user_id="abc123", endpoint="/api/orders"}

# BOM: agregar por endpoint, sem user_id
http_requests_total{endpoint="/api/orders"}

```

**Como identificar métricas de alta cardinalidade:**

```promql
# Top 10 métricas por número de séries temporais
topk(10, count by (__name__) ({__name__!=""}))

```

**Como limitar no agente:**

```yaml
# ama-metrics-settings-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ama-metrics-settings-configmap
  namespace: kube-system
data:
  default-scrape-settings: |
    [default-scrape-settings]
        # Limitar o número de séries temporais por scrape target
        sample_limit = 5000
        # Limitar o tamanho do label
        label_limit = 20
        label_name_length_limit = 128
        label_value_length_limit = 512

```

### Problema 3: Grafana data source "Prometheus" não mostra dados

Isso acontece quando o data source foi configurado manualmente (em vez de automaticamente pelo `--grafana-resource-id`). Para verificar e corrigir:

```bash
# Listar data sources configurados
az grafana data-source list \
  --name $GRAFANA_NAME \
  --resource-group $RESOURCE_GROUP

# Se o data source Prometheus não existir, criar manualmente
az grafana data-source create \
  --name $GRAFANA_NAME \
  --resource-group $RESOURCE_GROUP \
  --definition '{
    "name": "Azure Managed Prometheus",
    "type": "prometheus",
    "access": "proxy",
    "url": "https://amw-prometheus-prod-xxxxx.eastus2.prometheus.monitor.azure.com",
    "jsonData": {
      "httpMethod": "POST",
      "azureCredentials": {
        "authType": "msi"
      }
    }
  }'

```

### Problema 4: Prometheus rules não disparam alertas

**Causas comuns:**

1. **Rule group não associado ao cluster**: O `--cluster-name` precisa corresponder exatamente ao nome do cluster AKS.
2. **Métrica referenciada não existe**: A regra usa uma métrica que não está sendo coletada. Verifique no Grafana Explore:

```promql
# Verificar se a métrica existe
up{job="api-pedidos"}

# Listar todas as métricas disponíveis de um job
{job="api-pedidos"}

```

1. **Período de avaliação longo demais**: Se o `for` é `PT30M` mas a métrica só fica anormal por 10 minutos, o alerta nunca vai disparar.

### Problema 5: Latência alta nas queries do Grafana

Queries lentas geralmente indicam que você está consultando muitas séries temporais ou usando ranges muito longos.

**Otimizações:**

| Problema                               | Solução                                        |
| -------------------------------------- | ---------------------------------------------- |
| Query lenta com rate() em range grande | Usar recording rules para pré-computar         |
| Dashboard carrega devagar              | Reduzir o time range padrão (1h em vez de 24h) |
| Muitas séries no mesmo painel          | Adicionar filtros por namespace ou label       |
| topk() em milhões de séries            | Filtrar antes do topk() com label matchers     |

## Custos e otimização

Entender o modelo de custo é essencial para evitar surpresas na fatura.

### Modelo de precificação

| Componente                               | Modelo de cobrança               | Faixa de preço (referência)                    |
| ---------------------------------------- | -------------------------------- | ---------------------------------------------- |
| **Azure Monitor workspace (Prometheus)** | Por milhão de amostras ingeridas | \~$0.30 por milhão de amostras (primeiros 50B) |
| **Managed Grafana Standard**             | Instância fixa mensal            | \~$150/mês por instância                       |
| **Retenção**                             | 18 meses incluídos               | Sem custo adicional para retenção padrão       |
| **Queries**                              | Incluídas                        | Sem custo por query PromQL                     |

### Dicas para controlar custos

1. **Reduza o scrape interval**: Mudar de 15s para 30s corta a ingestão pela metade
2. **Filtre métricas desnecessárias**: Nem toda métrica do node-exporter é útil
3. **Use keep/drop no relabel\_configs**: Descarte séries que você nunca vai consultar
4. **Monitore a ingestão**: Use as métricas internas do agente para acompanhar volume

```yaml
# Exemplo: descartar métricas de filesystem de tmpfs e shm
relabel_configs:
- source_labels: [__name__]
  regex: 'node_filesystem_(size_bytes|avail_bytes|free_bytes)'
  action: keep
metric_relabel_configs:
- source_labels: [fstype]
  regex: 'tmpfs|shm'
  action: drop

```

## Comparativo: Managed Prometheus vs Azure Monitor Metrics

Para fechar, uma comparação direta entre usar Prometheus gerenciado e Azure Monitor Metrics nativo. Muitos times se perguntam se precisam escolher um ou outro — a resposta é que podem coexistir.

| Critério                 | Azure Managed Prometheus                     | Azure Monitor Metrics (nativo)         |
| ------------------------ | -------------------------------------------- | -------------------------------------- |
| **Linguagem de query**   | PromQL                                       | KQL (Kusto)                            |
| **Formato de métricas**  | Prometheus / OpenMetrics                     | Azure Monitor metrics format           |
| **Visualização**         | Grafana (managed)                            | Azure Workbooks, Portal, Power BI      |
| **Alertas**              | Prometheus alert rules (PromQL)              | Azure Monitor Alert Rules (KQL)        |
| **Ecossistema**          | Prometheus exporters, dashboards Grafana.com | Azure integrations nativas             |
| **Retenção padrão**      | 18 meses                                     | 93 dias (métricas de plataforma)       |
| **Multi-cluster**        | Nativo (mesmo workspace)                     | Nativo (mesmo Log Analytics)           |
| **Curva de aprendizado** | Familiar para quem já usa Prometheus/Grafana | Familiar para quem já usa Azure        |
| **Custo**                | Baseado em ingestão de amostras              | Baseado em ingestão de dados + queries |

**Recomendação**: Use **Prometheus + Grafana** para métricas de infraestrutura Kubernetes e aplicações cloud-native. Use **Azure Monitor** para métricas de serviços PaaS do Azure (App Service, SQL Database, Storage, etc.) e correlação com logs via KQL. Os dois coexistem naturalmente.

## Conclusão

A combinação de Azure Managed Grafana com Azure Monitor managed service for Prometheus representa o melhor dos dois mundos: a familiaridade e o ecossistema rico do stack open-source Prometheus/Grafana com a confiabilidade operacional e a integração nativa do Azure.

Neste artigo, implementamos uma stack completa de observabilidade moderna que vai desde o provisionamento via CLI e Terraform até dashboards avançados com PromQL, alerting rules com integração a Action Groups, monitoramento multi-cluster e instrumentação de aplicações em Python e .NET. Também cobrimos os cinco problemas mais comuns que travam times em produção e como resolvê-los de forma definitiva.

Os próximos passos naturais a partir daqui são:

1. **Integrar com SLOs**: Usar as métricas Prometheus como base para [SLIs e SLOs](https://www.azurebrasil.cloud/blog/sre-no-azure-implementando-slis-slos-e-error-budgets-com-azure-monitor/) usando recording rules para calcular error budgets
2. **Adicionar traces**: Complementar métricas com distributed tracing via OpenTelemetry + Azure Monitor Application Insights
3. **Automatizar resposta a incidentes**: Conectar alertas Prometheus com [runbooks automatizados](https://www.azurebrasil.cloud/blog/resposta-a-incidentes-no-azure-automacao-de-alertas-runbooks-e-integracao-com-ferramentas-de-on-call/)
4. **Dashboards como código no pipeline**: Versionar todos os dashboards em Git e deployar via CI/CD

Se você já tem Prometheus e Grafana self-hosted, a migração para o managed é incremental: comece com um cluster de staging, valide que suas queries PromQL funcionam identicamente e expanda para produção. A compatibilidade é excelente — na maioria dos casos, é literalmente plug and play.

## Referências

- [Azure Managed Grafana — Documentação oficial](https://learn.microsoft.com/azure/managed-grafana/overview?ref=azurebrasil.cloud)
- [Azure Monitor managed service for Prometheus — Overview](https://learn.microsoft.com/azure/azure-monitor/essentials/prometheus-metrics-overview?ref=azurebrasil.cloud)
- [Configurar coleta de métricas Prometheus no AKS](https://learn.microsoft.com/azure/azure-monitor/containers/prometheus-metrics-enable?ref=azurebrasil.cloud)
- [Prometheus Rule Groups no Azure Monitor](https://learn.microsoft.com/azure/azure-monitor/essentials/prometheus-rule-groups?ref=azurebrasil.cloud)
- [Custom scrape configuration para Prometheus no AKS](https://learn.microsoft.com/azure/azure-monitor/containers/prometheus-metrics-scrape-configuration?ref=azurebrasil.cloud)
- [Grafana dashboards — Comunidade](https://grafana.com/grafana/dashboards/?ref=azurebrasil.cloud)
- [PromQL — Documentação oficial](https://prometheus.io/docs/prometheus/latest/querying/basics/?ref=azurebrasil.cloud)
- [Terraform provider azurerm — azurerm\_dashboard\_grafana](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dashboard%5Fgrafana?ref=azurebrasil.cloud)