Solución de problemas: Diagnóstico rápido de errores comunes en contenedores Docker
Los contenedores Docker están diseñados para ser resilientes, pero los fallos de inicio son una parte inevitable del ciclo de vida del desarrollo. Cuando un contenedor se detiene repentinamente, comprender la causa raíz rápidamente es primordial para mantener la velocidad de despliegue. Estos fallos a menudo son crípticos, marcados solo por un código de salida distinto de cero.
Esta guía proporciona metodologías expertas de solución de problemas utilizando el conjunto de comandos Docker esencial. Recorreremos un proceso de diagnóstico estructurado, aprovechando docker ps, docker logs y docker inspect para identificar y resolver rápidamente los problemas más frecuentes de inicio de contenedores, permitiéndole ir más allá de las conjeturas y aplicar correcciones accionables.
Fase 1: Triaje inicial y evaluación del estado
El primer paso para diagnosticar cualquier fallo de un contenedor es determinar su estado actual y reciente. El comando docker ps predeterminado solo muestra los contenedores en ejecución, lo cual no es útil cuando un contenedor se ha detenido inmediatamente al iniciarse.
Uso de docker ps -a para encontrar fallos
El comando crucial para el triaje inicial es docker ps -a (listar todos los contenedores, en ejecución o detenidos). Esto le permite ver el estado, el código de salida y la antigüedad del contenedor detenido.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d3f4b5c6e7a my-app:latest "/usr/bin/start.sh" 5 minutes ago Exited (127) 3 minutes ago web-service
d8c9a0b1c2d3 nginx:latest "nginx -g 'daemon..." 10 minutes ago Up 8 minutes 80/tcp active-proxy
Indicadores clave de estado:
- Exited (0): El contenedor se apagó correctamente y de forma intencionada (a menudo después de que un trabajo por lotes se completara). El diagnóstico suele ser mínimo.
- Exited (Non-Zero): Ocurrió un fallo. Los códigos comunes distintos de cero (1, 126, 127) indican problemas graves, como el bloqueo de un proceso, la no localización de un archivo o errores de permisos.
- Created: El contenedor se creó pero nunca se inició, o el inicio falló demasiado rápido para que se actualizara el estado.
Fase 2: Profundizando con los registros del contenedor
Una vez que tenga el ID o el nombre del contenedor, la herramienta más valiosa para el diagnóstico es el mecanismo de registro. Docker captura las transmisiones de salida estándar (stdout) y error estándar (stderr) del proceso principal del contenedor.
Recuperación de registros históricos
Utilice el comando docker logs para recuperar toda la salida capturada del contenedor con fallos. Esta salida a menudo contiene el mensaje de error preciso (por ejemplo, el rastreo de pila, el error de configuración o la advertencia de archivo faltante) que provocó la detención del contenedor.
# Recuperar registros del contenedor con fallos
$ docker logs web-service
# --- Ejemplo de salida de registro ---
Standardizing environment...
Error: Configuration file not found at /etc/app/config.json
Application initialization failed. Exiting.
Consejos avanzados de filtrado de registros:
| Opción de comando | Propósito | Ejemplo |
|---|---|---|
-f, --follow |
Transmitir registros en tiempo real (útil si el contenedor se inicia y se bloquea rápidamente). | docker logs -f web-service |
--tail N |
Mostrar solo las últimas N líneas de registros. | docker logs --tail 50 web-service |
-t, --timestamps |
Mostrar marcas de tiempo para cada entrada de registro (útil para correlacionar eventos). | docker logs -t web-service |
--since |
Mostrar registros generados después de un tiempo o duración específicos (por ejemplo, 1h, 15m). |
docker logs --since 15m web-service |
Mejor práctica: Siempre verifique los registros inmediatamente después de un fallo. Si los registros están vacíos, el fallo ocurrió antes de que el proceso principal de la aplicación pudiera iniciarse, lo que a menudo indica un problema con la propia configuración
ENTRYPOINToCMDde Docker.
Fase 3: Análisis del estado y la configuración con docker inspect
Cuando los registros son insuficientes (por ejemplo, muestran un error genérico o nada en absoluto), necesita analizar la configuración interna y el entorno de ejecución del contenedor.
Revisión del objeto de estado completo
docker inspect proporciona un objeto JSON completo que detalla todo sobre el contenedor, desde la configuración de red hasta los límites de recursos, y de manera crucial, el estado final y el mensaje de error.
$ docker inspect web-service
Concéntrese en las siguientes rutas JSON clave dentro de la salida:
1. Información de estado
Esta sección contiene la información detallada de salida, incluido el momento del fallo y cualquier mensaje de error a nivel del sistema (si corresponde).
...
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 127,
"Error": "", // A menudo vacío, pero puede contener mensajes a nivel del kernel
"StartedAt": "2023-10-26T14:30:00.123456789Z",
"FinishedAt": "2023-10-26T14:30:00.223456789Z"
},
...
2. Punto de entrada y comando
Si el contenedor salió con el código 127 (comando no encontrado) o 126 (comando no ejecutable), verifique la Path y Args en las secciones Config o State para asegurarse de que el proceso principal esté correctamente especificado y que la ruta exista dentro de la imagen.
...
"Config": {
"Entrypoint": [
"/usr/bin/start.sh"
],
"Cmd": [
"--mode=production"
],
...
3. Montajes y volúmenes
Si la aplicación falló debido a archivos faltantes o errores de permisos, verifique la sección Mounts para confirmar que los volúmenes del host se mapearon correctamente, sean accesibles y posean los permisos necesarios.
Fase 4: Escenarios comunes de fallos de inicio y resoluciones
Al combinar los registros y los datos de inspección, puede categorizar el fallo y aplicar una solución específica.
Escenario 1: Puerto ya asignado (Error de enlace)
Esto ocurre cuando el puerto del host que intenta mapear (-p 8080:80) ya está en uso por otro proceso (otro contenedor o un proceso que se ejecuta en la máquina host).
Diagnóstico: El contenedor a menudo falla al iniciarse inmediatamente, o los registros muestran un error como bind: address already in use.
Resolución:
1. Detenga el proceso o contenedor en conflicto.
2. Cambie el mapeo del puerto del host (por ejemplo, -p 8081:80).
Escenario 2: Comando no encontrado (Código de salida 127)
Esto significa que el tiempo de ejecución de Docker no pudo ejecutar el comando especificado en la directiva ENTRYPOINT o CMD.
Diagnóstico: Verifique docker logs (que podría estar vacío) y revise la sección Config usando docker inspect.
Resolución:
1. Asegúrese de que la ruta del ejecutable sea correcta (por ejemplo, /usr/local/bin/app, no solo app).
2. Verifique que el ejecutable exista en la imagen. Es posible que necesite ejecutar un contenedor de depuración temporal para examinar el sistema de archivos de la imagen:
# Ejecute temporalmente la imagen, anulando el comando fallido
$ docker run -it --entrypoint /bin/bash my-app:latest
# Ahora, dentro del contenedor, verifique: ls -l /usr/bin/start.sh
Escenario 3: Permiso denegado (Código de salida 126 o errores de volumen)
Generalmente ocurre cuando el usuario del contenedor carece de permiso para acceder a un archivo, directorio o punto de montaje de volumen requerido.
Diagnóstico: Los registros muestran errores como Permission denied o cannot open file.
Resolución:
1. Permisos de volumen: Si utiliza montajes de host (-v /host/data:/container/data), asegúrese de que la carpeta del host tenga permisos de lectura/escritura para el ID de usuario con el que se ejecuta el contenedor (a menudo UID 1000 o root).
2. Permisos del punto de entrada: Asegúrese de que el script especificado en ENTRYPOINT tenga el indicador de ejecución establecido dentro del Dockerfile (RUN chmod +x /path/to/script).
Escenario 4: Falta de memoria (OOMKilled)
Este es un fallo a nivel del sistema donde el kernel termina el proceso principal del contenedor debido a un consumo excesivo de memoria.
Diagnóstico: Verifique docker ps -a para ver STATUS Exited (137) o ejecute docker inspect [id] y busque el campo "OOMKilled": true en el objeto State.
Resolución:
1. Aumente el límite de memoria del contenedor usando el indicador -m (por ejemplo, --memory 2g).
2. Optimice la aplicación para reducir el uso de memoria.
Resumen y próximos pasos
La solución de problemas eficiente de Docker se basa en un enfoque estructurado: comience con docker ps -a para evaluar el fallo, utilice docker logs como su principal herramienta de investigación y reserve docker inspect para problemas de configuración y entorno más profundos. Al comprender el significado de los códigos de salida y saber dónde buscar dentro del estado del contenedor, puede reducir drásticamente el tiempo dedicado a resolver fallos de inicio comunes.
Acciones adicionales:
- Si el problema está relacionado con la imagen, reconstruya la imagen incluyendo pasos de depuración temporales (por ejemplo, imprimiendo variables de entorno) en el Dockerfile.
- Si los registros son escasos, cambie temporalmente la inicialización del contenedor para usar
bashoshpara navegar manualmente por el sistema de archivos y probar comandos dentro del entorno.