CrashLoopBackOff no Kubernetes: como identificar e resolver na prática

Entenda o CrashLoopBackOff no Kubernetes e siga um fluxo objetivo de troubleshooting para identificar a causa raiz e corrigir o problema.

Ilustração do diagnóstico de um Pod em CrashLoopBackOff até sua recuperação no Kubernetes

Você executa um deploy no Kubernetes e, ao consultar os Pods, encontra algo como:

CrashLoopBackOff

Esse status normalmente indica que o container está iniciando, falhando e sendo reiniciado repetidamente.

Mas existe um ponto importante: CrashLoopBackOff não é a causa raiz do problema. Ele representa o comportamento do Kubernetes diante de um container que continua falhando.

O objetivo do troubleshooting é descobrir por que o processo dentro do container está encerrando ou sendo reiniciado.

O que é CrashLoopBackOff

Quando um container termina inesperadamente, o Kubernetes pode tentar iniciá-lo novamente.

Se a falha continua acontecendo, o kubelet aumenta progressivamente o intervalo entre as novas tentativas de inicialização. Esse mecanismo de espera é o chamado backoff.

Na prática, o comportamento pode ser resumido assim:

container inicia

processo falha

container termina

Kubernetes reinicia

processo falha novamente

CrashLoopBackOff

Por isso, ao encontrar esse status, a pergunta não deve ser apenas:

Como remover o CrashLoopBackOff?

A pergunta correta é:

Por que o processo do container está falhando?

Causas comuns

Entre as causas mais frequentes estão:

  • erro da própria aplicação durante o startup;
  • command ou args incorretos;
  • variável de ambiente inválida ou ausente;
  • ConfigMap ou Secret incorreto;
  • falha de acesso a banco, API, cache ou broker;
  • permissões inadequadas;
  • problemas de volume ou filesystem;
  • container encerrado por falta de memória (OOMKilled);
  • liveness ou startup probe configurada incorretamente.

O troubleshooting deve sempre buscar evidências antes de qualquer alteração no workload.

Primeiro passo: identificar o Pod com problema

Comece verificando os Pods do namespace:

kubectl get pods -n <namespace>

Observe principalmente:

READY
STATUS
RESTARTS

Um exemplo típico:

NAME                         READY   STATUS             RESTARTS
app-7c8f9d7b7f-xk2m9         0/1     CrashLoopBackOff   5

O número crescente em RESTARTS confirma que o container está sendo reiniciado repetidamente.

Terminal mostrando o Pod crashloop-demo em CrashLoopBackOff e cinco reinicializações

Analise o Pod com kubectl describe

O próximo passo é:

kubectl describe pod <pod> -n <namespace>

Procure principalmente por:

State
Last State
Reason
Exit Code
Restart Count
Events

O campo Last State pode mostrar como a execução anterior terminou.

Por exemplo:

Last State:     Terminated
Reason:         Error
Exit Code:      1

Em outros cenários, podemos encontrar:

Reason: OOMKilled

Os Events exibidos no final do describe também podem revelar falhas de probes, mounts, reinicializações e outros problemas relacionados ao Pod.

Saída do kubectl describe com estado Terminated, Exit Code 1 e seis reinicializações

Events do Pod mostrando o aviso BackOff ao reiniciar o container web

Verifique os logs do container

Depois, consulte os logs:

kubectl logs <pod> -n <namespace>

Em muitos casos, a causa aparece diretamente na saída da aplicação.

Exemplos:

FATAL: variável DATABASE_URL não configurada

ou:

Connection refused

ou ainda:

Configuration file not found

Logs claros reduzem bastante o tempo necessário para encontrar a causa raiz.

Consulte os logs da execução anterior

Esse é um dos comandos mais importantes em casos de CrashLoopBackOff:

kubectl logs <pod> -n <namespace> --previous

Também é possível utilizar:

kubectl logs -p <pod> -n <namespace>

Como o container pode reiniciar rapidamente, os logs mais relevantes podem pertencer justamente à execução anterior.

É comum encontrar aqui a mensagem exibida imediatamente antes do processo encerrar.

Logs anteriores indicando APP_MODE com valor broken em vez de production

Verifique o Exit Code e o estado anterior

Também podemos consultar diretamente o último estado do container:

kubectl get pod <pod> \
  -n <namespace> \
  -o jsonpath='Reason anterior: {.status.containerStatuses[0].lastState.terminated.reason}{"\n"}Exit code anterior: {.status.containerStatuses[0].lastState.terminated.exitCode}{"\n"}Restarts: {.status.containerStatuses[0].restartCount}{"\n"}'

Uma saída possível:

Reason anterior: Error
Exit code anterior: 1
Restarts: 5

