Guia Completo de Grafana em Kubernetes: Dashboards, Alertas e Loki para Logs Já leu

Introdução ao Grafana em Kubernetes Grafana é uma plataforma de visualização e análise de dados amplamente utilizada em ambientes de produção. Quando integrada a um cluster Kubernetes, ela se torna uma ferramenta poderosa para monitorar a saúde e o desempenho de suas aplicações. O diferencial do Grafana em Kubernetes é sua capacidade de coletar dados de múltiplas fontes (Prometheus, Loki, InfluxDB, entre outras) e transformá-los em dashboards intuitivos e em tempo real. A abordagem que veremos aqui é prática e focada no que realmente funciona em produção. Vamos começar com a implantação do Grafana em um cluster Kubernetes usando Helm, depois construir dashboards efetivos, configurar alertas que realmente disparam quando necessário, e integrar o Loki para centralizar logs. Este é o trio essencial para observabilidade em Kubernetes. Deployment do Grafana em Kubernetes com Helm Instalação e Configuração Básica A forma mais robusta de implantar Grafana em Kubernetes é usar Helm, o gerenciador de pacotes da plataforma. Helm abstrai a complexidade

Introdução ao Grafana em Kubernetes

Grafana é uma plataforma de visualização e análise de dados amplamente utilizada em ambientes de produção. Quando integrada a um cluster Kubernetes, ela se torna uma ferramenta poderosa para monitorar a saúde e o desempenho de suas aplicações. O diferencial do Grafana em Kubernetes é sua capacidade de coletar dados de múltiplas fontes (Prometheus, Loki, InfluxDB, entre outras) e transformá-los em dashboards intuitivos e em tempo real.

A abordagem que veremos aqui é prática e focada no que realmente funciona em produção. Vamos começar com a implantação do Grafana em um cluster Kubernetes usando Helm, depois construir dashboards efetivos, configurar alertas que realmente disparam quando necessário, e integrar o Loki para centralizar logs. Este é o trio essencial para observabilidade em Kubernetes.

Deployment do Grafana em Kubernetes com Helm

Instalação e Configuração Básica

A forma mais robusta de implantar Grafana em Kubernetes é usar Helm, o gerenciador de pacotes da plataforma. Helm abstrai a complexidade dos manifestos YAML e fornece valores pré-configurados que facilitam a instalação.

Primeiro, adicione o repositório Helm oficial do Grafana e instale-o no seu cluster:

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

# Criar namespace para isolamento
kubectl create namespace monitoring

# Instalar Grafana com valores customizados
helm install grafana grafana/grafana \
  --namespace monitoring \
  --set adminPassword=seu_senha_aqui \
  --set persistence.enabled=true \
  --set persistence.size=10Gi \
  --set service.type=LoadBalancer

Este comando cria um deployment do Grafana com persistência de dados (importante em produção), define uma senha de admin segura e expõe o serviço via LoadBalancer. Se estiver em um ambiente local (minikube, kind), use service.type=NodePort em vez de LoadBalancer.

Acessando Grafana e Primeiros Passos

Após a instalação, obtenha o acesso ao Grafana:

# Para NodePort (desenvolvimento local)
kubectl port-forward -n monitoring svc/grafana 3000:80

# Para LoadBalancer (produção)
kubectl get svc -n monitoring grafana

Abra seu navegador em http://localhost:3000 ou no IP externo fornecido. Faça login com usuário admin e a senha que você definiu. O primeiro passo após autenticar é adicionar uma data source.

Data Sources e Conexão com Prometheus e Loki

Configurando Prometheus como Data Source

Antes de criar dashboards, você precisa de dados. Prometheus é o sistema padrão para coleta de métricas em Kubernetes. Vamos configurar Grafana para se conectar ao Prometheus.

Na interface do Grafana, vá em Configuration > Data Sources > Add data source e escolha Prometheus. A URL do Prometheus geralmente é http://prometheus:9090 (se estiver no mesmo cluster). Aqui está um exemplo de manifest Kubernetes para Prometheus, caso não tenha instalado:

apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitoring
spec:
  ports:
  - port: 9090
    targetPort: 9090
  selector:
    app: prometheus
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
    scrape_configs:
    - job_name: 'kubernetes-pods'
      kubernetes_sd_configs:
      - role: pod
      relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: 'true'
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - name: prometheus
        image: prom/prometheus:latest
        ports:
        - containerPort: 9090
        volumeMounts:
        - name: config
          mountPath: /etc/prometheus
        args:
          - '--config.file=/etc/prometheus/prometheus.yml'
      volumes:
      - name: config
        configMap:
          name: prometheus-config

Configurando Loki para Centralização de Logs

