Pular para o conteúdo
Abrir o Kubepier

Kubernetes · guia

CrashLoopBackOff: o que significa e como resolver em 5 comandos

Equipe IA4CODE
engenharia de plataforma e SRE
publicado em 25 set 2026 8 min de leitura verificado contra a documentação do Kubernetes ("Pod Lifecycle")

TL;DR

CrashLoopBackOff não é o erro: é o kubelet avisando que o container caiu, foi reiniciado, caiu de novo, e que agora ele espera cada vez mais entre tentativas: 10 s, 20 s, 40 s, até o teto de 5 minutos (documentação do Kubernetes, "Pod Lifecycle"). A causa está dentro do container. Cinco comandos resolvem a maioria dos casos: get pods para confirmar o padrão de reinícios, describe pod para ler o Last State e o Exit Code, logs --previous para ver o que o container escreveu antes de morrer, get events para o que o kubelet reportou e exec ou debug para testar a hipótese de dentro. O exit code aponta a família da causa: 137 é memória (OOMKilled), 1 é erro da aplicação, 127 é comando não encontrado.

O que o CrashLoopBackOff significa (e o que não significa)

Todo pod tem um restartPolicy, e o padrão é Always. Quando um container termina, com sucesso ou não, o kubelet o reinicia. Se ele terminar de novo logo depois, o kubelet passa a esperar antes de tentar: 10 segundos, depois 20, 40, 80, e assim por diante, com teto de 5 minutos. Se o container ficar 10 minutos rodando sem cair, o contador zera. Esses números vêm da documentação do Kubernetes, seção "Pod Lifecycle", item "Container restart policy".

Enquanto espera, o pod mostra CrashLoopBackOff na coluna STATUS. É um estado de espera, não uma causa. A pergunta certa não é "por que o Kubernetes está reiniciando meu pod?", e sim "por que meu processo termina?". As respostas moram em dois lugares: no exit code do último término e no log do container anterior.

notaDeletar o pod cria um pod novo, sem o back-off acumulado, e ganha alguns segundos de Running. Não muda o exit code seguinte. Se você já deletou três vezes hoje, pule para o comando 2.

comando 1Confirme o padrão com kubectl get pods

Antes de qualquer hipótese, olhe a coluna RESTARTS. Um pod com 6 reinícios em 9 minutos está em loop; um pod com 1 reinício em 3 dias teve um soluço. O kubectl mostra há quanto tempo foi o último reinício entre parênteses. Um detalhe que engana: um pod em CrashLoopBackOff continua na fase Running (quem está em espera é o container), então filtrar por status.phase não o encontra. Filtre pela coluna STATUS.

bash · namespace loja
kubectl -n loja get pods
# só o que não está Running na coluna STATUS:
kubectl -n loja get pods --no-headers | grep -v ' Running '
NAME                         READY   STATUS             RESTARTS      AGE
catalogo-5c4b7d8f9-p9m2r     1/1     Running            0             3d2h
checkout-7d9f8b6c4-x2k4q     0/1     CrashLoopBackOff   6 (42s ago)   9m17s
pagamentos-6f8d1c2a7-k3z7w   1/1     Running            0             3d2h

comando 2Leia o Last State com kubectl describe pod

O describe é longo; o que importa está em dois blocos. Last State diz como o container anterior terminou: Reason e Exit Code. Events, no fim, mostra o que o kubelet fez e quantas vezes.

terminal
kubectl -n loja describe pod checkout-7d9f8b6c4-x2k4q
# só o estado anterior, sem o resto:
kubectl -n loja get pod checkout-7d9f8b6c4-x2k4q -o jsonpath='{.status.containerStatuses[0].lastState}'
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
    Restart Count:  6
    Limits:
      cpu:     500m
      memory:  512Mi
    Requests:
      cpu:     250m
      memory:  256Mi
Events:
  Type     Reason   Age                   From     Message
  Warning  BackOff  38s (x26 over 8m51s)  kubelet  Back-off restarting failed container checkout

Aqui o caso já está quase fechado: Reason OOMKilled, Exit Code 137, limite de 512Mi. O container passou do limite de memória e o kernel o matou. A tabela de exit codes mais abaixo cobre os outros valores.

comando 3O log que importa é o anterior: kubectl logs --previous

O erro mais comum de quem está começando: rodar kubectl logs e ver o container atual, que acabou de subir e ainda não deu erro. A flag --previous (ou -p) mostra o log do container que morreu.

