CrashLoopBackOff en Kubernetes: causas y soluciones
CrashLoopBackOff es uno de los errores mas frecuentes en Kubernetes. El pod arranca, falla, Kubernetes lo reinicia, vuelve a fallar… y entra en un bucle. En este post te explico todas las causas posibles y como diagnosticarlo y solucionarlo paso a paso. Si acabas de empezar con Kubernetes, te recomiendo leer primero el post de Kubernetes para principiantes.
Que significa CrashLoopBackOff en Kubernetes
CrashLoopBackOff no es un error en si mismo — es el estado que muestra Kubernetes cuando un contenedor falla repetidamente al arrancar. El sufijo «BackOff» indica que Kubernetes va aumentando el tiempo de espera entre reinicios (10s, 20s, 40s… hasta 5 minutos) para no saturar el sistema.
# Ver el estado de los pods
kubectl get pods
# Salida tipica:
# NAME READY STATUS RESTARTS AGE
# mi-app-xyz 0/1 CrashLoopBackOff 5 3m
Paso 1: Lo primero siempre es ver los logs
Igual que con Systemd, el log es tu mejor amigo. El contenedor crash justo al arrancar, pero los logs del intento anterior siguen disponibles:
# Ver logs del contenedor (intento actual)
kubectl logs mi-app-xyz
# Ver logs del intento ANTERIOR (el que crasheo)
kubectl logs mi-app-xyz --previous
# Ver logs en tiempo real mientras el pod intenta arrancar
kubectl logs mi-app-xyz -f
# Ver los ultimos 50 logs
kubectl logs mi-app-xyz --tail=50
Paso 2: Describir el pod para mas contexto
kubectl describe pod mi-app-xyz
Busca en la seccion «Events» al final del output — ahi suele estar la causa real. Lineas como estas son muy informativas:
# Ejemplos de eventos tipicos:
Back-off restarting failed container
Error: failed to create containerd task: ... no such file or directory
OOMKilled: container exceeded memory limit
Liveness probe failed: ...
Error: secret "mi-secreto" not found
Causas mas comunes de CrashLoopBackOff
Causa 1: Error en la aplicacion al arrancar
La causa mas frecuente. La aplicacion falla al inicializarse por un error de codigo, configuracion o dependencia.
# Ver el error en los logs
kubectl logs mi-app-xyz --previous
# Ejemplos tipicos:
# Error: Cannot connect to database
# SyntaxError: Unexpected token in config.json
# FATAL: required env variable APP_SECRET not set
La solucion depende del error especifico. Lo mas habitual es que falte una variable de entorno o una conexion a base de datos.
Causa 2: Variables de entorno o secrets que faltan
# Verificar variables de entorno del pod
kubectl exec mi-app-xyz -- env
# Verificar que el secret existe
kubectl get secret mi-secreto
# Verificar que el configmap existe
kubectl get configmap mi-config
# Ver el contenido del configmap
kubectl describe configmap mi-config
Causa 3: OOMKilled — el contenedor se queda sin memoria
Kubernetes mata el contenedor cuando supera el limite de memoria definido en el deployment. Aparece como «OOMKilled» en el describe.
# Verificar si fue OOMKilled
kubectl describe pod mi-app-xyz | grep -A5 "Last State"
# Salida:
# Last State: Terminated
# Reason: OOMKilled
# Exit Code: 137
# Solucion: aumentar el limite de memoria en el deployment
resources:
requests:
memory: "128Mi"
limits:
memory: "512Mi" # aumentar este valor
Causa 4: Imagen incorrecta o que no existe
# Error tipico en el describe:
# Failed to pull image "mi-app:latest": ... not found
# Verificar la imagen del deployment
kubectl get deployment mi-app -o yaml | grep image
# Soluciones:
# 1. Corregir el nombre o tag de la imagen
# 2. Crear el imagePullSecret si es un registry privado
kubectl create secret docker-registry mi-registry-secret --docker-server=registry.ejemplo.com --docker-username=user --docker-password=password
Causa 5: Liveness probe mal configurada
Si la liveness probe falla antes de que la aplicacion este lista, Kubernetes reinicia el pod continuamente.
# Error tipico:
# Liveness probe failed: HTTP probe failed with statuscode: 500
# Solucion: aumentar initialDelaySeconds para dar tiempo a la app
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30 # dar 30s para que arranque
periodSeconds: 10
failureThreshold: 3
Causa 6: El comando del contenedor termina inmediatamente
Si el proceso principal del contenedor termina, Kubernetes lo reinicia. Tipico en scripts que se ejecutan y terminan, o en contenedores con un CMD incorrecto.
# Error: el contenedor vive 0-2 segundos y muere
# Verificar el comando del contenedor
kubectl get pod mi-app-xyz -o yaml | grep -A5 command
# Depurar ejecutando el contenedor con un comando que no termine
kubectl run debug-pod --image=mi-app:latest --command -- sleep 3600
# Luego conectarse y ejecutar el comando manualmente
kubectl exec -it debug-pod -- bash
Workflow de diagnostico para CrashLoopBackOff
kubectl logs mi-pod --previous— ver el error del ultimo crashkubectl describe pod mi-pod— ver eventos y estado del contenedor- Buscar «OOMKilled», «Error», «Liveness probe failed» en el output
- Verificar variables de entorno y secrets:
kubectl get secret - Si la imagen falla:
kubectl describe poden la seccion «Events» - Si no ves el error: ejecuta el contenedor con
sleep 3600y depura desde dentro
Conclusion
CrashLoopBackOff siempre tiene una causa concreta. El 90% de los casos se resuelven con los dos primeros pasos: kubectl logs --previous y kubectl describe pod. El log siempre te dice que ha pasado, solo hay que saber leerlo.
En el proximo post veremos Pods, Deployments y Services en detalle. Tienes algun CrashLoopBackOff que no hayas podido resolver? Dejalo en los comentarios.
