Ephemeral containers: debugging sem alterar o pod

1. O que são Ephemeral Containers e por que surgiram?

O debugging em clusters Kubernetes sempre foi um desafio para times de DevOps. O clássico kubectl exec permite acesso a um container em execução, mas falha quando:

  • O container não possui shell ou ferramentas de diagnóstico (sh, curl, tcpdump)
  • O container está em estado CrashLoopBackOff e não aceita comandos
  • Você precisa de ferramentas específicas que não podem ser instaladas na imagem de produção

Ephemeral containers surgiram para resolver exatamente esse problema. Eles são containers temporários que se anexam a um pod já em execução, sem modificar a especificação original do pod. Diferentemente de sidecars (que são declarados no deployment e executam durante todo o ciclo de vida) ou init containers (que executam e morrem antes dos containers principais), os ephemeral containers são injetados sob demanda e existem apenas enquanto você precisa deles.

A característica fundamental é: você não precisa alterar o Deployment, StatefulSet ou Pod original. O pod continua intacto, mas ganha um container extra para debugging.

2. Pré-requisitos e habilitação da feature

A feature EphemeralContainers passou por estágios:

  • Kubernetes 1.16: alpha (feature gate necessário)
  • Kubernetes 1.23: beta (habilitado por padrão em muitos clusters)
  • Kubernetes 1.25+: estável (GA), disponível sem configuração adicional

Se você estiver em versões antigas, verifique o feature gate:

kubectl describe node | grep -i ephemeral

Para RBAC, a permissão necessária é pods/ephemeralcontainers. Um ClusterRole típico:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ephemeral-debugger
rules:
- apiGroups: [""]
  resources: ["pods/ephemeralcontainers"]
  verbs: ["create", "get", "list", "update", "patch", "delete"]

3. Comandos fundamentais: kubectl alpha debug e alternativas

O comando principal é kubectl debug. Até o Kubernetes 1.27, pode ser necessário usar kubectl alpha debug em algumas distribuições.

Sintaxe básica para anexar um ephemeral container ao pod em execução:

kubectl debug my-pod -it --image=busybox --target=my-container

Flags importantes:

  • --target: especifica o container alvo (para compartilhar namespace de processos)
  • --copy-to: cria um pod duplicado (útil quando o pod não está Running)
  • --share-processes: permite ver processos do container alvo via /proc
  • --container: nome personalizado para o ephemeral container

Diferença crucial: usar --copy-to cria um pod separado (clone), enquanto o comportamento padrão anexa ao pod existente sem modificar sua especificação.

4. Debugando sem modificar o pod original

O caso de uso mais comum é anexar um container com ferramentas de rede a um pod de produção que só tem o binário da aplicação.

Exemplo prático: anexar nicolaka/netshoot (imagem repleta de ferramentas como curl, dig, tcpdump, nslookup):

kubectl debug my-app-pod -it --image=nicolaka/netshoot --target=my-app-container

Dentro do netshoot, você pode:

# Ver processos do container alvo (com --share-processes)
ps aux

# Acessar sistema de arquivos do container alvo via /proc/PID/root
ls -la /proc/1/root/app/config.json

# Inspecionar variáveis de ambiente
cat /proc/1/environ | tr '\0' '\n'

# Ver arquivos de configuração compartilhados
cat /proc/1/root/etc/nginx/nginx.conf

5. Casos de uso avançados

Debug de falhas de startup: containers que nunca ficam Running (CrashLoopBackOff) não podem receber kubectl debug direto. Use --copy-to:

kubectl debug my-crashing-pod -it --image=busybox --copy-to=my-debug-pod

Isso cria um pod duplicado com um container extra, permitindo inspecionar volumes, variáveis de ambiente e configurações antes mesmo do container principal iniciar.

Coleta de dump de memória sem reiniciar: anexe um ephemeral container com gdb ou jcmd (para Java) e capture heap dumps:

kubectl debug my-java-pod -it --image=openjdk:11-slim --target=java-container
jcmd 1 GC.heap_dump /tmp/heap.hprof

Teste de conectividade entre pods: crie um pod duplicado em outro namespace para testar comunicação:

kubectl debug my-pod -it --image=nicolaka/netshoot --copy-to=debug-pod --namespace=debug-ns

6. Limitações e boas práticas

Restrições de segurança: ephemeral containers herdam o securityContext do pod, mas não podem ultrapassar PodSecurityPolicy (PSP) ou Pod Security Standards (PSS). Se o pod roda como restricted, seu ephemeral container também rodará restrito.

Não persistem: se o pod for recriado (por exemplo, após um rollout), o ephemeral container desaparece. Eles não fazem parte da especificação do pod e não são recriados.

Impacto em recursos: ephemeral containers consomem CPU e memória adicionais. Monitore com:

kubectl top pod my-pod

Logs: logs do ephemeral container aparecem junto com os do pod, mas podem ser filtrados pelo nome do container:

kubectl logs my-pod -c debug-container

Boas práticas:

  • Sempre remova ephemeral containers após o uso com kubectl delete pod --force ou editando a especificação (remova o campo ephemeralContainers)
  • Use imagens pequenas como busybox, alpine ou distroless para evitar overhead
  • Documente os comandos de debug para que o time inteiro possa usar

7. Comparação com ferramentas externas

Ferramenta Quando usar Limitação
kubectl debug Debug direto em pods running Não funciona em CrashLoopBackOff sem --copy-to
kubectl-node-shell Acesso ao nó (kubelet, containerd) Não resolve problemas de aplicação
stern + kubetail Agregação de logs multi-pod Apenas logs, sem acesso interativo
k9s Interface TUI para gestão de clusters Debug limitado a execução de comandos

Ephemeral containers não são a melhor escolha quando:

  • Você precisa de debug persistente (use sidecar)
  • O cluster é muito antigo (< 1.16)
  • Há restrições severas de segurança que impedem containers interativos

8. Exemplo completo: debug de um pod com falha de DNS

Cenário: aplicação web-frontend não resolve nomes de domínio externos.

Passo 1: Verificar estado do pod

kubectl get pods web-frontend
NAME           READY   STATUS    RESTARTS   AGE
web-frontend   1/1     Running   2          15m

Passo 2: Anexar netshoot com compartilhamento de processos

kubectl debug web-frontend -it --image=nicolaka/netshoot --target=web-frontend-container

Passo 3: Testar DNS dentro do netshoot

# Testar resolução
nslookup google.com
;; connection timed out; no servers could be reached

# Ver configuração de DNS do pod
cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

# Verificar conectividade com o servidor DNS
nc -zv 10.96.0.10 53

Passo 4: Identificar problema — o servidor DNS (CoreDNS) não está respondendo. Verifique o cluster:

kubectl get pods -n kube-system -l k8s-app=kube-dns

Passo 5: Limpeza — remova o ephemeral container

# Saia do container (Ctrl+D ou exit)
# Remova o campo ephemeralContainers do pod
kubectl patch pod web-frontend --type=json -p='[{"op": "remove", "path": "/spec/ephemeralContainers"}]'

Se preferir, force a exclusão e recriação:

kubectl delete pod web-frontend --force --grace-period=0

O deployment recriará o pod automaticamente.

Referências