terminal
kubectl -n loja logs checkout-7d9f8b6c4-x2k4q --previous --tail=100
# pod com mais de um container: nomeie o container
kubectl -n loja logs checkout-7d9f8b6c4-x2k4q -c checkout --previous --timestamps
{"level":"info","msg":"iniciando checkout 2.14.0"}
{"level":"info","msg":"carregando catálogo em memória","itens":412000}
{"level":"warn","msg":"heap em 91% do limite do container"}
(fim do log: o processo foi morto sem escrever mais nada)

Num OOMKilled o log costuma terminar no meio do trabalho: o kernel não avisa o processo. A última linha antes do silêncio é a pista. Num erro de aplicação (exit 1), ao contrário, o log geralmente termina com a exceção completa.

comando 4O que o cluster disse: kubectl get events

Os eventos contam a história em ordem: agendado, imagem puxada, container criado, iniciado, back-off. Se aparecer um Unhealthy antes do Killing, a causa é uma liveness probe, não a aplicação. Eventos são retidos por 1 hora por padrão (flag --event-ttl do kube-apiserver); depois disso, só no seu sistema de observabilidade.

terminal
kubectl -n loja get events --sort-by=.lastTimestamp \
  --field-selector involvedObject.name=checkout-7d9f8b6c4-x2k4q
LAST SEEN   TYPE      REASON      MESSAGE
9m18s       Normal    Scheduled   Successfully assigned loja/checkout-7d9f8b6c4-x2k4q to aks-nodepool1-vmss000002
9m17s       Normal    Pulled      Container image "registry.loja.internal/checkout:2.14.0" already present on machine
41s         Normal    Created     Created container checkout
41s         Normal    Started     Started container checkout
12s         Warning   BackOff     Back-off restarting failed container checkout

comando 5Teste a hipótese de dentro: kubectl exec e kubectl debug

Se o container fica de pé por alguns segundos, exec dá tempo de conferir variáveis e conectividade. Se não fica, kubectl debug anexa um container efêmero ao pod, compartilhando o namespace de processos do container alvo (documentação do Kubernetes, "Debug Running Pods"; contêineres efêmeros são estáveis desde a versão 1.25).

terminal
# variáveis que o container realmente recebeu
kubectl -n loja exec checkout-7d9f8b6c4-x2k4q -- env | grep -iE 'db_|redis_|java_'
# o container não fica de pé: container efêmero com ferramentas
kubectl -n loja debug -it checkout-7d9f8b6c4-x2k4q --image=busybox:1.36 --target=checkout
# testar a dependência de dentro do pod
nc -zv -w 3 postgres.loja.svc.cluster.local 5432

Tabela: o exit code aponta a família da causa

Códigos acima de 128 seguem a convenção POSIX: 128 mais o número do sinal que matou o processo. Os demais são definidos pela própria aplicação ou pelo shell.

Exit codeOrigemFamília da causaOnde olhar
0processo terminou normalmenteO comando principal acaba. Comum em imagens cujo CMD roda um script e sai.Dockerfile: CMD e ENTRYPOINT; o processo precisa ficar em primeiro plano
1erro genérico da aplicaçãoExceção não tratada, configuração inválida, dependência recusando conexão.logs --previous: a exceção costuma estar nas últimas linhas
126shell: não executávelO entrypoint existe mas não tem permissão de execução.Dockerfile: chmod +x ou usuário errado
127shell: command not foundBinário ausente na imagem ou caminho errado no CMD.Dockerfile e imagem base (distroless, alpine)
137128 + 9 (SIGKILL)Quase sempre OOMKilled: o container passou do limite de memória.describe pod: Reason OOMKilled; limits.memory
139128 + 11 (SIGSEGV)Falha de segmentação: binário nativo, biblioteca incompatível com a arquitetura.imagem: arquitetura (amd64 ou arm64) e dependências nativas
143128 + 15 (SIGTERM)Encerrado pelo kubelet: liveness probe falhou, rollout, eviction ou scale-down.get events: Unhealthy e Killing antes do término

fontes: convenção POSIX de códigos de saída; lista de sinais do Linux (man 7 signal); documentação do Kubernetes, "Pod Lifecycle"

As 5 causas mais comuns e a correção de cada uma

Limite de memória abaixo do picoexit 137 · OOMKilled

O limits.memory foi copiado de um tutorial ou de outro serviço. A aplicação carrega cache, catálogo ou pool na subida e passa do teto.

Correção: Meça o uso real e defina o limite acima do pico. Em JVM e Node, faça o runtime respeitar o limite do container (MaxRAMPercentage, --max-old-space-size). Veja a página de erro OOMKilled.

Dependência indisponível na subidaexit 1 · ECONNREFUSED no log