O Exit Code sozinho nem sempre explica a falha.

O importante é correlacionar:

Status
+
Last State
+
Exit Code
+
Logs
+
Events
+
Configuração do workload

Consulta JSONPath mostrando motivo Error, Exit Code 1 e seis reinicializações

Analise os Events

Para visualizar os eventos em ordem cronológica:

kubectl get events \
  -n <namespace> \
  --sort-by=.metadata.creationTimestamp

Em um cenário de CrashLoopBackOff, podemos encontrar eventos relacionados ao mecanismo de backoff.

Em outros casos, os Events podem apontar para:

  • falha de volume;
  • erro de probe;
  • problema de scheduling;
  • falha na obtenção da imagem;
  • problemas durante a inicialização do container.

Eventos em ordem cronológica mostrando o BackOff do container no namespace crashloop-lab

Confira a configuração do workload

Depois de coletar as evidências, consulte o manifesto efetivamente aplicado:

kubectl get deployment <deployment> \
  -n <namespace> \
  -o yaml

Verifique principalmente:

  • command;
  • args;
  • variáveis de ambiente;
  • ConfigMaps;
  • Secrets;
  • volumes;
  • probes;
  • requests e limits.

No cenário utilizado neste laboratório, os logs mostraram que a aplicação encerrava durante a inicialização porque uma variável de ambiente possuía um valor inválido.

A aplicação esperava:

APP_MODE=production

mas havia sido configurada como:

APP_MODE=broken

Nesse caso, o Kubernetes estava funcionando corretamente. O processo da aplicação é que encerrava com erro.

Manifesto do Deployment mostrando APP_MODE com o valor inválido broken

Corrigindo o problema

Depois de identificar a causa raiz, corrigimos a configuração do Deployment:

kubectl set env \
  deployment/<deployment> \
  -n <namespace> \
  APP_MODE=production

Comando kubectl set env atualizando APP_MODE para production no Deployment

A alteração no Pod template gera um novo rollout.

Acompanhe:

kubectl rollout status \
  deployment/<deployment> \
  -n <namespace>

Terminal confirmando que o Deployment crashloop-demo concluiu o rollout

Depois valide:

kubectl get pods -n <namespace>

O esperado é que o novo Pod permaneça:

1/1   Running

Novo Pod em estado Running, pronto e sem reinicializações

Por fim, consulte novamente os logs:

kubectl logs <novo-pod> -n <namespace>

Logs do novo Pod confirmando APP_MODE production e a inicialização válida do Nginx

Isso confirma se a aplicação concluiu sua inicialização corretamente.

Um fluxo simples para troubleshooting

Para a maioria dos primeiros diagnósticos, podemos seguir esta sequência:

kubectl get pods -n <namespace>
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --previous
kubectl get events \
  -n <namespace> \
  --sort-by=.metadata.creationTimestamp

Depois, conforme as evidências encontradas:

kubectl get deployment <deployment> \
  -n <namespace> \
  -o yaml

O objetivo não é executar comandos aleatoriamente, mas construir uma sequência de evidências até chegar à causa raiz.

Boas práticas

Algumas práticas ajudam a reduzir esse tipo de incidente e também tornam o troubleshooting mais rápido.

Produza logs úteis

A aplicação deve registrar claramente erros ocorridos durante o startup, sem expor senhas, tokens ou outros segredos.

Valide configurações antes do deploy

Pipelines podem verificar manifests, variáveis obrigatórias, Helm charts, sintaxe e policies antes que a alteração chegue ao cluster.

Configure probes corretamente

Liveness e startup probes precisam refletir o comportamento real da aplicação.

Uma probe configurada com tempos ou endpoints incorretos pode provocar reinicializações desnecessárias.

Defina recursos com base em métricas

Requests e limits devem refletir o consumo real do workload.

Limits de memória inadequados podem causar OOMKilled.

Monitore reinicializações

Aumento no restartCount, Pods não Ready e falhas recorrentes de probes são sinais que devem fazer parte da observabilidade do cluster.

Conclusão

CrashLoopBackOff não deve ser tratado como causa raiz.

Ele é um sintoma de que o Kubernetes está tentando manter um container em execução, mas alguma condição continua fazendo o processo falhar.

Um fluxo objetivo de investigação pode ser resumido assim:

observar o Pod

analisar describe

consultar logs

consultar logs anteriores

verificar Exit Code

analisar Events

validar configuração

corrigir a causa

validar o novo rollout

Mais importante do que decorar comandos é aprender a correlacionar as evidências apresentadas pelo Kubernetes com o comportamento da aplicação.

É isso que transforma um simples CrashLoopBackOff em uma causa raiz identificável e corrigível.

Referências