Loki é um sistema de agregação de logs otimizado para Kubernetes. Diferente de Elasticsearch, Loki é mais leve e indexa apenas metadados, mantendo os logs compactados. Para adicionar Loki como data source, instale-o primeiro:

helm install loki grafana/loki-stack \
  --namespace monitoring \
  --set loki.enabled=true \
  --set promtail.enabled=true \
  --set grafana.enabled=false

Depois, no Grafana, adicione Loki como data source apontando para http://loki:3100. A partir daí, você consegue fazer queries em seus logs usando LogQL. Aqui está um exemplo de query prática:

{namespace="production"} | json | level="ERROR"

Esta query retorna todos os logs do namespace production, converte-os de JSON e filtra apenas mensagens de erro.

Criando Dashboards Efetivos em Grafana

Estrutura de um Dashboard Bem Projetado

Um dashboard Grafana que realmente agrega valor segue uma estrutura clara: status geral no topo, métricas críticas em destaque, e detalhes exploráveis abaixo. Evite dashboards poluídos com 50 panels — uma pessoa deve entender a saúde do sistema em 10 segundos olhando para ele.

Vamos criar um dashboard para monitorar aplicações em Kubernetes. No Grafana, clique em Create > Dashboard e adicione um novo panel. Escolha Prometheus como data source e insira a query abaixo:

sum(rate(container_cpu_usage_seconds_total[5m])) by (pod_name)

Esta query retorna o uso de CPU agregado por pod nos últimos 5 minutos. Configure o painel como gráfico para visualizar tendências. Repita o processo para memória:

sum(container_memory_usage_bytes) by (pod_name) / 1024 / 1024

Integrando Logs no Dashboard com Loki

Uma funcionalidade poderosa do Grafana é correlacionar métricas com logs. Quando um pod tem consumo anômalo de CPU, você quer ver os logs daquele pod no mesmo dashboard. Adicione um panel de logs com:

{pod_name=~"$pod"} | json

Use a variável $pod para permitir seleção dinâmica. Para configurar variáveis, vá em Dashboard Settings > Variables e crie uma nova variável com query Prometheus:

label_values(container_cpu_usage_seconds_total, pod_name)

Agora, ao selecionar um pod no dropdown, tanto as métricas quanto os logs se atualizam automaticamente. Aqui está um exemplo de manifest que exporta um dashboard como JSON (útil para versionamento em Git):

# Exportar dashboard existente
curl -s http://admin:senha@localhost:3000/api/dashboards/uid/seu_uid | jq '.dashboard' > dashboard.json

# Importar dashboard em outro cluster
curl -X POST http://admin:senha@localhost:3000/api/dashboards/db \
  -H "Content-Type: application/json" \
  -d @dashboard.json

Alertas em Grafana: Detecção e Notificação

Estruturando Regras de Alerta Práticas

Alertas são inúteis se forem genéricos demais ou muito ruidosos. A chave está em criar alertas baseados em SLOs (Service Level Objectives) reais do seu negócio. Um alerta só deve disparar quando uma ação humana é necessária.

Para criar um alerta efetivo, comece definindo a condição. No Grafana, abra um panel e clique em Alert. Configure uma query de avaliação — por exemplo, um alerta quando CPU ultrapassa 80%:

avg(rate(container_cpu_usage_seconds_total[5m])) by (namespace, pod) > 0.8

Configure o intervalo de avaliação em 1 minuto e o tempo de espera (for) em 5 minutos. O "for" evita que picos momentâneos disparem alertas falsos. Defina as labels e anotações que ajudem na investigação:

# Anotação dentro da regra
description: "Pod {{ $labels.pod }} no namespace {{ $labels.namespace }} com CPU acima de 80%"
runbook_url: "https://seu-wiki.com/cpu-high"

Configurando Notificações via Webhook

Grafana suporta múltiplos canais de notificação: email, Slack, PagerDuty, webhooks customizados, entre outros. Para configurar um webhook (útil para integrar com sistemas legados), vá em Configuration > Notification channels e crie um novo canal:

{
  "type": "webhook",
  "settings": {
    "url": "https://seu-sistema.com/api/alerts",
    "httpMethod": "POST"
  }
}

Aqui está um exemplo de payload recebido pelo seu webhook:

{
  "status": "firing",
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "HighCPU",
        "namespace": "production",
        "pod": "api-server-abc123"
      },
      "annotations": {
        "description": "Pod api-server-abc123 no namespace production com CPU acima de 80%",
        "runbook_url": "https://seu-wiki.com/cpu-high"
      },
      "startsAt": "2024-01-15T10:30:00.000Z",
      "endsAt": "0001-01-01T00:00:00Z"
    }
  ]
}

Agrupamento e Silenciamento de Alertas

