Monitoramento com Prometheus e Grafana

1. Introdução ao Monitoramento em Ambientes Kubernetes

Em ambientes Kubernetes, a natureza efêmera dos pods e a dinamicidade dos serviços tornam o monitoramento tradicional insuficiente. Prometheus e Grafana emergiram como a stack padrão para observabilidade em clusters Kubernetes, oferecendo coleta de métricas baseada em pull, armazenamento time-series e visualização flexível.

A arquitetura básica funciona em três camadas:
- Coleta: Prometheus "puxa" métricas de exporters e aplicações via HTTP endpoints
- Armazenamento: Dados são persistidos em banco time-series com labels para identificação
- Visualização: Grafana consulta o Prometheus e exibe dashboards interativos

Comparado a soluções comerciais como Datadog ou New Relic, Prometheus é open-source, tem custo zero de licenciamento e oferece total controle sobre os dados. Já comparado ao Zabbix, Prometheus é mais moderno, nativamente cloud-native e melhor integrado com Kubernetes.

2. Instalação e Configuração do Prometheus no Kubernetes

O método mais eficiente é utilizar o Prometheus Operator via Helm chart. O Operator automatiza a gestão de instâncias Prometheus, regras de alerta e targets de monitoramento.

# Adicionar repositório Helm
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Instalar kube-prometheus-stack (inclui Prometheus, Grafana e Alertmanager)
helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set prometheus.prometheusSpec.retention=15d \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=standard \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi

Após a instalação, o Prometheus descobre automaticamente métricas de serviços via ServiceMonitor e PodMonitor. Exemplo de ServiceMonitor para uma aplicação customizada:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: minha-app-monitor
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: minha-app
  namespaceSelector:
    matchNames:
      - production
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

Para persistência, configuramos volumes com retenção de 15 dias e 50GB de armazenamento, conforme mostrado no comando Helm.

3. Coleta de Métricas com Exporters e ServiceMonitor

Três exporters essenciais vêm pré-configurados no kube-prometheus-stack:

kube-state-metrics: Fornece métricas sobre o estado dos objetos Kubernetes (pods, deployments, nodes). Exemplo de métrica:

kube_pod_status_phase{namespace="default", pod="nginx-7c9d5b6b8f-xk4j2", phase="Running"} 1

node-exporter: Coleta métricas de hardware e SO dos nós (CPU, memória, disco, rede). Métrica típica:

node_cpu_seconds_total{mode="system", instance="10.0.0.1:9100"}

cAdvisor: Integrado ao kubelet, fornece métricas de performance de containers:

container_cpu_usage_seconds_total{container="nginx", pod="nginx-7c9d5b6b8f-xk4j2", namespace="default"}

Para validar a coleta, acesse o target list no Prometheus UI via port-forward:

kubectl port-forward -n monitoring svc/prometheus-operated 9090:9090
# Acesse http://localhost:9090/targets

4. Configuração e Customização de Regras de Alerta

Regras de alerta são definidas em PromQL (Prometheus Query Language) e agrupadas em grupos. Exemplo de regra para detectar pod em crash loop:

groups:
- name: kubernetes-alerts
  rules:
  - alert: PodCrashLooping
    expr: rate(kube_pod_status_phase{phase="Pending"}[5m]) > 0
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "Pod {{ $labels.pod }} em crash loop no namespace {{ $labels.namespace }}"

  - alert: HighCPUUsage
    expr: sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace) > 0.8
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Pod {{ $labels.pod }} usando mais de 80% CPU"

Para aplicar as regras, crie um ConfigMap e referencie no Prometheus CR:

kubectl create configmap -n monitoring prometheus-rules --from-file=rules.yaml
kubectl patch prometheus -n monitoring k8s --patch '{"spec":{"ruleSelector":{"matchLabels":{"role":"alert-rules"}}}}'

O Alertmanager gerencia o roteamento das notificações (Slack, email, PagerDuty). Configure no values.yaml do Helm:

