Hero case 2025-07 → 2026-03

Observabilidade consolidada: 620 painéis em 5 dashboards para 50 em 1

Cluster gov federal: -88% painéis por máquina, alertas Postgres com roteamento semântico, dois incidentes capturados antes do usuário nas primeiras 48h.

DevOps/Infra Engineer (Estagiário) · Consultoria AWS Select Partner

  • Grafana
  • Prometheus
  • Loki
  • Promtail
  • Alertmanager
  • PostgreSQL
  • Node Exporter
  • Blackbox Exporter

TL;DR

  • 5 dashboards e ~620 painéis consolidados em 1 dashboard / ~50 painéis (-88% por máquina, -92% no total).
  • 13/13 alertas Postgres entregues (10 infra + 3 app), com roteamento semântico via Alertmanager.
  • 8 rotas de API gov monitoradas (Blackbox OAuth2 + fallback Python), 4 abordagens avaliadas, 2 selecionadas por trade-off documentado.

Contexto

O ambiente era um cluster de produção de um cliente gov federal mantido por uma Consultoria AWS Select Partner. A operação herdou cinco dashboards Grafana criados ao longo do tempo por times diferentes, totalizando aproximadamente 620 painéis. Não havia SLA pactuado por escrito, e os alertas viviam em canal de chat sem severidade nem rota — qualquer ruído acabava silenciado por adaptação humana.

Quando algo quebrava em produção, o plantão precisava abrir as cinco visualizações em sequência para correlacionar disco, RAM, banco e rota de API. O custo cognitivo era alto e o tempo até decisão ficava no nível do “perceptível, mas sem baseline formal”.

Capacity rodava com risco silencioso: durante a auditoria inicial, encontramos uma máquina de aplicação com disco em 92,1% sem alarme configurado.

Ação

A entrega foi quebrada em um pipeline de oito estágios (S0–S8) com 12 ADRs e 24 decisões técnicas registradas. Três frentes principais:

Consolidação dos dashboards

Inventário completo, classificação dos painéis por intenção (capacity vs. saúde vs. performance) e padronização de thresholds:

  • Visual: 70 / 85 (warning / critical) para CPU, RAM e disco.
  • Alerta: 80 / 90, com banda de tolerância para evitar flapping em sazonalidades de ETL.

Resultado: de 124 painéis por máquina para 12 (-88%), e ~620 totais para ~50 (-92%). Cada painel sobrevivente respondia uma pergunta operacional explícita, escrita na descrição.

Alertas Postgres

Treze alertas modelados (10 infra + 3 app), agrupados por severidade e rota de notificação. Baseline foi descoberto empiricamente medindo o pico real de queries simultâneas durante janelas de ETL/GIS — cerca de 35 — para então fixar um threshold realista em > 45 queries ativas por mais de 5 minutos.

# recording_rules.yaml — trecho ilustrativo
groups:
  - name: postgres-saturation
    interval: 30s
    rules:
      - record: pg:active_queries:5m
        expr: avg_over_time(pg_stat_activity_count{state="active"}[5m])
      - alert: PgQueryPressureHigh
        expr: pg:active_queries:5m > 45
        for: 5m
        labels:
          severity: warning
          team: db
        annotations:
          summary: "Pressão sustentada de queries ativas (baseline ~35, threshold 45)"
recording_rules.yaml — bloco postgres-saturation trecho ilustrativo, anonimizado

Quatro bloqueios reais consumiram tempo aqui — VPN, cross-network, security group tcp/9100 e SMTP 535 — e estão documentados como aprendizado de infra real, não como vitrine.

Monitoramento de APIs

Quatro abordagens foram avaliadas para autenticar contra um broker OAuth2 gov: probe HTTP simples, exporter custom em Go, exporter Python com cache de token, e Blackbox com módulo OAuth2 nativo. Duas selecionadas:

  • Blackbox Exporter com módulo OAuth2 para 4 rotas internas com renovação automática.
  • Fallback Python exporter para as 4 rotas que retornavam payload condicional ao escopo do token (Blackbox cobria status, exporter mediu integridade da resposta).

Scrape configurado em janelas de 10 minutos para respeitar o rate limit do broker.

# blackbox.yml — módulo oauth2 (anonimizado)
modules:
  api_gov_oauth2:
    prober: http
    timeout: 8s
    http:
      method: GET
      headers:
        Authorization: "Bearer ${OAUTH_TOKEN}"
      valid_status_codes: [200, 204]
      fail_if_body_not_matches_regexp:
        - '"status"\s*:\s*"ok"'

Trade-offs e o que NÃO fiz

  • Dual Grafana vs. instância única (DT-10): considerei manter uma instância única consolidada para reduzir overhead operacional, mas escolhi dual Grafana (uma para infra, outra para aplicação) por isolamento de blast radius — uma falha de plugin ou upgrade quebrado em um lado não derrubava a observabilidade do outro. O custo é manter dois conjuntos de dashboards sincronizados; o ganho é poder fazer manutenção sem ficar sem visão.
  • Não migrei alertas para Grafana Alerting: Alertmanager ficou como roteador porque o time já tinha rotina operacional sobre ele; trocar agora seria churn sem ganho.
  • Não escrevi exporter custom em Go apesar da tentação técnica: Python entregou em 1/3 do tempo e a equipe consegue manter.
  • Não cobri tracing distribuído (OpenTelemetry): ficou no backlog explícito como próximo ciclo — ROI maior agora estava em alertas confiáveis, não em traces extra.

Resultado

-88%redução
Painéis por máquina
evidência
13/ 13 planejados
Alertas Postgres entregues
evidência
8rotas críticas
Rotas API monitoradas
evidência
2primeiras 48h
Incidentes detectados antes do usuário

Nas primeiras 48h após a entrada em produção dos 13 alertas Postgres, dois incidentes legítimos foram capturados antes de qualquer reclamação chegar ao suporte:

  1. Disco em 93,5% numa máquina de aplicação — o threshold 90 disparou, time agiu em janela planejada, sem indisponibilidade.
  2. Queries lentas sustentadas acima do threshold de 45 ativas durante uma janela ETL não anunciada — investigação reduziu o pico futuro com índice ajustado.

MTTR formal não tinha baseline antes da consolidação, então o ganho está descrito qualitativamente (“plantão deixou de abrir cinco dashboards para abrir um”); SLA segue como meta pactuada com o PO do cliente, sem número público.

A entrega final somou 22 tasks em 4 fases, 9 tópicos de research documentados e 5h efetivas em 4 sessões focadas para a fase de alertas Postgres — o que importou aqui não foi a velocidade, e sim que a configuração sobreviveu ao primeiro fim de semana sem precisar de mim.

Resultados mensuráveis

-88%redução
Painéis por máquina
evidência
13/ 13 planejados
Alertas Postgres entregues
evidência
8rotas críticas
Rotas API monitoradas
evidência
2primeiras 48h
Incidentes detectados antes do usuário
evidência