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.