<h2>Introdução ao Grafana em Kubernetes</h2>
<p>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.</p>
<p>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.</p>
<h2>Deployment do Grafana em Kubernetes com Helm</h2>
<h3>Instalação e Configuração Básica</h3>
<p>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.</p>
<p>Primeiro, adicione o repositório Helm oficial do Grafana e instale-o no seu cluster:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>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 <code>service.type=NodePort</code> em vez de LoadBalancer.</p>
<h3>Acessando Grafana e Primeiros Passos</h3>
<p>Após a instalação, obtenha o acesso ao Grafana:</p>
<pre><code class="language-bash"># Para NodePort (desenvolvimento local)
kubectl port-forward -n monitoring svc/grafana 3000:80
Para LoadBalancer (produção)
kubectl get svc -n monitoring grafana</code></pre>
<p>Abra seu navegador em <code>http://localhost:3000</code> ou no IP externo fornecido. Faça login com usuário <code>admin</code> e a senha que você definiu. O primeiro passo após autenticar é adicionar uma data source.</p>
<h2>Data Sources e Conexão com Prometheus e Loki</h2>
<h3>Configurando Prometheus como Data Source</h3>
<p>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.</p>
<p>Na interface do Grafana, vá em <strong>Configuration</strong> > <strong>Data Sources</strong> > <strong>Add data source</strong> e escolha Prometheus. A URL do Prometheus geralmente é <code>http://prometheus:9090</code> (se estiver no mesmo cluster). Aqui está um exemplo de manifest Kubernetes para Prometheus, caso não tenha instalado:</p>
<pre><code class="language-yaml">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</code></pre>
<h3>Configurando Loki para Centralização de Logs</h3>
<p>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:</p>
<pre><code class="language-bash">helm install loki grafana/loki-stack \
--namespace monitoring \
--set loki.enabled=true \
--set promtail.enabled=true \
--set grafana.enabled=false</code></pre>
<p>Depois, no Grafana, adicione Loki como data source apontando para <code>http://loki:3100</code>. A partir daí, você consegue fazer queries em seus logs usando LogQL. Aqui está um exemplo de query prática:</p>
<pre><code class="language-logql">{namespace="production"} | json | level="ERROR"</code></pre>
<p>Esta query retorna todos os logs do namespace production, converte-os de JSON e filtra apenas mensagens de erro.</p>
<h2>Criando Dashboards Efetivos em Grafana</h2>
<h3>Estrutura de um Dashboard Bem Projetado</h3>
<p>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.</p>
<p>Vamos criar um dashboard para monitorar aplicações em Kubernetes. No Grafana, clique em <strong>Create</strong> > <strong>Dashboard</strong> e adicione um novo panel. Escolha Prometheus como data source e insira a query abaixo:</p>
<pre><code class="language-promql">sum(rate(container_cpu_usage_seconds_total[5m])) by (pod_name)</code></pre>
<p>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:</p>
<pre><code class="language-promql">sum(container_memory_usage_bytes) by (pod_name) / 1024 / 1024</code></pre>
<h3>Integrando Logs no Dashboard com Loki</h3>
<p>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:</p>
<pre><code class="language-logql">{pod_name=~"$pod"} | json</code></pre>
<p>Use a variável <code>$pod</code> para permitir seleção dinâmica. Para configurar variáveis, vá em <strong>Dashboard Settings</strong> > <strong>Variables</strong> e crie uma nova variável com query Prometheus:</p>
<pre><code class="language-promql">label_values(container_cpu_usage_seconds_total, pod_name)</code></pre>
<p>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):</p>
<pre><code class="language-bash"># 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</code></pre>
<h2>Alertas em Grafana: Detecção e Notificação</h2>
<h3>Estruturando Regras de Alerta Práticas</h3>
<p>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.</p>
<p>Para criar um alerta efetivo, comece definindo a condição. No Grafana, abra um panel e clique em <strong>Alert</strong>. Configure uma query de avaliação — por exemplo, um alerta quando CPU ultrapassa 80%:</p>
<pre><code class="language-promql">avg(rate(container_cpu_usage_seconds_total[5m])) by (namespace, pod) > 0.8</code></pre>
<p>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:</p>
<pre><code class="language-yaml"># 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"</code></pre>
<h3>Configurando Notificações via Webhook</h3>
<p>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 <strong>Configuration</strong> > <strong>Notification channels</strong> e crie um novo canal:</p>
<pre><code class="language-json">{
"type": "webhook",
"settings": {
"url": "https://seu-sistema.com/api/alerts",
"httpMethod": "POST"
}
}</code></pre>
<p>Aqui está um exemplo de payload recebido pelo seu webhook:</p>
<pre><code class="language-json">{
"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"
}
]
}</code></pre>
<h3>Agrupamento e Silenciamento de Alertas</h3>
<p>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 <code>alertmanager.yml</code> para reduzir ruído:</p>
<pre><code class="language-yaml">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'</code></pre>
<p>O Grafana permite silenciar alertas manualmente através da UI. Isso é essencial durante manutenções planejadas:</p>
<pre><code class="language-bash"># 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"
}'</code></pre>
<h2>Loki: Centralizando e Consultando Logs</h2>
<h3>Arquitetura e Fluxo de Logs no Loki</h3>
<p>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.</p>
<p>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).</p>
<h3>Configuração de Promtail para Capturar Logs de Kubernetes</h3>
<p>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:</p>
<pre><code class="language-yaml">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</code></pre>
<h3>Queries Práticas em LogQL</h3>
<p>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á:</p>
<pre><code class="language-logql"># 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</code></pre>
<p>A query abaixo é particularmente útil para investigar comportamentos anormais — mostra a evolução de um erro ao longo do tempo:</p>
<pre><code class="language-logql">avg_over_time({namespace="staging", app="backend"} | json | duration | unwrap duration(s) [1m]) by (endpoint)</code></pre>
<h2>Conclusão</h2>
<p>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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://grafana.com/docs/grafana/latest/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Grafana</a></li>
<li><a href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/" target="_blank" rel="noopener noreferrer">Guia do Prometheus para Kubernetes</a></li>
<li><a href="https://grafana.com/docs/loki/latest/" target="_blank" rel="noopener noreferrer">Loki: Log Aggregation for Kubernetes</a></li>
<li><a href="https://www.prometheus.io/docs/guides/kubernetes-monitoring/" target="_blank" rel="noopener noreferrer">Kubernetes Monitoring with Prometheus (Livro)</a></li>
<li><a href="https://prometheus.io/docs/alerting/latest/configuration/" target="_blank" rel="noopener noreferrer">AlertManager Configuration Guide</a></li>
</ul>
<p><!-- FIM --></p>