Em ambientes grandes, você pode receber centenas de alertas relacionados ao mesmo problema (um node down gera alertas de todos os pods daquele node). Configure agrupamento no arquivo alertmanager.yml para reduzir ruído:

route:
  group_by: ['alertname', 'cluster', 'namespace']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default'
  routes:
  - match:
      severity: critical
    receiver: 'pagerduty'
    continue: true
  - match:
      severity: warning
    receiver: 'slack'

O Grafana permite silenciar alertas manualmente através da UI. Isso é essencial durante manutenções planejadas:

# Exemplo de curl para silenciar alertas (via AlertManager)
curl -X POST http://alertmanager:9093/api/v1/silences \
  -H "Content-Type: application/json" \
  -d '{
    "matchers": [
      {"name": "namespace", "value": "staging", "isRegex": false}
    ],
    "startsAt": "2024-01-15T10:00:00Z",
    "endsAt": "2024-01-15T12:00:00Z",
    "createdBy": "usuario@empresa.com",
    "comment": "Manutenção planejada"
  }'

Loki: Centralizando e Consultando Logs

Arquitetura e Fluxo de Logs no Loki

Loki funciona de forma diferente de stacks ELK. Enquanto Elasticsearch indexa todo o conteúdo dos logs (custoso), Loki indexa apenas labels (metadados) e compacta o conteúdo. Isso torna Loki muito mais eficiente em termos de armazenamento e custos, especialmente em Kubernetes.

O fluxo é simples: aplicações geram logs no stdout, Promtail (agente de coleta) os lê, adiciona labels dinâmicos baseado em metadados do Kubernetes, e envia para Loki. Loki os armazena em chunks compactados. Quando você consulta, Loki faz matching de labels primeiro (rápido) e depois busca no conteúdo (menos custoso).

Configuração de Promtail para Capturar Logs de Kubernetes

O Promtail é um agente leve que roda em cada node do cluster. Ele tira proveito da auto-descoberta do Kubernetes para identificar todos os pods e seus logs. Aqui está uma configuração real de Promtail:

apiVersion: v1
kind: ConfigMap
metadata:
  name: promtail-config
  namespace: monitoring
data:
  promtail-config.yaml: |
    clients:
    - url: http://loki:3100/loki/api/v1/push
    scrape_configs:
    - job_name: kubernetes-pods
      kubernetes_sd_configs:
      - role: pod
      relabel_configs:
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: pod_name
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: namespace
      - source_labels: [__meta_kubernetes_pod_label_app]
        action: replace
        target_label: app
      - source_labels: [__meta_kubernetes_pod_container_name]
        action: replace
        target_label: container
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: promtail
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: promtail
  template:
    metadata:
      labels:
        app: promtail
    spec:
      serviceAccountName: promtail
      containers:
      - name: promtail
        image: grafana/promtail:latest
        args:
          - -config.file=/etc/promtail/promtail-config.yaml
        volumeMounts:
        - name: config
          mountPath: /etc/promtail
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: promtail-config
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: promtail
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: promtail
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: promtail
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: promtail
subjects:
- kind: ServiceAccount
  name: promtail
  namespace: monitoring

Queries Práticas em LogQL

LogQL é a linguagem de consulta do Loki, similar a PromQL mas otimizada para logs. Diferente de Elasticsearch, você não consulta campos individuais sem ter um label correspondente. Aqui estão queries reais que você usará:

# Todos os logs de um namespace específico
{namespace="production"}

# Logs ERROR de uma aplicação específica
{app="api-gateway"} | json | level="ERROR"

# Logs contendo "timeout" com duração acima de 5s
{namespace="production"} | json | duration > 5 and message=~"timeout"

# Taxa de erros por minuto
sum(rate({namespace="production"} | json | level="ERROR" [1m])) by (pod_name)

# Logs ordenados por timestamp e limitados aos últimos 100
{app="web-server"} | json | line_format "{{.timestamp}} {{.level}} {{.message}}" | limit 100

A query abaixo é particularmente útil para investigar comportamentos anormais — mostra a evolução de um erro ao longo do tempo:

avg_over_time({namespace="staging", app="backend"} | json | duration | unwrap duration(s) [1m]) by (endpoint)

Conclusão

Você aprendeu nesta aula que Grafana, Prometheus e Loki formam um trio poderoso para observabilidade em Kubernetes. O conhecimento prático que você ganhou vai além de "clicar em botões": você entendeu que alertas efetivos exigem foco em SLOs reais, que dashboards devem contar uma história clara em 10 segundos, e que logs indexados por labels (Loki) são fundamentalmente mais eficientes que indexação full-text em clusters Kubernetes. A chave para sucesso em produção é começar simples (monitorar CPU e memória), testar seus alertas antes de conectar notificações, e evoluir baseado em alertas que realmente são acionáveis.

Referências


Artigos relacionados