El Comportamiento Esperado y el Error CrashLoopBackOff
Al implementar una aplicación en Kubernetes (K8s), el comportamiento esperado es que el Pod pase de Pending directamente a Running, y que los contenedores en su interior permanezcan activos. Sin embargo, uno de los errores más comunes y notorios que se encuentran es CrashLoopBackOff.
Este estado significa que un contenedor dentro del Pod se inicia, falla instantáneamente, y Kubernetes intenta reiniciarlo continuamente—con retrasos crecientes (backoffs) entre cada intento (10s, 20s, 40s, hasta 5 minutos).
A diferencia de un estado Pending (que implica un problema de infraestructura o programación), un CrashLoopBackOff te dice explícitamente que el nodo ha programado el Pod, extraído la imagen y ejecutado el contenedor, pero la aplicación en su interior salió voluntariamente o fue eliminada a la fuerza.
Requisitos Previos
Antes de sumergirte en los pasos de solución de problemas, asegúrate de tener:
- Un Cluster Kubernetes en ejecución (Minikube, EKS, GKE, AKS o bare metal).
- La herramienta de línea de comandos
kubectlinstalada y configurada para apuntar a tu cluster. - El nombre exacto del Pod que muestra el error y el espacio de nombres en el que reside.
Causa del Problema del CrashLoopBackOff
Dado que CrashLoopBackOff es un síntoma más que la causa exacta, debemos buscar la razón subyacente. Los culpables más comunes incluyen:
- Pánico de la Aplicación/Error Fatal: El código encuentra una excepción no controlada o falta una dependencia inmediatamente al iniciarse (por ejemplo, fallo al conectar a una base de datos) y sale explícitamente.
- Configuración/Secretos Faltantes: La aplicación espera una variable de entorno mapeada desde un
ConfigMapoSecretque no existe o tiene un error tipográfico. - Fallos del Liveness Probe: Tu
livenessProbefalla consecutivamente, causando que Kubernetes interprete que el contenedor no está saludable y lo mate repetidamente para reiniciarlo. - OOMKilled (Sin Memoria): El contenedor intenta asignar más memoria de la que le permite su
limits.memory, lo que provoca que el kernel de Linux termine el proceso. - Entrypoint/Comando Inválido: El comando especificado en el YAML o en el
CMD/ENTRYPOINTdel Dockerfile es sintácticamente incorrecto, carece de permisos o sale inmediatamente porque no es un proceso en primer plano.
Solución Paso a Paso
1. Ver la Descripción del Pod
El primer comando que debes ejecutar es describe. Esto te dará el Exit Code exacto del fallo.
kubectl describe pod <pod-name> -n <namespace>
Desplázate hacia abajo hasta la sección Containers y mira el bloque Last State:
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Fri, 27 Feb 2026 10:00:00 GMT
Finished: Fri, 27 Feb 2026 10:00:02 GMT
Códigos de Salida Comunes:
- Exit Code 1: Error general de la aplicación (mira los logs de tu código).
- Exit Code 2: Mal uso de los comandos integrados de la shell (revisa tu comando de Dockerfile).
- Exit Code 126: El comando invocado no se puede ejecutar (error de permisos).
- Exit Code 128: Argumento de salida no válido.
- Exit Code 137: OOMKilled (Out of Memory - el contenedor alcanzó su límite).
- Exit Code 255: Estado de salida fuera de rango (usualmente un fallo de inicialización fatal).
2. Revisar los Logs Anteriores
Dado que el contenedor está fallando y reiniciándose activamente, el comando normal kubectl logs podría devolver un resultado vacío si consultas justo cuando el contenedor se inicia de nuevo. En su lugar, usa la bandera --previous para obtener los logs del contenedor muerto justo antes de ser eliminado:
kubectl logs <pod-name> -n <namespace> --previous
Esto es muy efectivo para capturar los trazos de la pila, conexiones faltantes a bases de datos o errores “File Not Found” que causaron el pánico.
3. Comprobar OOMKilled
Si el Código de Salida es 137 o la salida de describe dice literalmente OOMKilled, la solución es aumentar los límites de memoria de tu contenedor.
Edita tu YAML de implementación para aumentar el límite de memoria:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi" # <-- Aumenta este valor
cpu: "500m"
Aplica los cambios usando kubectl apply -f deployment.yaml.
4. Sobrescribir el Entrypoint para la Depuración (Solución Alternativa)
Si la salida del registro es críptica o inexistente (por ejemplo, salida inmediata del script debido a permisos), una excelente manera de depurar con seguridad es sobrescribir el command con un proceso de suspensión en la terminal. Esto obliga al contenedor a mantenerse activo el tiempo suficiente para que puedas ingresar a él.
Modifica temporalmente tu manifiesto de Deployment:
containers:
- name: my-crashing-app
image: my-registry/my-app:v1
command: ["sleep", "3600"] # Obliga al pod a mantenerse vivo
Aplica el manifiesto. El Pod ahora pasará a Running y se quedará ahí. Entonces, ejecuta con seguridad (exec) para entrar en él:
kubectl exec -it <pod-name> -- /bin/sh
Una vez dentro, puedes ejecutar el script de tu aplicación manualmente (npm start, python app.py, etc.) y observar el error en tiempo real, inspeccionar archivos o verificar las variables de entorno.
Prevención
Para reducir la incidencia de CrashLoopBackOff en tus clusters de producción, implementa las siguientes mejores prácticas:
- Implementar Correctamente Pruebas de Preparación y Actividad (Liveness/Readiness Probes): Asegúrate de que tu
livenessProbele da a la aplicación suficienteinitialDelaySecondspara que arranque antes de empezar a hacerle ping. - Uso de Contenedores de Inicio (Init Containers): Si tu aplicación depende de una base de datos o un servicio externo que debe estar disponible, usa un
initContainerpara esperar a ese servicio antes de iniciar la aplicación principal, previniendo efectivamente el pánico. - Validar las Dependencias de Configuración: Garantiza que tu pipeline de CI/CD valide que los
ConfigMapsySecretsreferenciados en tus Deployments realmente existen antes de aplicar los manifiestos.
Resumen
CrashLoopBackOffindica que un contenedor arrancó pero se detuvo/murió repetidamente.- Usa
kubectl describe podpara localizar el Exide Code. - Usa
kubectl logs --previouspara leer el trazo de la pila de la última iteración fallada. - El código
137significa que se han alcanzado los límites de memoria (OOMKilled). - Sobrescribe el comando del deployment a
sleepsi necesitas acceder por consola vía SSH manualmente en el pod para depurar el sistema de archivos o temas de permiso.