Observabilidade de Rede com Cilium Hubble: Visualizando Fluxos de Tráfego em Clusters Kubernetes

Monitore complexos microserviços em execução no kubernetes exige mais do que apenas logs de aplicação e métricas básicas de CPU. A camada de rede é o coração da comunicação entre pods, mas historicamente permanece uma “caixa preta” para muitas equipes. cilium, na vanguarda do networking e segurança baseado em ebpf, introduz o Hubble para preencher essa lacuna, oferecendo uma observabilidade profunda do plano de dados com zero impacto de desempenho. Vamos mergulhar na arquitetura, instalação e utilização prática do Hubble para mapear e auditaria o tráfego da sua mesh de serviços em tempo real.

Arquitetura do Hubble: O Poder do eBPF no Core da Rede

O Hubble não é um agente de coleta tradicional que vaza pacotes para um pipeline de logs. Ele opera como um serviço de observabilidade distribuído, embutido diretamente no agente do Cilium (cilium-agent) em cada nó. Utilizando programas eBPF carregados nos hooks de rede do kernel (XDP para ingresso e socket filters para egresso), ele observa o fluxo de dados sem copiar pacotes para o espaço do usuário. Cada evento de fluxo capturado é estruturado com metadados ricos – identidade do pod, namespace, labels do Kubernetes, portas e protocolos – e enviados para o monitor do Hubble em um nó de escolha (geralmente o nó onde a API do Hubble reside).

Essa arquitetura peer-to-peer garante baixa latência e elimura o single point of failure da coleta. O monitor agrega esses fluxos e expõe uma API RESTful e um endpoint para o Hubble UI. É crucial entender que a eBPF perfila o fluxo no kernel antes que políticas do Cilium ou qualquer outro mecanismo de filtragem interfaçam. Isso significa que você visualiza o “tráfego real”, o que é fundamental para diagnóstico de falhas de política de rede e para entender comportamento não intencional.

Diagrama de Fluxo: (1) Tráfego entra no nó; (2) Programa eBPF observa o pacote no hook XDP/TC; (3) Metadados são extraídos; (4) Evento é emitido para o loopback; (5) Cilium Agent captura o evento; (6) Hubble Monitor recebe o evento; (7) Hubble UI/API query o banco de dados de fluxo.

Dependências de Infraestrutura

Para a implantação em produção, três componentes são não-negociáveis: um kernel Linux compatível (5.10+ recomendado), o Cilium operando em modo de dataplane BPF (configurado via flag --kube-proxy-replacement=strict), e o RBAC do Kubernetes para conceder permissões ao Hubble de acessar informações do API Server. O Hubble UI necessita de um endpoint autenticado; em ambientes restritos, configuramos um túnel LocalProxy através do hubble-relay.

Instalação via Cilium CLI e Helm

Não há “instalação do Hubble” como um helm chart separado na versão estável; ele é um flag estrutural do próprio Cilium. A primeira etapa é garantir que o Cilium seja operado com o dataplane eBPF habilitado. No terminal do seu terminal de operações, verifique a versão do kernel e instale o Cilium usando a CLI oficial.

# Verifica compatibilidade do kernel (BPF é essencial)
uname -r
# Saída esperada: 5.15.0-101-generic ou superior

# Adiciona o repositório do Cilium
helm repo add cilium https://helm.cilium.io/
helm repo update

# Instala o Cilium com Hubble habilitado por padrão
# Flags críticas: --kube-proxy-replacement e --hubble-enabled
cilium install --set kubeProxyReplacement=strict --set hubble.enabled=true

O comando acima é a abordagem declarativa mínima. Em uma implantação IaC completa usando Terraform ou Helmfile, você deve definir valores específicos para otimizar o buffer de fluxos do Hubble, especialmente em clusters de alta taxa de pacotes. Edite um arquivo values.yaml do Helm para essa finalidade:

# values-hubble-prod.yaml
cilium:
  hubble:
    enabled: true
    metrics:
      enabled:
        - "flow"
        - "drop"
        - "port-distribution"
    relay:
      enabled: true
    ui:
      enabled: true
  # Ajuste de buffer para picos de tráfego
  agent:
    hubble-event-buffer-capacity: 10000
    hubble-metrics-server: ":4244"

# Aplicação via Helmfile ou CLI
helm upgrade --install cilium cilium/cilium 
  --namespace kube-system 
  --values values-hubble-prod.yaml

Após a instalação, a validação é via cilium status. Uma saída saudável deve mostrar o Hubble como “OK”. O Hubble Relay (o serviço de proxy para acessar os monitores distribuídos) deve ser acessível, e a UI pode ser port-forwarded para inspeção local.

Exploração de Fluxos via Hubble UI e CLIs

A Hubble UI oferece uma visualização de grafos de dependência de serviços em tempo real. No entanto, para automação e troubleshooting eficiente, o hubble CLI é o ferramenta primária. Ele se conecta diretamente ao socket UNIX do monitor localmente ou através do relay para consultas agregadas.

Para listar fluxos ativos de um namespace específico em tempo real:

# Conecta-se ao relay (se acessível externamente) ou localmente
hubble status

# Monitora fluxos de entrada/saída do namespace 'payment-service'
# Filtros avançados por label do Kubernetes
hubble observe --follow 
  --namespace payment-service 
  --label k8s:app=payment-api 
  --type l7 
  --verdict FORWARDED

# Saída estruturada:
# 2023-10-27T14:30:05.123456Z    flow        FORWARDED    TCP     10.244.1.5:443 -> 10.244.2.8:55555  [app:payment-api, namespace:payment-service]

Na Hubble UI, os grafos são construídos dinamicamente. Um fluxo de um pod frontend-v1 para backend-v2 aparece como uma seta direcionada. Clicar no link revela métricas de latência, taxa de pacotes e verificações de política de segurança aplicadas (negada, permitida, default-deny). Para equipes SRE, a visualização de “drop flows” (pacotes descartados por políticas ou congestionamento) é a primeira etapa do diagnóstico de “comunicação quebrotizante” em microserviços.

Integração com Prometheus e Grafana para Métricas Profundas

Enquanto o Hubble é excelente para traces de fluxo individual, a observabilidade em escala exige agregação e alerta. O Hubble exporta métricas no formato padrão do Prometheus. Habilitar essa exportação altera o dado da configuração do Helm (ou via ConfigMap) para expor o endpoint de métricas.

No seu values.yaml ou ConfigMap do Cilium Agent, adicione:

# Exemplo de ConfigMap para habilitar métricas Hubble
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  hubble-metrics: "flow:source_namespace,source_pod,destination_namespace,destination_pod,source_ip,destination_ip,ip,verdict,story,l7proto;drop:source_namespace,source_pod,destination_namespace,destination_pod,drop_reason,source_ip,destination_ip,verdict;port-distribution;dns"
  enable-hubble-metrics: "true"
  hubble-metrics-server: ":4244"

Depois de aplicar a ConfigMap e reiniciar os pods do Cilium, o endpoint http://<pod-ip>:4244/metrics estará disponível. Configurar o Prometheus no Kubernetes para realizar um scraping scrapping na port 4244 com um label específico (ex: app: hubble-metrics) injeta as métricas no seu banco de series temporais. Exemplos de queries PromQL úteis:

# Taxa de pacotes dropados por namespace (útil para alertas)
rate(hubble_drop_total{namespace="production"}[5m]) > 0.1

# Distribuição de tráfego L7 por protocolo (HTTP, gRPC, DNS)
sum by (protocol) (rate(hubble_flow_total{verdict="FORWARDED",source_namespace="api-gateway"}[5m]))

Para visualização, um dashboard Grafana pré-construído pelo Cilium Community pode importado via ID `17935` ou, como boas práticas, definimos como IaC usando o plugin de datasource Prometheus e adiccionamos painéis que correlacionam métricas de rede (fluxos do Hubble) com métricas de aplicação (latência de pod, taxas de erro HTTP) vindas do Instrumentation padrão (OpenTelemetry).

Auditoria de Segurança com Hubble CLI e Scripts

A observabilidade de rede vai além de debug; é uma camada de segurança ativa. O Hubble permite auditorizar quem está comunicando com quem em runtime, comparando o fluxo real com a CiliumNetworkPolicy definida. Vamos criar um script BASH para auditoria contínua de conexões não-autorizadas.

#!/bin/bash
# audit-unauthorized-connections.sh
# Executa a cada 5 minutos via CronJob

NAMESPACES=$(kubectl get ns -o jsonpath='{.items[*].metadata.name}')

for ns in $NAMESPACES; do
  echo "Auditing namespace: $ns"
  # Coleta fluxos com veredito DROP no último minuto
  hubble observe --namespace "$ns" 
    --verdict DROPPED 
    --type L3_L4 
    --last 1m 
    --output json | 
    jq -r '.flow | "Namespace: (.source.namespace), Pod: (.source.pod), Dest: (.destination.ip), Reason: (.drop_reason)"'
done

# Saída exemplo para logs:
# Namespace: payment-service, Pod: payment-api-5f4b, Dest: 10.244.3.12, Reason: Policy denied

Esse script pode ser encapsulado em uma imagem Docker dedicada para execução como um CronJob. Ele exige que o Hubble CLI esteja presente na imagem ou que o container faça port-forwarding para o socket do Hubble Relay. Em ambientes GitOps, esse script é o primeiro passo para criar uma “Policy as Code” mais rígida baseada no comportamento observado, através de ferramentas como o cilium-cli para aplicar políticas derivadas.

Otimização de Performance e Controle de Dados

Em clusters de alta escala (1000+ pods), o volume de fluxos capturados pelo Hubble pode ser massivo. A otimização é essencial para não afetar a CPU do nó e saturar a rede com logs. Duas estratégias devem ser implementadas: filtragem agressiva e retenção de dados.

A filtragem pode ser feita via ConfigMap. Não é recomendado capturar todos os fluxos em produção. Filtre por namespace crítico ou por tipo de evento. Um exemplo de configuração que captura apenas fluxos de erro e dados de política de L7:

apiVersion: v1
kind: ConfigMap
metadata:
  name: hubble-config
data:
  # Não captura fluxos BYPASS (COMUNICAÇÃO LOCAL PADRÃO)
  events: "[FLOW, L7, DROPPED, DEBUG]"
  # Limita a taxa de eventos por segundo por nó
  rate-limit: "1000"
  # Buffer de eventos antes de descartar (evita perda em picos)
  buffer-size: "10000"

Para controle de duração dos dados, o Hubble UI armazena fluxos em memória por padrão. Para retenção persistente, integra-se o Hubble com um sistema de logging (Fluent Bit) que consome do socket do Hubble Relay ou exporta para um armazenamento de longo prazo como S3 ou Elasticsearch. Abaixo, um exemplo de ConfigMap do Fluent Bit para parsing de logs JSON do Hubble:

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-config
data:
  fluent-bit.conf: |
    [INPUT]
        Name              tail
        Path              /var/log/cilium/hubble/*.log
        Parser            json
        Tag               hubble.flows

    [FILTER]
        Name              modify
        Match             hubble.flows
        Add               cluster_name prod-k8s-us-east

    [OUTPUT]
        Name              es
        Match             hubble.flows
        Host              elasticsearch.kube-logging.svc.cluster.local
        Port              9200
        Index             hubble-flows
        Type              _doc

Esta abordagem garante que você tenha tracibilidade completa (Hubble UI para fluxo em tempo real + Elasticsearch para análise forense) sem sobrecarregar o cluster.

Cenários de Debug Avançado: Correlação de Falhas

Um caso clássico é a falha de um microserviço com erro 503 do gateway. Logs do aplicativo mostram timeouts, mas a causa raiz é na camada de rede. Usando o Hubble CLI com correlação de labels, podemos isolar o problema.

Suponha um serviço orders-api falhando. Primeiro, identificamos os pods de destino do gateway que estão servindo o orders-api:

# Lista pods com a label app=orders-api no namespace production
kubectl get pods -n production -l app=orders-api -o wide
# Saída: orders-api-xyz-0  10.244.1.5  Running

Agora, examinamos o tráfego L3/L4 de um gateway específico para esse pod, filtrando por drop e verdict:

hubble observe --follow 
  --namespace production 
  --source-ip 10.244.0.10  # IP do pod do gateway 
  --destination-ip 10.244.1.5 
  --verdict DROPPED 
  --type L3_L4

Se o output mostrar Reason: Policy denied ou Reason: Unknown, sabemos que a política CiliumNetworkPolicy bloqueia a conexão, não que o pod está morto. Podemos verificar a política aplicada no pod destino:

cilium policy get | grep -A 20 orders-api

Combinando essa saída com o fluxo observado, você identifica rapidamente se a falha é de configuração de política (ex: faltou uma porta TCP) ou de um DNS interno que resolveu um IP errado (verificado via --type L7 --l7-protocol DNS no Hubble). Essa capacidade de correlacionar o tráfego em tempo real com a configuração de segurança é a chave para um MTTR (Mean Time To Resolution) drasticamente reduzido.

Automatizando a Geração de Dashboards e Alertas

Para equipes que operam em GitOps, a definição de dashboards e alertas deve ser código. A integração com Prometheus Alertmanager e Grafana via Terraform ou ArgoCD permite versionar sua observabilidade.

Um exemplo de Alerta no Prometheus Alertmanager baseado em métricas do Hubble (definido em um arquivo alert-rules.yaml):

groups:
- name: hubble-network-alerts
  rules:
  - alert: HighDropRate
    expr: rate(hubble_drop_total[5m]) > 10
    for: 2m
    labels:
      severity: warning
      team: sre
    annotations:
      summary: "Alta taxa de pacotes dropados no cluster {{ $labels.cluster }}"
      description: "Pod {{ $labels.source_pod }} está descartando pacotes para {{ $labels.destination_ip }}. Motivo: {{ $labels.drop_reason }}"

Para o Grafana, utilizamos o provider do Grafana para declarar o dashboard como código. Abaixo, um trecho de Terraform para provisionar um painel base:

resource "grafana_dashboard" "hubble_overview" {
  config_json = jsonencode({
    title   = "Hubble Network Flows"
    tags    = ["cilium", "network", "hubble"]
    panels  = [
      {
        title = "Flow Rate by Namespace"
        type  = "graph"
        targets = [{
          expr = "sum by (namespace) (rate(hubble_flow_total{verdict="FORWARDED"}[5m]))"
        }]
      }
    ]
  })
}

Essa abordagem garante que todos os clusters de produção tenham o mesmo nível de visibilidade e que a resposta a incidentes seja automatizada, reduzindo a dependência de ações manuais e a fadiga de alertas para a equipe de operações.

Em resumo, a implementação do Hubble transforma a rede de um componente opaco em uma entidade auditável e autodescritiva. Ao abraçar a observabilidade de fluxo com ferramentas nativas do eBPF, as equipes DevOps podem governar microsserviços com a mesma precisão que gerenciam a computação de aplicação.