Cuando el daemon de Docker no arranca, tu host se convierte en una pieza de museo: contenedores congelados en el tiempo, jobs de CI atascados, despliegues que revierten y alguien preguntando si «podemos simplemente reiniciarlo otra vez». Puedes reiniciar, claro. También puedes meter un portátil mojado en el microondas. Ninguno de los dos es una estrategia.
El camino más rápido no es una secuencia aleatoria de reinicios. Es una lectura limpia del registro correcto, seguida de un pequeño número de comandos deliberados que te dicen qué falló: configuración, almacenamiento, características del kernel, reglas de red, permisos o containerd.
Guía de diagnóstico rápido (qué comprobar primero)
Si solo tienes cinco minutos y un pager vibrando en las muelas, haz esto en orden. El objetivo es identificar rápidamente la clase de bloqueo: fallo de parseo de configuración, dependencia de runtime fallida, corrupción/capacidad de almacenamiento, incompatibilidad de características del kernel o fallo de reglas de red.
Primero: systemd dice por qué se negó a mantener Docker vivo
Docker suele gestionarse con systemd. systemd tiene la primera opinión que importa: código de salida y stderr inmediato.
cr0x@server:~$ systemctl status docker --no-pager -l
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 17s ago
Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
Main PID: 1842 (code=exited, status=1/FAILURE)
CPU: 230ms
Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument
Jan 02 10:12:54 server systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Jan 02 10:12:54 server systemd[1]: docker.service: Failed with result 'exit-code'.
Jan 02 10:12:54 server systemd[1]: Failed to start Docker Application Container Engine.
Decisión: Toma en serio la primera línea failed to start daemon:. Casi siempre indica la clase de causa raíz. Aquí grita «overlay2 mount invalid argument» → incompatibilidad kernel/sistema de archivos/overlayfs, no un «bug de Docker».
Segundo: journalctl para Docker da la pila completa, no solo el titular
cr0x@server:~$ journalctl -u docker -b --no-pager -n 200
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152001115Z" level=error msg="failed to mount overlay: invalid argument" storage-driver=overlay2
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument"
Decisión: Si ves level=fatal seguido de un subsistema concreto (graphdriver, iptables, daemon.json), deja de adivinar. Pivota a las comprobaciones de ese subsistema.
Tercero: comprueba la capacidad y el sistema de archivos bajo /var/lib/docker
Un disco lleno o la escasez de inodos no siempre se anuncian con cortesía. Simplemente hacen que los daemons se comporten como si hubieran olvidado escribir.
cr0x@server:~$ df -h /var/lib/docker
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p4 80G 79G 300M 100% /
cr0x@server:~$ df -i /var/lib/docker
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p4 5.0M 5.0M 0 100% /
Decisión: Si los bloques o inodos están al 100%, tu «Docker no arranca» es un incidente de almacenamiento. Libera espacio primero; no cambies drivers, no reinstales paquetes ni «restablezcas Docker» hasta que el host pueda escribir.
Cuarto: valida la configuración del daemon antes de perseguir fantasmas
Una coma final en JSON puede tumbar toda tu plataforma de contenedores. Ojalá fuera una broma. (No lo es.)
cr0x@server:~$ sudo cat /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", },
"iptables": true
}
Decisión: Esa coma después de "10m" evitará que dockerd arranque. Corrige el JSON y luego reinicia. No toques nada más.
Quinto: verifica que containerd esté vivo (o confirma que no lo esté)
cr0x@server:~$ systemctl status containerd --no-pager -l
● containerd.service - containerd container runtime
Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago
Docs: man:containerd(8)
Main PID: 1210 (containerd)
Decisión: Si containerd está abajo, Docker puede fallar con un error de socket o runtime. Arregla containerd primero. Si containerd está sano, sigue adelante.
El único registro que leer primero (y por qué)
Lee el journal de systemd para la unidad docker antes de leer cualquier otra cosa. No porque sea elegante. Porque es autoritativo. Captura:
- Por qué systemd dejó de reiniciar el servicio (límites de inicio, bucles de fallos).
- Exactamente lo que
dockerdimprimió en stderr/stdout. - El tiempo relativo a otros servicios (containerd, red, montajes).
En la mayoría de distros modernas, este es el comando clave:
cr0x@server:~$ journalctl -u docker -b --no-pager -o cat
time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: failed to load listeners: can't create unix socket /var/run/docker.sock: permission denied"
Decisión: Ese error no es un problema de «Docker no puede hablar con Docker». Es un problema de permisos/propiedad/SELinux/AppArmor en la ruta del socket (o su padre). Ahora sabes la clase de fallo en la que estás.
No empieces con /var/log/docker.log a menos que estés en un sistema que registre explícitamente allí. Muchas instalaciones no lo hacen. No empieces con soluciones aleatorias de Stack Overflow. Tu sistema ya te dijo qué está mal; simplemente no lo has escuchado aún.
Hechos e historia interesantes (para entender los errores)
- Docker originalmente usó LXC (Linux Containers) para aislamiento antes de pasar a libcontainer, lo que cambió cómo se consumen las características de bajo nivel del kernel.
- containerd se separó de Docker para que el runtime central pudiera evolucionar independientemente; por eso «Docker está caído» puede significar en realidad «containerd está caído».
- overlay2 se convirtió en el driver por defecto en muchas distros porque es rápido y eficiente en espacio, pero es exigente con las características del sistema de archivos (especialmente en kernels antiguos).
- La integración con iptables no es opcional para la red clásica de Docker; cuando firewalld/nftables/iptables entran en conflicto, Docker puede fallar al arrancar, no solo al ejecutar contenedores.
- La adopción de cgroups v2 cambió la canalización de control de recursos; versiones antiguas de Docker en distros nuevas pueden fallar temprano por incompatibilidades con el controlador de cgroups.
- Los valores por defecto de logging de Docker (json-file) pueden llenar discos silenciosamente; que el daemon falle al arrancar tras un evento de disco lleno es a menudo crecimiento de logs autoinfligido.
- El comportamiento de start-limit es una característica de systemd: tras fallos repetidos, deja de intentar. Los operadores a menudo interpretan esto como «Docker se congeló».
- /var/lib/docker no es sagrado; es solo estado. Contiene imágenes, capas, metadatos y volúmenes (según configuración). Se puede migrar, pero hacerlo a la ligera es como ganarse trabajo el fin de semana.
- Existe Rootless Docker para reducir privilegios del daemon, pero añade una clase separada de fallos alrededor de servicios de usuario, XDG_RUNTIME_DIR y delegación de cgroups.
Tareas prácticas: comandos, salidas y la decisión que tomas
No arreglas Docker repitiendo «restart». Arreglas Docker recopilando un pequeño conjunto de hechos y tomando una decisión después de cada uno. Abajo están tareas que he usado en incidentes reales, con salidas realistas y lo que significan.
Tarea 1: Confirma el estado de la unidad y la última razón de fallo
cr0x@server:~$ systemctl is-enabled docker; systemctl is-active docker; systemctl status docker --no-pager -l
enabled
failed
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 2min 11s ago
Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: Error initializing network controller: failed to create NAT chain DOCKER: iptables failed
Decisión: Si el fallo apunta al network controller / iptables, no pierdas tiempo en comprobaciones de almacenamiento primero. Ve a la sección de iptables/nftables.
Tarea 2: Extrae los registros completos del arranque para docker
cr0x@server:~$ journalctl -u docker -b --no-pager -n 300
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="libcontainerd: started new containerd process" pid=1901
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="iptables failed: iptables -t nat -N DOCKER: iptables v1.8.7 (nf_tables): Chain already exists."
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Error initializing network controller: iptables failed"
Decisión: «Chain already exists» sugiere reglas obsoletas de una ejecución anterior o un conflicto con el backend nftables. Estás en el modo de fallo de reglas de red.
Tarea 3: Comprueba si systemd te está limitando por inicio
cr0x@server:~$ systemctl status docker --no-pager -l | sed -n '1,25p'
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: start-limit-hit) since Tue 2026-01-02 10:13:09 UTC; 18s ago
Jan 02 10:13:09 server systemd[1]: docker.service: Start request repeated too quickly.
Jan 02 10:13:09 server systemd[1]: docker.service: Failed with result 'start-limit-hit'.
Decisión: Limpia el start-limit después de arreglar el problema subyacente; de lo contrario «lo arreglas» y seguirá siendo rechazado.
cr0x@server:~$ sudo systemctl reset-failed docker
Tarea 4: Valida /etc/docker/daemon.json sin fiarte de tus ojos
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
Expecting property name enclosed in double quotes: line 3 column 36 (char 61)
Decisión: Corrige la sintaxis JSON primero. Si esto falla, Docker no arrancará. Punto. Tras corregir el fichero, vuelve a ejecutar el validador hasta que imprima JSON formateado y salga 0.
Tarea 5: Extrae la línea de comandos efectiva de Docker (los drop-in importan)
cr0x@server:~$ systemctl cat docker --no-pager
# /lib/systemd/system/docker.service
[Service]
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --data-root /mnt/docker-data --storage-driver=overlay2
Decisión: Si ves overrides, trátalos como sospechosos hasta demostrar lo contrario. Muchos incidentes de «Docker rompió tras una actualización» son en realidad «override antiguo se encuentra con nuevos valores por defecto».
Tarea 6: Comprueba el montaje de data-root de Docker y el tipo de sistema de archivos
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /var/lib/docker
/dev/nvme0n1p4 ext4 rw,relatime
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /mnt/docker-data
/dev/sdb1 xfs rw,relatime,attr2,inode64,logbufs=8,logbsize=32k
Decisión: Overlay2 sobre XFS generalmente requiere ftype=1. Si migraste datos de Docker a un XFS formateado con ftype=0, overlay2 fallará.
Tarea 7: Verifica ftype de XFS (crítico para overlay2 en XFS)
cr0x@server:~$ sudo xfs_info /dev/sdb1 | grep ftype
naming =version 2 bsize=4096 ascii-ci=0, ftype=0
Decisión: ftype=0 es un paro obligatorio para overlay2. Tu solución es reformatar con ftype=1 (requiere migración de datos) o cambiar el driver de almacenamiento (generalmente un mal día). No sigas reintentando.
Tarea 8: Comprueba soporte del kernel para overlayfs (y detecta causas de «invalid argument»)
cr0x@server:~$ uname -r
4.15.0-213-generic
cr0x@server:~$ lsmod | grep overlay
overlay 102400 0
cr0x@server:~$ sudo dmesg -T | tail -n 20
[Mon Jan 2 10:12:54 2026] overlayfs: filesystem on '/var/lib/docker/overlay2' not supported as upperdir
Decisión: Esa línea en dmesg te dice que el kernel rechazó el sistema de archivos subyacente como upperdir de overlay (común con ciertos sistemas de archivos en red, rutas mal montadas o opciones no soportadas). Arregla el montaje/elección del sistema de archivos; Docker no lo arreglará por ti.
Tarea 9: Confirma el socket y la salud de containerd
cr0x@server:~$ ls -l /run/containerd/containerd.sock
srw-rw---- 1 root root 0 Jan 2 10:08 /run/containerd/containerd.sock
cr0x@server:~$ systemctl status containerd --no-pager -l | sed -n '1,15p'
● containerd.service - containerd container runtime
Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago
Decisión: Si falta el socket o containerd falla, arregla containerd antes de Docker. Si containerd está bien, el error de Docker está en otro lado.
Tarea 10: Busca denegaciones obvias de permisos (SELinux/AppArmor aparecen aquí)
cr0x@server:~$ sudo journalctl -b --no-pager | grep -E 'DENIED|apparmor="DENIED"|avc:'
Jan 02 10:12:54 server kernel: audit: type=1400 apparmor="DENIED" operation="create" profile="docker-default" name="/var/run/docker.sock" pid=1842 comm="dockerd"
Decisión: Si ves negaciones explícitas, deja de tratarlo como un problema de configuración de Docker. Arregla la política/perfil o el contexto del archivo. Iniciar Docker con «simplemente desactivar seguridad» es como saltarse las alarmas de humo porque quemaste el pan.
Tarea 11: Inspecciona incompatibilidad del backend de iptables (iptables vs nft)
cr0x@server:~$ sudo iptables --version
iptables v1.8.7 (nf_tables)
cr0x@server:~$ sudo iptables -t nat -S | sed -n '1,25p'
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
Decisión: Si Docker se queja de cadenas existentes, puede que tengas gestores de reglas en conflicto (firewalld, kube-proxy, scripts personalizados). Decide quién posee las reglas. En caso de apuro, vacía solo las cadenas gestionadas por Docker con cuidado—tras entender el radio de impacto.
Tarea 12: Confirma modo de cgroup y desajuste de driver
cr0x@server:~$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
cr0x@server:~$ journalctl -u docker -b --no-pager | grep -i cgroup | tail -n 5
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Devices cgroup isn't mounted"
Decisión: Esto suele indicar una build antigua de Docker o configuración errónea para cgroups v2. La solución es alinear versiones (actualizar Docker) o configurar el driver/modo de cgroups correcto para tu distro. No lo soluciones desactivando el control de recursos a menos que te guste la ruleta de rendimiento.
Tarea 13: Busca corrupción o escrituras parciales tras cortes de energía
cr0x@server:~$ journalctl -u docker -b --no-pager | tail -n 20
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="failed to load container metadata" error="unexpected end of JSON input"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: error while opening volume store metadata database"
Decisión: La corrupción de metadatos es real. Ahora decides: recuperar desde backup, eliminar quirúrgicamente el objeto corrupto o reconstruir el estado de Docker. Tu elección depende de si puedes perder imágenes/volúmenes locales.
Tarea 14: Ejecuta dockerd en modo dry-run directamente (útil cuando systemd oculta stderr)
cr0x@server:~$ sudo dockerd --debug --validate --config-file=/etc/docker/daemon.json
unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: hosts
Decisión: Tienes fuentes de configuración en conflicto (flags de systemd ExecStart vs daemon.json). Elimina una fuente de verdad. En producción prefiero dejar hosts a systemd y usar daemon.json para ajustes del daemon, no para listeners.
Tarea 15: Comprueba conflictos de puerto (común con flags antiguos de dockerd)
cr0x@server:~$ sudo ss -ltnp | grep -E ':2375|:2376' || true
LISTEN 0 4096 0.0.0.0:2375 0.0.0.0:* users:(("dockerd",pid=902,fd=7))
Decisión: Si un proceso dockerd antiguo sigue ligado (o otro servicio), tu nuevo daemon no puede enlazar. Mata el proceso sobrante limpiamente y luego arregla la unidad para no lanzar múltiples daemons.
Tarea 16: Libera espacio de forma segura sin destruirlo todo
cr0x@server:~$ sudo du -sh /var/lib/docker/* 2>/dev/null | sort -h | tail -n 10
2.1G /var/lib/docker/containers
12G /var/lib/docker/overlay2
18G /var/lib/docker/volumes
cr0x@server:~$ sudo find /var/lib/docker/containers -name '*-json.log' -size +200M -printf '%p %s\n' | head
/var/lib/docker/containers/2f3.../2f3...-json.log 987654321
Decisión: Si los logs de contenedores son los culpables, trunca logs en lugar de borrar directorios de contenedores.
cr0x@server:~$ sudo truncate -s 0 /var/lib/docker/containers/2f3.../2f3...-json.log
Decisión: Haz que el daemon arranque primero y luego implementa rotación de logs correctamente. Disco lleno es un outage; la higiene perfecta puede esperar una hora.
Los grandes modos de fallo (cómo se ven en los registros)
Las fallas de arranque del daemon de Docker se agrupan en unos pocos buckets. Reconoce el bucket y habrás reducido el incidente a la mitad.
1) Parseo de configuración y conflictos de configuración
Líneas típicas en registros:
unable to configure the Docker daemon with file ...: invalid characterdirectives are specified both as a flag and in the configuration fileunknown log optdespués de un cambio de versión
Qué está pasando realmente: Docker es estricto con la sintaxis JSON y con ajustes duplicados. Las flags de systemd también son «ajustes».
Filosofía de la solución: Una sola fuente de verdad. Mantén daemon.json minimalista; pon listeners (-H) en systemd o viceversa, pero no los dividas entre ambos.
2) Fallos del driver de almacenamiento (overlay2, devicemapper, btrfs, zfs)
Líneas típicas en registros:
error initializing graphdriveroverlay2: failed to mountfailed to register layer
Qué está pasando realmente: El kernel y el sistema de archivos negocian características. Si discrepan, overlayfs devuelve «invalid argument» y Docker lo traduce en desesperación.
Filosofía de la solución: Confirma tipo/opciones del sistema de archivos y soporte del kernel. No cambies el driver de almacenamiento en medio del incidente a menos que estés preparado para perder imágenes locales y potencialmente volúmenes.
3) Capacidad y salud del sistema de archivos
Líneas típicas en registros:
no space left on deviceread-only file systemtras un error de I/Odatabase is lockedo lecturas parciales de metadatos tras un apagado abrupto
Qué está pasando realmente: Docker es dependiente del estado. Si el almacenamiento del host no puede escribir de forma fiable, el arranque es la primera víctima.
Filosofía de la solución: Restaura la capacidad de escritura (espacio, fsck, remount, arreglar disco subyacente). Solo entonces considera remediaciones específicas de Docker.
4) Rotura de dependencias containerd/runtime
Líneas típicas en registros:
failed to dial "/run/containerd/containerd.sock"containerd: connect: no such file or directory
Qué está pasando realmente: Docker delega responsabilidades de runtime. Si falta containerd, es incompatible o no está en ejecución, Docker no puede continuar.
Filosofía de la solución: Trata a containerd como un servicio prerequisito. Alinea versiones vía tu gestor de paquetes y mantén la unidad saludable.
5) Fallos de inicialización de red (iptables/nftables/firewalld)
Líneas típicas en registros:
failed to create NAT chain DOCKERiptables: No chain/target/match by that nameChain already existscon backend nf_tables
Qué está pasando realmente: Docker intenta programar reglas NAT y filter. Si otro actor gestiona esas tablas de forma distinta (o el backend de iptables cambió), Docker no puede crear lo que espera.
Filosofía de la solución: Decide la propiedad de las reglas. Si debes intervenir, hazlo de forma quirúrgica y documentada. Los flushs aleatorios son cómo te quedas sin SSH en tu propio host.
6) Permisos, LSMs y creación de sockets
Líneas típicas en registros:
can't create unix socket /var/run/docker.sock: permission deniedapparmor="DENIED"o denegaciones AVC de SELinux
Qué está pasando realmente: Docker necesita crear un socket privilegiado y namespaces de montaje. Los módulos de seguridad y permisos del sistema de archivos pueden detenerlo en seco.
Filosofía de la solución: Lee la denegación. Arregla la política/contexto/propiedad. Deshabilitar SELinux «por Docker» es como quitar detectores de humo porque quemaste la cena.
Una cita, porque sigue siendo trabajo: «La esperanza no es una estrategia.»
— Gene Kranz
Errores comunes: síntoma → causa raíz → solución
Estos aparecen constantemente porque son fáciles de crear y molestos de diagnosticar bajo presión.
1) Docker atascado en start-limit-hit
Síntoma: systemctl muestra start-limit-hit y se niega a nuevos inicios.
Causa raíz: Docker se estrelló repetidamente; systemd dejó de reintentar.
Solución: Arregla el error subyacente primero, luego:
cr0x@server:~$ sudo systemctl reset-failed docker
cr0x@server:~$ sudo systemctl start docker
2) «invalid character» o errores JSON al arrancar
Síntoma: Docker falla al instante tras un ajuste de configuración.
Causa raíz: JSON inválido, comentarios en JSON, comas finales o tipos incorrectos.
Solución: Valida el fichero y corrige:
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
3) overlay2 «failed to mount» / «invalid argument»
Síntoma: graphdriver init falla, errores de montaje de overlay2.
Causa raíz: Sistema de archivos no soportado para upperdir (común con NFS), XFS ftype=0 o incompatibilidad kernel/sistema de archivos.
Solución: Sitúa data-root de Docker en un sistema de archivos local soportado (ext4, XFS con ftype=1). Verifica con xfs_info y dmesg. Migra estado si es necesario.
4) errores de cadenas iptables tras cambios en el firewall
Síntoma: Docker falla con errores al crear cadenas NAT.
Causa raíz: Gestores de firewall en conflicto o cambio de backend de iptables (legacy vs nf_tables).
Solución: Alinea las herramientas de iptables y la propiedad de reglas. En entornos controlados, fija un backend consistente y haz coexistir firewalld/kube/Docker intencionalmente.
5) «permission denied» en /var/run/docker.sock
Síntoma: Docker no puede crear su socket.
Causa raíz: Permisos incorrectos en subrutas de /var/run, socket obsoleto con propietario erróneo o denegación de LSM.
Solución: Elimina el socket obsoleto (si Docker está parado), corrige la propiedad y atiende denegaciones AppArmor/SELinux. No hagas chmod 777 por desesperación.
6) Docker falla tras mover data-root a «almacenamiento rápido»
Síntoma: Docker funcionaba; tras mover --data-root muere al arrancar.
Causa raíz: El nuevo montaje es un sistema de archivos en red o está formateado sin características requeridas.
Solución: Reevalúa el almacenamiento. La ruta caliente de Docker quiere disco local de baja latencia. Si debes usar almacenamiento en red, úsalo para volúmenes, no para capas overlay.
7) Disco lleno y Docker no arranca después de intentos de limpieza
Síntoma: Borraste «algo», Docker sigue sin arrancar y ahora los metadatos parecen corruptos.
Causa raíz: Borrar archivos aleatorios bajo /var/lib/docker rompe la consistencia de metadatos.
Solución: Para el daemon. Restaura desde backup si está disponible. Si no, acepta que una reconstrucción (wipe de data-root) puede ser más segura que una reparación parcial artesanal.
8) errores de cgroup en distros más nuevas
Síntoma: Errores sobre devices cgroup no montado, o desajuste de driver de cgroup.
Causa raíz: Versión de Docker no compatible con los defaults de cgroups v2, o driver de cgroup mal configurado.
Solución: Actualiza Docker a una versión que soporte el modo de cgroup de tu distro y mantén la configuración consistente en la flota.
Broma #1: Si tu «solución» es reiniciar Docker hasta que funcione, básicamente estás jugando a una máquina tragamonedas con privilegios de root.
Tres mini-historias del mundo corporativo reales
Mini-historia 1: El outage causado por una suposición equivocada
El equipo tenía un plan limpio: mover data-root de Docker fuera del disco OS hacia un montaje compartido más grande. El equipo de almacenamiento compartido prometió que era «como un disco». Estaba montado vía NFS, pero nadie dijo NFS explícitamente en la solicitud de cambio. Todos asumieron «almacenamiento es almacenamiento».
La migración ocurrió en una ventana tranquila. Rsyncaron /var/lib/docker a /mnt/docker-data, añadieron un override de systemd con --data-root y reiniciaron. Docker no volvió. systemd dijo «failed to start daemon: failed to mount overlay.» El on-call pasó 40 minutos persiguiendo docs de overlay2 y módulos del kernel.
El descubrimiento vino de dmesg, no de los logs de Docker: overlayfs rechazó el upperdir porque el sistema de archivos no era soportado. NFS era válido para almacenamiento masivo. No era válido para las capas union de Docker. La suposición equivocada no fue «overlay2 es inestable». Fue asumir que «NFS se comporta como ext4».
Hicieron rollback a XFS local con las características correctas y mantuvieron NFS solo para volúmenes de aplicaciones, con límites claros. El outage terminó. El postmortem terminó con una nueva regla: los tipos de almacenamiento deben nombrarse explícitamente en las solicitudes de cambio. «Montaje compartido» no es un tipo.
Mini-historia 2: La optimización que salió mal
Un ingeniero preocupado por el rendimiento quiso acelerar el arranque de contenedores. Vio la churn en el directorio overlay2 y decidió tunear montajes y reducir la amplificación de escritura. La «optimización» incluyó mover Docker a un sistema de archivos con opciones agresivas y desactivar algunas características de metadatos que pensó eran overhead.
Rendía bien en un entorno de dev con unos pocos contenedores. Luego llegó a producción: cientos de contenedores, pulls frecuentes de imágenes, muchas operaciones de archivos pequeños. En días, el nodo empezó a lanzar errores I/O intermitentes. Tras un reinicio brusco, Docker no arrancó. Los logs mostraban fallos de registro de capas y errores en la base de datos de metadatos.
Lo ocurrido no fue misterioso. La optimización redujo márgenes de seguridad: el sistema ahora era más sensible a pérdida de energía y a casos límite del sistema de archivos. El coste de unos pocos puntos de rendimiento fue una mayor probabilidad de corrupción y un camino de recuperación más duro.
Revirtieron los tweaks de montaje, reconstruyeron el nodo y adoptaron una regla aburrida: si cambias el sustrato de almacenamiento de Docker, lo haces con una matriz de compatibilidad documentada y plan de rollback. Las ganancias de rendimiento son reales, pero «rápido y frágil» es un mal trade en producción.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Otra organización tenía un hábito del que nadie se jactaba: recopilaban logs de arranque para servicios críticos y los enviaban a un lugar central. No solo logs de aplicación—también registros de unidades systemd y mensajes del kernel. Era aburrido. También funcionó.
Una mañana, un subconjunto de nodos dejó de iniciar Docker tras una actualización rutinaria del OS. La intuición humana inicial fue «regresión de Docker». Pero la línea de tiempo en los logs mostró algo más claro: Docker falló justo después de un reload del firewall en el arranque. El backend de iptables había cambiado y el gestor de firewall empezó a pre-crear cadenas de una forma que a Docker no le gustó.
Como tenían los logs, no discutieron durante horas. Identificaron el punto de cambio, lo reproducieron en un canary y desplegaron una configuración consistente del backend de iptables. Docker volvió sin tocar almacenamiento, imágenes ni cargas de trabajo de contenedores.
Esa práctica no evitó la falla. Evitó el outage prolongado. En producción, el tiempo para entender es la mitad del incidente.
Listas de verificación / plan paso a paso
Checklist A: Hacer que Docker vuelva a arrancar (pasos mínimos seguros)
- Deja de hacer thrash. Si el servicio está en crash-loop, páralo mientras investigas.
cr0x@server:~$ sudo systemctl stop docker - Lee el journal una vez, correctamente.
cr0x@server:~$ journalctl -u docker -b --no-pager -n 200Decisión: Identifica el bucket: config, storage, capacity, networking, permissions, dependency.
- Comprueba disco e inodos en el filesystem de data-root.
cr0x@server:~$ df -h /var/lib/docker; df -i /var/lib/dockerDecisión: Si está lleno, libera espacio sin borrar estado aleatorio. Trunca logs; elimina artefactos grandes conocidos con cuidado.
- Valida daemon.json si existe.
cr0x@server:~$ test -f /etc/docker/daemon.json && sudo python3 -m json.tool /etc/docker/daemon.jsonDecisión: Corrige errores de parseo; elimina duplicados con flags de systemd.
- Confirma que containerd está sano.
cr0x@server:~$ systemctl status containerd --no-pager -lDecisión: Arregla containerd primero si hace falta.
- Limpia límites de start de systemd después de la corrección.
cr0x@server:~$ sudo systemctl reset-failed docker - Inicia Docker y observa logs en vivo 30 segundos.
cr0x@server:~$ sudo systemctl start docker cr0x@server:~$ journalctl -u docker -f --no-pagerDecisión: Si falla otra vez, ahora capturas el punto de transición exacto sin arqueología de scroll.
Checklist B: Si se sospecha corrupción de almacenamiento (actúa con cuidado)
- Haz snapshot o copia de evidencia primero (si puedes). Al menos, captura logs y el desglose actual de tamaños en
/var/lib/docker. - No borres directorios aleatorios bajo
/var/lib/dockermientras dockerd esté en ejecución. Para el daemon. - Identifica si los volúmenes importan en este host. Algunos entornos guardan datos persistentes en volúmenes Docker; otros no. Tu plan de recuperación depende de eso.
- Prefiere reconstruir el nodo sobre reparaciones artesanales cuando el host sea cattle. Prefiere recuperación cuidadosa si el host es, desgraciadamente, un pet.
Checklist C: Si se sospecha iptables/red
- Confirma que el error de Docker menciona iptables/nftables.
- Comprueba backend de iptables y cadenas actuales.
- Identifica el otro gestor de reglas (firewalld, kube-proxy, scripts personalizados).
- Haz explícita la propiedad de reglas y luego reinicia Docker.
Broma #2: La red de Docker es fácil hasta que no lo es, momento en el que se convierte en una danza interpretativa ejecutada por iptables.
Preguntas frecuentes
1) ¿Debo ejecutar dockerd manualmente para depurar?
Sí, brevemente, si systemd está ocultando stderr o sospechas de conflictos de configuración. Usa --debug y para la unidad de systemd antes de evitar dos daemons peleando por el mismo socket.
2) ¿Es seguro borrar /var/lib/docker para «arreglarlo»?
Es seguro solo si estás borrando intencionalmente imágenes locales, contenedores y posiblemente volúmenes (según tu configuración). Es el último recurso para recuperación rápida en nodos sin estado, no una solución por defecto.
3) Docker dice overlay2 falló al montar. ¿Docker está roto?
Normalmente no. Suele ser una incompatibilidad kernel/sistema de archivos (XFS ftype, upperdir no soportado, opciones de montaje). Revisa dmesg para la queja real del kernel.
4) ¿Por qué Docker falla en el arranque por iptables? ¿No puede simplemente funcionar sin NAT?
La red bridge clásica de Docker depende de reglas de iptables. Si Docker no puede programar reglas NAT/filter, se niega a iniciar la red correctamente y puede fallar el daemon para evitar un comportamiento parcialmente operativo.
5) Cambié daemon.json y ahora Docker no arranca. ¿Cuál es la comprobación de cordura más rápida?
Valida JSON con un parser real:
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
Si da error, corrige la sintaxis. Si tiene éxito, busca conflictos de directivas con flags de systemd.
6) Docker no arranca tras una actualización del SO. ¿Cuál es el culpable probable?
Culpables comunes: cambios en defaults de cgroups v2, switches del backend de iptables y overrides antiguos en drop-ins de systemd. Empieza con systemctl cat docker y el journal.
7) ¿Puede containerd estar en ejecución pero Docker aún fallar al arrancar?
Absolutamente. La salud de containerd solo elimina una clase de fallos. Docker aún puede fallar en init del driver de almacenamiento, reglas de red, permisos de socket o parseo de daemon.json.
8) ¿Cómo sé si el disco está «lo bastante lleno» como para romper Docker?
Si el espacio libre baja a cientos de MB, o los inodos están agotados, Docker puede fallar al arrancar o comportarse de forma errática. Comprueba tanto df -h como df -i. También vigila remounts a solo lectura tras errores de I/O.
9) ¿Qué pasa si docker info se queda colgado en lugar de fallar?
Si el CLI cuelga, normalmente está esperando por el socket. Confirma si el daemon está en ejecución (systemctl is-active docker) y si el socket existe (ls -l /var/run/docker.sock). Colgar suele ser «daemon no responde», no «CLI roto».
10) ¿Rootless Docker es menos propenso a fallar?
Falla de forma distinta. Reduces la superficie de blast radius por privilegios, pero añades dependencia en servicios de usuario, delegación de cgroups y directorios runtime por usuario. Genial cuando está diseñado para ello; confuso cuando se añade a mitad de camino.
Próximos pasos que realmente reducen incidentes futuros
Hacer que Docker arranque es la victoria inmediata. Evitar el próximo «daemon down» es el verdadero trabajo. Esto es lo que haría tras que el polvo del incidente se asiente:
- Codifica la guía de diagnóstico rápido en tu runbook, con rutas y decisiones específicas de tu distro. Los comandos anteriores son una base; adáptalos.
- Estandariza la fuente de configuración de Docker: elige daemon.json para ajustes del daemon y drop-ins de systemd para ExecStart flags, o al revés—pero no mezcles sin criterio.
- Pon el estado de Docker en el almacenamiento correcto: ext4 local o XFS con las características adecuadas, monitorizado para capacidad e inodos. Mantén las capas overlay fuera de montajes en red.
- Controla el crecimiento de logs: configura rotación de logs de contenedores y monitoriza los tamaños de
/var/lib/docker/containers/*-json.log. Los outages por disco lleno son opcionales. - Haz explícita la propiedad del firewall en el diseño de la plataforma: Docker, firewalld, Kubernetes y agentes de seguridad pueden coexistir, pero solo si decides quién escribe qué reglas.
- Practica la recuperación en un nodo no productivo: simula un daemon.json corrupto, un disco lleno y un conflicto de iptables. Tu yo futuro te lo agradecerá y estará un poco menos cafeinado.