O banco, a fila ou o gerenciador de segredos ainda não respondiam quando o processo iniciou, e a aplicação encerra em vez de tentar de novo.

Correção: Retry com back-off dentro da aplicação e uma startupProbe com failureThreshold generoso. initContainers que esperam para sempre só escondem o problema.

Variável ou Secret com valor erradoexit 1 · erro de parse ou autenticação

A chave existe (senão seria CreateContainerConfigError), mas o valor está vazio, com quebra de linha no fim ou em base64 duplo.

Correção: kubectl exec -- env para ver o que o container recebeu; kubectl get secret -o jsonpath e decodifique o valor.

Comando que terminaexit 0 em loop

O CMD roda uma migração ou um script e sai com sucesso. Para o Kubernetes, um container que termina precisa ser reiniciado.

Correção: Processo em primeiro plano no CMD. Tarefa que termina é Job, não Deployment.

Liveness probe agressivaexit 143 · Unhealthy nos eventos

A aplicação demora a ficar pronta e a liveness probe usa os padrões: período 10 s, timeout 1 s, 3 falhas. O kubelet mata um processo saudável.

Correção: startupProbe para a subida e liveness com timeout e failureThreshold realistas (documentação do Kubernetes, "Configure Liveness, Readiness and Startup Probes").

deployment.yaml · correção para o caso do exemplo (OOMKilled)
resources:
  requests: { cpu: 250m, memory: 512Mi }
  limits:   { cpu: 500m, memory: 1Gi }
env:
  - name: JAVA_TOOL_OPTIONS
    value: "-XX:MaxRAMPercentage=75.0"

Como o Kubepier mostra isso

O Kubepier mostra os eventos do pod, com os avisos primeiro, e o log. O diagnóstico por IA explica o erro a partir deles, em português: causa provável, evidência e correção sugerida. Você usa a sua própria chave de API (Anthropic ou OpenAI). Abaixo, uma ilustração do painel para o pod deste guia, com dados fictícios.

Kubepier um produto
CrashLoopBackOff · 6 reinícios
Last StateTerminated · OOMKilled
exit 137
Consumolimit 512Mi · uso 498Mi
request 256Mi
Log anterior · última linhawarn heap em 91% do limite do container
Diagnóstico por IA · sua chave Anthropic ou OpenAI

O container excede o limite de memória ao carregar o catálogo na subida. Evidência: OOMKilled com exit 137 nos eventos e aviso de heap a 91% antes do término, no log. Correção sugerida: subir limits.memory acima do uso real e alinhar o heap da JVM ao limite (MaxRAMPercentage).

Perguntas frequentes

CrashLoopBackOff é um erro do Kubernetes ou da minha aplicação?

Da aplicação, quase sempre. O Kubernetes só reporta que o container terminou e que está esperando cada vez mais entre reinícios. A causa está no exit code (describe pod) e no log anterior (logs --previous). As exceções são a liveness probe mal configurada e o limite de memória baixo, que são configuração sua no manifesto.

Quanto tempo o kubelet espera entre reinícios?

Começa em 10 segundos e dobra a cada falha (20, 40, 80…), com teto de 5 minutos. Depois que o container roda 10 minutos sem cair, o contador zera. Fonte: documentação do Kubernetes, "Pod Lifecycle", item "Container restart policy".

Por que kubectl logs não mostra nada?

Sem --previous você vê o container atual, que acabou de subir. Use --previous (ou -p) para o container que morreu. Se ainda assim estiver vazio, o processo morreu antes de escrever: típico de OOMKilled, de exit 127 (binário não encontrado) e de aplicações que só escrevem log depois de conectar ao banco.

Deletar o pod resolve?

O pod novo começa sem o back-off acumulado, então parece resolver por alguns segundos. Se a causa não mudou, o exit code volta. Vale a pena só quando a dependência externa já foi corrigida e você não quer esperar a próxima tentativa.

Exit code 137 é sempre OOMKilled?

Não. 137 é 128 + 9, ou seja, SIGKILL. O OOM killer do kernel usa SIGKILL, mas o kubelet também usa SIGKILL quando o container não encerra dentro do terminationGracePeriodSeconds (30 s por padrão). Confirme pelo Reason no describe pod: OOMKilled aparece explicitamente.

Como evitar o CrashLoopBackOff em deploys?

Requests e limits medidos, startupProbe para aplicações lentas na subida, retry com back-off para dependências e rollout com maxUnavailable 0. Acompanhe o primeiro pod novo antes de deixar o rollout continuar: kubectl rollout status mostra se ele ficou Ready.