alertmanager:
  config:
    route:
      receiver: 'slack-notifications'
    receivers:
    - name: 'slack-notifications'
      slack_configs:
      - api_url: 'https://hooks.slack.com/services/TOKEN'
        channel: '#alerts'
        send_resolved: true

5. Instalação e Configuração do Grafana

O Grafana já é instalado junto com o kube-prometheus-stack. Para instalar separadamente:

helm install grafana grafana/grafana \
  --namespace monitoring \
  --set persistence.enabled=true \
  --set persistence.size=10Gi \
  --set adminPassword=admin123

Acesse o Grafana via port-forward:

kubectl port-forward -n monitoring svc/grafana 3000:80

Configure o datasource Prometheus automaticamente (já configurado pelo stack) ou manualmente:
1. Acesse Configuration > Data Sources
2. Adicione Prometheus com URL: http://prometheus-operated:9090
3. Teste a conexão

Importe dashboards prontos: no Grafana, vá em Dashboards > Import e use o ID 315 (Kubernetes Cluster Monitoring) ou 6417 (Kubernetes Pod Metrics).

6. Criação de Dashboards Personalizados

Vamos construir um dashboard simples para monitorar uma aplicação customizada. Primeiro, crie variáveis para filtros dinâmicos:

# Variável: namespace
Type: Query
Query: label_values(kube_pod_info, namespace)

# Variável: pod
Type: Query
Query: label_values(kube_pod_info{namespace="$namespace"}, pod)

Painéis de exemplo:

CPU Usage por Pod:

Query: sum(rate(container_cpu_usage_seconds_total{namespace="$namespace", pod=~"$pod", container!=""}[5m])) by (pod)
Unit: percent (0-100)
Visualization: Bar gauge

Memory Usage:

Query: sum(container_memory_working_set_bytes{namespace="$namespace", pod=~"$pod", container!=""}) by (pod)
Unit: bytes
Visualization: Gauge

Network Traffic:

Query: sum(rate(container_network_receive_bytes_total{namespace="$namespace", pod=~"$pod"}[5m])) by (pod)
Unit: Bps
Visualization: Time series

Disk I/O:

Query: sum(rate(container_fs_writes_bytes_total{namespace="$namespace", pod=~"$pod"}[5m])) by (pod)
Unit: Bps
Visualization: Time series

7. Boas Práticas e Otimização

Escalonamento: Para clusters grandes (>100 nodes), utilize sharding:

prometheus:
  prometheusSpec:
    shards: 2
    replicas: 2

Segurança: Habilite RBAC e TLS:

prometheus:
  prometheusSpec:
    serviceMonitorSelectorNilUsesHelmValues: false
    podMonitorSelectorNilUsesHelmValues: false
    secrets:
    - prometheus-tls

Backup: Faça backup periódico dos dados do Prometheus e dashboards do Grafana:

# Backup Prometheus data
kubectl exec -n monitoring prometheus-k8s-0 -- tar czf /tmp/prometheus-backup.tar.gz /prometheus
kubectl cp monitoring/prometheus-k8s-0:/tmp/prometheus-backup.tar.gz ./backup.tar.gz

# Export Grafana dashboards via API
curl -u admin:admin http://localhost:3000/api/dashboards/db -X GET > dashboards.json

8. Integração com a Stack de Observabilidade

Para observabilidade completa, integre com Loki para logs e Jaeger/Tempo para tracing:

# Instalar Loki
helm install loki grafana/loki-stack \
  --namespace monitoring \
  --set grafana.enabled=false

# Instalar Tempo para tracing
helm install tempo grafana/tempo \
  --namespace monitoring

No Grafana, configure datasources adicionais:
- Loki: http://loki:3100
- Tempo: http://tempo:3200

Crie dashboards unificados que combinem métricas (Prometheus), logs (Loki) e traces (Tempo) em um único painel, usando links entre painéis e queries correlacionadas.

Referências