Docker “No se puede conectar con el daemon de Docker”: soluciones que realmente funcionan
El error siempre llega en el peor momento: estás en medio de un despliegue, la CI acaba de fallar, o intentas ejecutar una orden rápida antes de una reunión.
Escribes docker ps y Docker responde con el equivalente a un encogimiento de hombros:
No se puede conectar con el daemon de Docker.
Esto no es un solo problema. Es un síntoma. A veces el daemon está caído. A veces está en ejecución pero estás hablando con el socket equivocado.
A veces no tienes permiso para hablar con él. Y a veces ni siquiera estás en la máquina que crees. Arreglemos lo correcto, rápido,
sin rituales de “sudo a todo” por costumbre.
Qué significa realmente el error (y por qué miente)
La CLI de Docker es un cliente. El daemon de Docker (dockerd) es un servidor. El error “No se puede conectar” es el cliente diciendo:
“Intenté alcanzar al servidor en algún endpoint y fallé”.
Ese endpoint suele ser un socket Unix en Linux: /var/run/docker.sock. En Docker Desktop, es un socket proxyado a través
de la aplicación Desktop y una VM. En configuraciones remotas, puede ser TCP con TLS, o transporte por SSH. Si el cliente no puede abrir el socket, no puede
autenticarse, o se conecta al lugar equivocado, obtendrás el mismo mensaje genérico.
Hay cuatro grandes categorías:
- El daemon no está en ejecución (servicio detenido, bucle de reinicio, actualización fallida).
- El daemon está en ejecución pero es inalcanzable (ruta de socket equivocada, contexto equivocado,
DOCKER_HOSTincorrecto, problemas de DNS/SSH/TLS). - Permiso denegado (usuario no está en el grupo
docker, desajuste rootless, permisos del socket). - El daemon no puede arrancar (disco lleno, estado corrupto, problemas del driver de almacenamiento, fallos de cgroup/iptables, configuración incompatible).
Datos interesantes e historia breve (porque el pasado sigue rompiendo tu presente)
- El valor por defecto original de Docker era un socket Unix local. La “API remota por TCP” llegó después y ha sido un problema de seguridad desde entonces.
- systemd cambió las reglas para la gestión de servicios en Linux; “Docker está caído” se volvió “systemd dice que está arriba, pero no responde” (problema distinto).
- Docker Desktop usa una VM en macOS y Windows; nunca estás hablando con un dockerd “nativo” en el sistema operativo anfitrión.
- El modo rootless existe para evitar un daemon propiedad de root, pero cambia sockets, rutas y expectativas—buena idea, confusión frecuente.
- El grupo docker equivale efectivamente a root en la mayoría de sistemas. Puede montar el sistema de archivos host y escapar de contenedores. Trátalo como sudo.
- OverlayFS se volvió el driver principal de almacenamiento en Linux, reemplazando drivers antiguos como AUFS; las actualizaciones pueden sacar a la luz peculiaridades del sistema de archivos.
- La adopción de cgroups v2 (ahora común) cambió supuestos de control de recursos; configuraciones antiguas del daemon pueden romperse de formas extrañas.
- Las transiciones iptables/nftables causaron años de sorpresas en redes de contenedores; un daemon puede “arrancar” pero fallar al configurar reglas NAT.
- Los contextos de Docker se introdujeron para gestionar múltiples endpoints limpiamente; también facilitaron hablar accidentalmente con el daemon equivocado.
Un modelo mental útil: la CLI de Docker no “arranca Docker”. Solo le pide a Docker que haga cosas. Si la línea telefónica está cortada, puedes gritar más fuerte
(sudo) pero sigues gritando a un receptor muerto.
Una cita que vale la pena poner en una nota adhesiva, porque evita horas de depuración dirigida por superstición:
Idea parafraseada de Sidney Dekker: la fiabilidad vive en cómo los sistemas responden a las sorpresas, no en la ausencia de sorpresas.
Guion de diagnóstico rápido: primeras/segundas/terceras comprobaciones
Cuando estás de guardia, no “exploras”. Filtras. Aquí está el camino más corto hacia la verdad.
Primero: ¿qué endpoint está intentando usar la CLI?
- Comprueba
docker contexty las variables de entorno (DOCKER_HOST,DOCKER_CONTEXT). - Decisión: si apunta a remoto, Desktop o rootless, depura esa vía—no
systemctlen el host.
Segundo: ¿está vivo y escuchando el daemon?
- En Linux:
systemctl status dockeryjournalctl -u docker. - Decisión: si el servicio está caído o en bucle, arregla errores de inicio antes de tocar permisos.
Tercero: si está vivo, ¿es problema de permisos o de ruta del socket?
- Inspecciona la propiedad/modo de
/var/run/docker.sock, confirma tus grupos de usuario. - Decisión: si es permiso denegado, corrige la pertenencia al grupo (o usa rootless correctamente). Evita “chmod 666” como si fuera malware.
Cuarto (solo si es necesario): ¿falla el daemon por recursos o configuración?
- Espacio/inodos. Driver de almacenamiento. Cgroups/iptables. Proxy env. Certificados TLS.
- Decisión: elige la corrección concreta que responda al error en los logs, no la que recuerdas del año pasado.
Broma #1: Troubleshooting de Docker es como hacer espresso—la mayoría culpa a la máquina, y suele ser la molienda (tu endpoint).
Tareas prácticas: comandos, salidas, decisiones (12+)
Cada tarea abajo tiene tres partes: un comando que puedes ejecutar, qué suele significar la salida, y qué decisión deberías tomar.
Esta es la sección de “deja de adivinar”.
Task 1: Ver exactamente a dónde intenta conectarse la CLI de Docker
cr0x@server:~$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
prod Production daemon over SSH ssh://deploy@prod-host
Significado: El asterisco marca el contexto activo. El endpoint te dice el transporte y el socket/host.
Decisión: Si el contexto activo no es el que pretendías, cambia de contexto antes de hacer cualquier otra cosa.
Task 2: Mostrar variables de entorno que sobrescriben el endpoint
cr0x@server:~$ env | egrep '^(DOCKER_HOST|DOCKER_CONTEXT|DOCKER_TLS_VERIFY|DOCKER_CERT_PATH)='
DOCKER_HOST=tcp://127.0.0.1:2375
Significado: Tu shell está obligando a Docker a usar TCP en 2375 (a menudo desde un script o perfil antiguo).
Decisión: Desmárcalo (unset DOCKER_HOST) o corrígelo al endpoint deseado. No depures /var/run/docker.sock hasta que lo hagas.
Task 3: Chequeo rápido de salud—¿la CLI alcanza al daemon en absoluto?
cr0x@server:~$ docker version
Client: Docker Engine - Community
Version: 26.1.3
API version: 1.45
Go version: go1.22.3
Git commit: 9e34c2a
OS/Arch: linux/amd64
Server:
ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Significado: El cliente está instalado; el servidor no es alcanzable.
Decisión: Continúa con las comprobaciones de servicio/socket. No reinstales el cliente; ya está ahí.
Task 4: En Linux, comprueba si systemd cree que Docker está en ejecución
cr0x@server:~$ systemctl status docker --no-pager
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-01-02 09:14:03 UTC; 7min ago
TriggeredBy: ● docker.socket
Docs: man:dockerd(8)
Main PID: 1423 (dockerd)
Tasks: 19
Memory: 88.2M
CPU: 1.268s
CGroup: /system.slice/docker.service
└─1423 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Significado: El daemon está en ejecución, así que “No se puede conectar” probablemente sea una discordancia de endpoint o permisos.
Decisión: Ve a permisos del socket y comprobaciones de contexto/env, no a reinicios.
Task 5: Si Docker está caído, arráncalo y mira si se mantiene arriba
cr0x@server:~$ sudo systemctl start docker
cr0x@server:~$ systemctl is-active docker
active
Significado: El servicio arrancó correctamente (por ahora).
Decisión: Revisa los logs inmediatamente si hace flapping. “Activo” ahora no significa que estará activo en 30 segundos.
Task 6: Lee las últimas 100 líneas del log; deja de adivinar
cr0x@server:~$ sudo journalctl -u docker --no-pager -n 100
Jan 02 09:12:41 server dockerd[1399]: failed to start daemon: error initializing graphdriver: no space left on device
Jan 02 09:12:41 server systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Jan 02 09:12:41 server systemd[1]: docker.service: Failed with result 'exit-code'.
Significado: No es un problema de permisos. No es un problema de socket. El daemon no puede inicializar el almacenamiento por agotamiento de disco.
Decisión: Arregla el espacio/inodos primero. Reiniciar no ayudará.
Task 7: Confirma que el socket existe y quién es el propietario
cr0x@server:~$ ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 Jan 2 09:14 /var/run/docker.sock
Significado: El socket existe, es propiedad de root:docker, accesible a miembros del grupo docker.
Decisión: Si no estás en el grupo docker, o te añades (con cautela) o usas sudo/rootless correctamente.
Task 8: Confirma que tu usuario está en el grupo docker
cr0x@server:~$ id
uid=1001(cr0x) gid=1001(cr0x) groups=1001(cr0x),27(sudo)
Significado: No estás en docker.
Decisión: Añade el usuario al grupo (o decide no darle ese privilegio y apegarte a sudo).
Task 9: Añade el usuario al grupo docker de forma segura, luego vuelve a iniciar sesión
cr0x@server:~$ sudo usermod -aG docker cr0x
cr0x@server:~$ newgrp docker
cr0x@server:~$ id
uid=1001(cr0x) gid=1001(cr0x) groups=1001(cr0x),27(sudo),999(docker)
Significado: La shell actual ahora tiene el grupo docker.
Decisión: Reintenta docker ps. Si tu organización trata el grupo docker como privilegiado (debería), documenta y restringe la membresía.
Task 10: Detecta desajuste rootless vs rootful
cr0x@server:~$ docker info 2>/dev/null | egrep 'Rootless|Docker Root Dir|Server Version'
Server Version: 26.1.3
Docker Root Dir: /var/lib/docker
Rootless: false
Significado: Estás hablando con un daemon rootful (a nivel de sistema).
Decisión: Si pretendías rootless, estás en el contexto equivocado o en el socket equivocado. Si pretendías rootful, sigue con permisos y salud del servicio.
Task 11: Si el disco está lleno, mídelo como corresponde (espacio e inodos)
cr0x@server:~$ df -h /var/lib/docker
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p3 120G 120G 120M 100% /
cr0x@server:~$ df -i /var/lib/docker
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p3 7.6M 7.6M 1.2K 100% /
Significado: Estás sin bytes y sin inodos. Contenedores y capas consumen inodos.
Decisión: Libera espacio (prune images/containers) o amplía almacenamiento. No esperes que el daemon arranque hasta que ambos números sean razonables.
Task 12: Encuentra qué en /var/lib/docker está consumiendo la máquina
cr0x@server:~$ sudo du -xhd1 /var/lib/docker | sort -h
1.2G /var/lib/docker/containers
6.8G /var/lib/docker/overlay2
8.1G /var/lib/docker
Significado: Las capas overlay son el principal consumidor. Eso es normal; la pregunta es si está fuera de control.
Decisión: Considera docker system df y pruning, pero solo después de confirmar que no eliminarás imágenes necesarias en producción.
Task 13: Prune de forma segura (y entiende lo que estás borrando)
cr0x@server:~$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 42 6 18.3GB 12.7GB (69%)
Containers 9 2 1.1GB 700MB (63%)
Local Volumes 16 8 9.4GB 2.2GB (23%)
Build Cache 88 0 6.5GB 6.5GB
cr0x@server:~$ docker system prune -f
Deleted Containers:
...
Total reclaimed space: 8.1GB
Significado: Recuperaste espacio, mayormente de imágenes/caché no usadas.
Decisión: Si esto es producción, obtén aprobación explícita o usa pruning dirigido (docker image prune) para evitar borrar capas en caché usadas por despliegues.
Task 14: Verifica que el daemon esté escuchando donde crees
cr0x@server:~$ sudo ss -xlpn | egrep 'docker\.sock|containerd\.sock'
u_str LISTEN 0 4096 /run/docker.sock 22788 * 0 users:(("dockerd",pid=1423,fd=4))
u_str LISTEN 0 4096 /run/containerd/containerd.sock 22787 * 0 users:(("containerd",pid=961,fd=7))
Significado: dockerd está escuchando en /run/docker.sock, no necesariamente en /var/run/docker.sock (que a menudo es un symlink).
Decisión: Si tu cliente apunta a /var/run/docker.sock y esa ruta está rota, arregla el symlink o corrige el endpoint.
Task 15: Detecta un symlink roto en /var/run (sí, pasa)
cr0x@server:~$ ls -l /var/run/docker.sock
ls: cannot access '/var/run/docker.sock': No such file or directory
cr0x@server:~$ ls -ld /var/run
lrwxrwxrwx 1 root root 4 Jan 2 08:59 /var/run -> /run
Significado: El directorio de runtime canónico es /run; /var/run es un symlink. Si /run/docker.sock existe pero el otro no, hay inconsistencia.
Decisión: Prefiere unix:///run/docker.sock si tu sistema lo usa. Arregla rutas rotas en lugar de hacer chmod a archivos aleatorios.
Linux (systemd): cuando el servicio está caído o enfermo
En servidores Linux, este error a menudo es simple: dockerd no está en ejecución. Pero “no está en ejecución” tiene capas, como todo buen incidente de almacenamiento.
Un servicio puede estar detenido, en bucle de reinicio, bloqueado por dependencias, o vivo pero incapaz de responder a peticiones API porque está atascado en tareas de arranque.
Empieza con la vista de systemd, luego confirma la realidad
Si systemctl status dice “active (running)”, verifica que el socket exista y que realmente puedas consultar el daemon.
Si dice “failed”, no toques permisos. Logs primero.
Bloqueadores de inicio comunes que verás en los logs
- Disco lleno / agotamiento de inodos: la inicialización del graphdriver falla; Docker no puede montar capas overlay.
- daemon.json inválido: un typo detiene el daemon en seco.
- Problemas con iptables: Docker puede arrancar pero no puede crear redes; a veces falla al iniciar dependiendo de la distro y configuración.
- Desajuste de cgroup: configuraciones antiguas en kernels nuevos pueden romper supuestos del runtime de contenedores.
- containerd caído: dockerd depende de containerd; si está inestable, Docker puede fallar al iniciar o comportarse de forma errática.
Valida daemon.json en lugar de discutir con él
cr0x@server:~$ sudo cat /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" },
"data-root": "/var/lib/docker",
"iptables": true
}
cr0x@server:~$ sudo jq . /etc/docker/daemon.json >/dev/null
cr0x@server:~$ echo $?
0
Significado: El JSON se parsea correctamente.
Decisión: Si jq falla, arregla el JSON antes de reiniciar Docker. systemd reiniciará felizmente una configuración rota para siempre.
Reinicia con intención, no con pánico
cr0x@server:~$ sudo systemctl restart docker
cr0x@server:~$ systemctl --no-pager -l status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-01-02 10:02:19 UTC; 3s ago
Docs: man:dockerd(8)
Significado: Docker se reinició y actualmente está vivo.
Decisión: Prueba inmediatamente docker ps. Si funciona, terminaste. Si falla, el problema no era “servicio caído”.
Si docker.service está “active” pero la CLI aún no puede conectar
Aquí es donde los profesionales pierden tiempo si no se detienen. Si el daemon está en ejecución, “No se puede conectar” casi siempre es uno de:
(a) discordancia de endpoint, (b) permisos, o (c) estás en un contenedor/namespace donde la ruta del socket no existe.
Comprueba los argumentos del proceso para ver en qué está escuchando:
cr0x@server:~$ ps -ef | grep -E '[d]ockerd'
root 1423 1 0 09:14 ? 00:00:03 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Significado: -H fd:// significa que la activación por socket de systemd está en juego; la unidad de socket de Docker importa.
Decisión: Inspecciona docker.socket si el archivo de socket no aparece.
cr0x@server:~$ systemctl status docker.socket --no-pager
● docker.socket - Docker Socket for the API
Loaded: loaded (/lib/systemd/system/docker.socket; enabled; preset: enabled)
Active: active (listening) since Tue 2026-01-02 09:13:58 UTC; 48min ago
Triggers: ● docker.service
Listen: /run/docker.sock (Stream)
Significado: La unidad de socket está escuchando en /run/docker.sock.
Decisión: Asegura que el endpoint del cliente coincida (unix:///run/docker.sock) o que el symlink /var/run esté intacto.
Permisos y grupos: docker.sock y la “costumbre del sudo”
La variante más común de “No se puede conectar” es en realidad:
permiso denegado al intentar conectar con el socket del daemon de Docker.
Docker a menudo imprime ambos mensajes, pero la gente solo lee la primera línea y reinicia servicios como si fuera una alarma de incendios.
Entiende lo que estás concesionando
Añadir un usuario al grupo docker es conveniente. También concede casi control root, porque Docker puede montar el sistema de archivos host
o ejecutar contenedores privilegiados. En entornos corporativos, esto debe tratarse como acceso sudo.
Diagnostica problemas de permisos con limpieza
cr0x@server:~$ docker ps
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json": dial unix /var/run/docker.sock: connect: permission denied
Significado: Probablemente el daemon esté en ejecución; tu usuario no puede abrir el socket.
Decisión: Corrige la pertenencia al grupo o usa sudo docker para ese host (con aprobación de política). No pongas permisos 666 al socket.
No hagas “chmod 666 /var/run/docker.sock”
“Arregla” el error haciendo el socket de control de Docker escribible por todos. Eso no es una solución. Es dejar las llaves del servidor bajo el felpudo
y luego sorprenderse de que te robaron. Además: systemd recreará el socket en el reinicio con permisos correctos, así que tu “arreglo” es inestable.
Cuando sudo es aceptable
En máquinas personales de desarrollo, está bien. En sistemas compartidos, runners de CI y cualquier cosa con datos de clientes, deberías preferir patrones de acceso explícitos:
membresía controlada de grupos, Docker rootless, o un agente de build dedicado con privilegios mínimos.
Verifica cómo deberían verse los permisos del socket
cr0x@server:~$ stat -c '%A %U:%G %n' /run/docker.sock
srw-rw---- root:docker /run/docker.sock
Significado: Solo root y el grupo docker pueden leer/escribir el socket.
Decisión: Si el grupo no es docker o el modo es inusual, revisa overrides de la unidad systemd o cambios del empaquetado de la distro.
Endpoint equivocado: contextos de Docker, DOCKER_HOST, SSH, TLS
Si Docker está en ejecución y los permisos están bien, el siguiente culpable más probable es que te estés conectando al lugar equivocado.
Los contextos hicieron que trabajar en múltiples entornos sea sensato. También hicieron fácil hablar silenciosamente con un daemon muerto porque tu shell recordó una elección.
Conoce las reglas de precedencia
DOCKER_HOSTsobrescribe casi todo.DOCKER_CONTEXTselecciona un contexto (y sobrescribe el contexto “actual”).- El “contexto actual” es lo que
docker context useestablece. - Docker Desktop a menudo configura un contexto como
desktop-linux.
Cambia de contexto explícitamente y verifica
cr0x@server:~$ docker context use default
default
cr0x@server:~$ docker context inspect --format '{{.Name}} -> {{.Endpoints.docker.Host}}' default
default -> unix:///var/run/docker.sock
Significado: Has vuelto al socket local.
Decisión: Reintenta el comando Docker. Si funciona ahora, acabas de arreglar un fallo de memoria humana, no un bug del daemon.
Remoto por SSH: diagnostica la pierna SSH primero
cr0x@server:~$ docker --context prod ps
Cannot connect to the Docker daemon at ssh://deploy@prod-host. Is the docker daemon running?
cr0x@server:~$ ssh -o BatchMode=yes -o ConnectTimeout=5 deploy@prod-host 'systemctl is-active docker'
active
Significado: Docker está activo en remoto, y SSH funciona. El problema restante podría ser permisos del socket remoto o una discordancia de configuración SSH.
Decisión: Intenta ejecutar un comando docker remoto vía SSH directamente como prueba de control, o comprueba si el usuario remoto puede acceder al socket docker.
cr0x@server:~$ ssh deploy@prod-host 'docker ps'
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: connect: permission denied
Significado: El usuario remoto no tiene permisos.
Decisión: Corrige el acceso del usuario remoto (grupo docker o política sudo). No sigas toqueteando contextos localmente.
Endpoints TCP: si debes usarlos, hazlo como un adulto
Si ves tcp:// en DOCKER_HOST, desconfía. El puerto 2375 suele ser HTTP plano (sin TLS). El puerto 2376 suele ser TLS.
Docker expuesto por TCP plano es una “shell remota con permisos root” si está expuesto. Ideal para atacantes. Malo para dormir tranquilo.
cr0x@server:~$ echo "$DOCKER_HOST"
tcp://127.0.0.1:2375
cr0x@server:~$ curl -sS 127.0.0.1:2375/_ping
OK
Significado: Algo está escuchando en 2375 y responde como Docker.
Decisión: Si esto es inesperado, elimina esa configuración. Si es esperado, asegúrate de que esté ligado solo a loopback y, preferiblemente, protegido con TLS.
Docker Desktop: modos de fallo en macOS y Windows
Los entornos de escritorio crean una confusión especial: la CLI de Docker está en tu host, pero el daemon está en una VM.
Cuando Desktop falla, puedes perseguir servicios Linux fantasma que no existen.
macOS: el daemon no es un servicio launchd que puedas “systemctl”
En macOS, Docker Desktop gestiona su propio backend. Si obtienes “No se puede conectar”, normalmente tienes uno de:
- La app Desktop no está en ejecución o está atascada iniciando
- contexto cambiado desde
desktop-linux - estado de Desktop corrupto (raro, pero real)
- VPN/proxy/filtros de red interfiriendo con la conectividad de la VM
cr0x@server:~$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
desktop-linux Docker Desktop unix:///Users/cr0x/.docker/run/docker.sock
Significado: Estás en default pero Desktop espera desktop-linux.
Decisión: Cambia a desktop-linux y reintenta. Si la ruta del socket bajo tu home no existe, el backend de Desktop no está arriba.
Windows: WSL2 y confusión de contextos
En Windows con WSL2, puedes tener al menos tres realidades diferentes:
la CLI de Docker en PowerShell hablando con Docker Desktop,
la CLI de Docker dentro de una distro WSL hablando a través de la integración Desktop,
o un dockerd que instalaste dentro de WSL (lo cual probablemente no deberías).
Si estás dentro de WSL y instalaste Docker Engine allí, puede que falte systemd (dependiendo de la distro/configuración) y el servicio nunca arranque.
Si confías en la integración de Desktop, tu distro WSL no debería ejecutar su propio dockerd en absoluto.
cr0x@server:~$ docker info 2>/dev/null | egrep 'Operating System|Docker Root Dir|Server Version'
Server Version: 26.1.3
Operating System: Docker Desktop
Docker Root Dir: /var/lib/docker
Significado: Estás hablando con el backend de Docker Desktop.
Decisión: Si no puede conectar, arregla Desktop (reinicia, resetea, resuelve la integración WSL). No depures systemd Linux dentro de WSL a menos que ejecutes tu propio engine.
Broma #2: Si Docker Desktop dice que está “Starting…” durante 20 minutos, no está arrancando—está contemplando tus elecciones de vida.
Docker sin root, runners de CI y “funciona en mi portátil”
Docker sin root cambia la ubicación del socket y el modelo de propiedad. Ese es el punto. También rompe supuestos incorporados en scripts,
trabajos de CI y ese README que nadie ha actualizado desde la última reorganización.
Reconoce sockets rootless
Docker rootless normalmente escucha en un socket propiedad del usuario bajo algo como /run/user/1001/docker.sock.
Tu CLI podría seguir apuntando a /var/run/docker.sock, lo que fallará (o conectará a otro daemon).
cr0x@server:~$ ls -l /run/user/$(id -u)/docker.sock
srw-rw---- 1 cr0x cr0x 0 Jan 2 10:21 /run/user/1001/docker.sock
Significado: Existe el socket rootless para tu usuario.
Decisión: Apunta tu cliente a él (vía contexto o DOCKER_HOST=unix:///run/user/1001/docker.sock) y deja de intentar “arreglar” /var/run.
Runners de CI: efímeros, restringidos y a veces intencionalmente sin daemon
En CI, “No se puede conectar con el daemon de Docker” puede ser un comportamiento correcto: estás en un runner que no provee Docker-in-Docker, o el contenedor del servicio
no se inició. La solución correcta es alinear la arquitectura del pipeline, no añadir modo privilegiado por todos lados.
cr0x@server:~$ ls -l /var/run/docker.sock
ls: cannot access '/var/run/docker.sock': No such file or directory
Significado: No hay socket de daemon local. En CI, esto frecuentemente significa que el job no debe usar Docker directamente.
Decisión: O monta el socket (si tu modelo de seguridad lo permite), usa un builder remoto, o usa una cadena de herramientas de build sin root. No “instales docker” a ciegas.
Docker-in-Docker (DinD): entiende la compensación
DinD normalmente ejecuta un daemon separado dentro de un contenedor. Si olvidas iniciarlo, o si carece de privilegios/almacenamiento requerido, obtendrás el mismo error.
Es un patrón válido para algunos workloads de CI. También es una compensación de rendimiento y seguridad.
cr0x@server:~$ docker run --rm docker:26.1-dind dockerd --version
Docker version 26.1.3, build 9e34c2a
Significado: La imagen dind contiene dockerd, pero eso no significa que tu entorno de CI permitirá que se ejecute.
Decisión: Si necesitas DinD, asegúrate de que el runner soporte contenedores privilegiados y provea suficiente I/O de disco. De lo contrario usa un daemon remoto o un enfoque basado en BuildKit.
Almacenamiento y disco: cuando el daemon no puede respirar
Los fallos de almacenamiento son el primo escurridizo del error “No se puede conectar”. La CLI no puede conectar porque el daemon nunca llegó al punto en que puede aceptar conexiones.
O acepta conexiones pero es inutilizable porque está enloquecido por I/O.
Disco lleno no es sólo disco lleno
A Docker le importan:
- Bytes (df -h)
- Inodos (df -i)
- Características del sistema de archivos (expectativas de OverlayFS)
- Amplificación de escritura (capas overlay más logging intenso es tragedia)
Identifica el driver de almacenamiento y si es apropiado
cr0x@server:~$ docker info 2>/dev/null | egrep 'Storage Driver|Backing Filesystem|Supports d_type'
Storage Driver: overlay2
Backing Filesystem: ext4
Supports d_type: true
Significado: overlay2 sobre ext4 con soporte d_type es el camino bueno.
Decisión: Si ves Supports d_type: false o un driver inesperado, espera comportamientos raros de capas y problemas de inicio; arregla el sistema de archivos/configuración antes de culpar a Docker.
Cuando problemas de rendimiento parecen problemas de conectividad
A veces el daemon está “en ejecución” pero tan bloqueado por I/O que el cliente agota tiempo y reporta un fallo de conexión.
Verás demoras largas, docker ps colgado, y logs con timeouts hablando con containerd.
cr0x@server:~$ sudo iostat -xz 1 3
Linux 6.8.0 (server) 01/02/2026 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
10.23 0.00 6.12 58.90 0.00 24.75
Device r/s rkB/s rrqm/s %rrqm r_await w/s wkB/s w_await aqu-sz %util
nvme0n1 20.0 1200.0 0.0 0.0 2.10 900.0 64000.0 45.80 35.2 99.5
Significado: El disco está saturado; la latencia de escritura es alta. Las operaciones de metadatos de Docker se bloquearán.
Decisión: Trata esto como un incidente de recursos: reduce la carga de escritura (logs!), libera espacio, mueve data-root de Docker a un disco más rápido, o escala la carga.
Crecimiento de logs: el silencioso asesino de /var
El logging por defecto json-file de Docker puede comerse discos cuando las aplicaciones spamean logs. A tu daemon no le importan que sean “solo logs”;
le importa que no puede escribir metadatos y capas.
cr0x@server:~$ sudo find /var/lib/docker/containers -name '*-json.log' -printf '%s %p\n' | sort -n | tail -n 3
8246331120 /var/lib/docker/containers/1d9c.../1d9c...-json.log
9123341120 /var/lib/docker/containers/88af.../88af...-json.log
10322354112 /var/lib/docker/containers/a3b1.../a3b1...-json.log
Significado: Logs individuales de contenedores tienen varios GB. Esto puede llenar el disco e impedir que dockerd arranque.
Decisión: Implementa rotación de logs vía daemon.json (max-size, max-file) y/o mueve logs a un sistema centralizado. Luego trunca los peores cuidadosamente.
Tres mini-historias del mundo corporativo
1) El incidente causado por una suposición errónea: “contexto por defecto significa local”
Una empresa mediana tenía una configuración ordenada: los desarrolladores usaban Docker Desktop localmente, producción corría en VMs Linux, y ops usaba contextos de Docker para gestionar múltiples entornos.
El equipo tenía un contexto “prod” configurado por SSH para tareas de mantenimiento. Era conveniente. Demasiado conveniente.
Una mañana, un ingeniero obtuvo “No se puede conectar con el daemon de Docker” en su portátil. Asumió que Docker Desktop había muerto. Así que hizo lo que todos hacen:
reinició Docker Desktop, reinició su Mac, y aún obtuvo el error. La frustración creció. Saltaron mensajes en Slack. Nadie miró docker context ls.
El problema real: su perfil de shell exportaba DOCKER_CONTEXT=prod desde una sesión de hotfix de la semana anterior. Así que la CLI de Docker del portátil no intentaba conectar localmente en absoluto.
Intentaba alcanzar el endpoint SSH de producción. Excepto que producción había rotado llaves de host y la configuración SSH local ahora rechazaba la conexión.
El error de la CLI era técnicamente correcto pero emocionalmente poco útil.
La solución tomó dos minutos cuando alguien hizo la pregunta aburrida: “¿A dónde te estás conectando?”
Eliminó la exportación de entorno, cambió el contexto de vuelta a Desktop, y documentó una política de equipo: no exportar variables de contexto Docker persistentes en perfiles de shell.
Usa comandos explícitos y shells de corta duración para trabajo en prod. La conveniencia es un impuesto que pagarás después.
2) La optimización que salió mal: “Pongamos Docker en el gran sistema de archivos compartido”
Otra organización intentó optimizar uso de disco. Sus servidores de build se quedaron sin espacio, y el almacenamiento era caro.
Alguien propuso mover el data-root de Docker a un sistema de archivos de red compartido montado en cada builder.
Una copia de capas, compartida entre máquinas. En PowerPoint parecía victoria.
Lo implementaron, actualizaron /etc/docker/daemon.json, reiniciaron Docker, y durante unos días “funcionó”.
Luego el primer incidente real: “No se puede conectar con el daemon de Docker” intermitente en builders aleatorios. No todos a la vez; uno aquí, otro allá.
systemd mostraba docker.service “activo”, pero la CLI colgaba o fallaba. Los logs tenían timeouts de containerd y errores de overlay.
Lo que salió mal vino de realidades que no aparecen en una hoja de cálculo:
overlay2 y metadatos de contenedores son extremadamente habladores. La latencia importa. La semántica de bloqueo importa. Los fallos de red importan.
Bajo carga, el sistema de archivos compartido introdujo esperas largas de escritura; dockerd se volvió no responsivo y a veces caía durante escaneos de inicio.
La solución final no fue heroica. Fue arquitectónica: mantiene las capas escribibles de Docker en SSDs locales, usa un registry para compartir imágenes,
y deja que la caché ocurra en las capas correctas (build cache, mirrors de registry) en lugar de hacer que el filesystem finja ser un disco único grande.
La “optimización” intentaba compartir lo equivocado.
3) La práctica aburrida pero correcta que salvó el día: rotación de logs y margen de disco
Una plataforma en el ámbito financiero tenía requisitos estrictos de uptime y un equipo SRE pragmático. No eran gente emocionante en fiestas.
Hicieron algo poco fashion: impusieron políticas de margen de disco y configuraron rotación de logs de Docker en todas partes, incluso en dev.
Un viernes, una nueva versión de servicio se lanzó con un bug que spameaba logs durante un bucle de reintento. En otras organizaciones, aquí es donde los discos se llenan,
Docker se detiene, y el fin de semana desaparece. Aquí, los logs de contenedor rotaron automáticamente. El uso de disco subió y luego se estabilizó. Las alertas saltaron por “logging inusual”,
no por “sistema muerto”.
Los ingenieros hicieron rollback, arreglaron el bug, y se fueron a casa. No hubo caída del daemon. No hubo errores en cascada “No se puede conectar”. No hubo triaje de sistema de archivos a medianoche.
La causa raíz aún importaba, pero la plataforma tenía suficientes medidas que el fallo no se expandió.
La lección es irritantemente predecible: los “defaults aburridos” no son aburridos cuando te evitan depurar almacenamiento a las 3 a.m.
Pon límites a los logs. Mantén margen de disco. Asume que los humanos enviarán software ruidoso.
Errores comunes: síntoma → causa raíz → solución
1) “No se puede conectar…” después de cambiar entre entornos
- Síntoma: Funcionaba ayer, hoy falla;
systemctl status dockerparece correcto. - Causa raíz: Contexto Docker equivocado o
DOCKER_HOST/DOCKER_CONTEXTseteado en el shell. - Solución:
docker context ls, desmarca overrides de entorno,docker context use defaulto el contexto Desktop correcto.
2) “permission denied … /var/run/docker.sock”
- Síntoma: El error menciona permiso denegado; el servicio Docker está activo.
- Causa raíz: Usuario no está en docker group, o el socket tiene permisos inesperados por un override de unidad.
- Solución: Añade usuario al grupo docker (con política), re-login/newgrp, verifica propiedad del socket
root:dockery modo660.
3) “No such file or directory” para docker.sock
- Síntoma: Ruta del socket faltante.
- Causa raíz: Daemon no iniciado, docker.socket deshabilitado, o estás en un namespace/contenedor sin el bind mount del socket.
- Solución: Inicia/habilita el servicio y socket de docker; en contenedores, monta
/var/run/docker.sockintencionalmente o usa un daemon remoto.
4) El servicio Docker no arranca después de un cambio de configuración
- Síntoma:
systemctl start dockerfalla; los logs muestran errores de parseo. - Causa raíz: JSON inválido o clave no soportada en
/etc/docker/daemon.json. - Solución: Valida con
jq, revierte el último cambio, reinicia. Mantén cambios mínimos y revisados.
5) Docker “activo” pero la CLI cuelga o agota tiempo
- Síntoma:
docker pscuelga; eventualmente “No se puede conectar” o timeouts; alta carga. - Causa raíz: Saturación de I/O de disco, containerd atascado, o operaciones enormes de capas/metadatos durante el inicio.
- Solución: Revisa iowait, libera espacio, reduce spam de logs, considera mover
data-roota disco más rápido, reinicia containerd si es necesario.
6) Docker Desktop: la CLI no puede conectar pero la depuración Linux no muestra nada
- Síntoma: En macOS/Windows intentas
systemctly no tiene sentido. - Causa raíz: Backend de Desktop no está en ejecución, estado corrupto, o contexto equivocado.
- Solución: Cambia al contexto Desktop, reinicia Desktop, verifica la integración WSL2 (Windows), resetea estado solo si es necesario.
7) Confusión rootless: el socket existe, pero la CLI apunta a otro lado
- Síntoma: Tienes
/run/user/UID/docker.sockpero la CLI intenta/var/run/docker.sock. - Causa raíz: Contexto/env aún apunta al endpoint rootful.
- Solución: Establece el contexto correcto o exporta
DOCKER_HOSTal socket rootless para esa sesión.
8) Proxies corporativos: comandos Docker fallan de formas que parecen problemas del daemon
- Síntoma: “No se puede conectar” aparece durante pulls/builds, especialmente con contextos remotos.
- Causa raíz: Variables de proxy aplicadas de forma inconsistente; falta NO_PROXY para sockets/hosts locales; MITM corporativo intercepta TLS.
- Solución: Confirma variables de proxy y NO_PROXY; mantén la configuración de proxy del daemon explícita en lugar de heredar variables de shell aleatorias.
Listas de verificación / plan paso a paso
Checklist A: Estás en Linux y necesitas Docker funcionando ahora
- Confirma endpoint:
docker context ls;env | egrep '^DOCKER_'. - Comprueba servicio:
systemctl is-active docker. - Si inactivo:
sudo systemctl start docker, luegosudo journalctl -u docker -n 100si falla. - Si está activo pero falla: comprueba que el socket existe y permisos:
ls -l /run/docker.sockyid. - Si permiso denegado: decide política (grupo docker vs sudo). Añade al grupo solo si es aceptable.
- Si relacionado con disco: ejecuta
df -hydf -i; recupera espacio deliberadamente.
Checklist B: Sospechas contexto/endpoint remoto equivocado
docker context ls: identifica contexto activo y endpoint.env | egrep '^(DOCKER_HOST|DOCKER_CONTEXT)=': elimina overrides.docker context use default(o el que quieras).- Vuelve a probar con
docker versionpara ver secciones client/server. - Si usas SSH: prueba SSH por separado; luego ejecuta
ssh host docker pspara aislar permisos remotos.
Checklist C: El servicio Docker falla al arrancar (no lo fuerces)
sudo journalctl -u docker -n 200: captura el error real.- Valida
/etc/docker/daemon.jsonconjq. - Revisa bytes e inodos:
df -h,df -i. - Comprueba driver de almacenamiento y expectativas del FS (
docker infosi arranca; si no, consulta logs). - Solo entonces reinicia:
sudo systemctl restart docker.
Checklist D: Docker Desktop (macOS/Windows)
- Confirma que el contexto es Desktop:
docker context ls. - Si la ruta del socket bajo tu home falta, el backend de Desktop está abajo.
- Reinicia Desktop; si WSL2, confirma que la integración esté habilitada para la distro correcta.
- Evita ejecutar un segundo dockerd dentro de WSL a menos que quieras manejar esa complejidad.
FAQ
1) ¿Por qué Docker dice “¿Está corriendo el docker daemon?” cuando sí está corriendo?
Porque la CLI no puede alcanzar el endpoint que tiene configurado. El daemon puede estar corriendo en un socket distinto, en otro contexto, o en otra máquina.
Comprueba contextos y DOCKER_HOST primero.
2) ¿Debería ejecutar todo con sudo?
Para depuración rápida, sudo docker ps puede confirmar un problema de permisos. Como hábito a largo plazo, es desordenado y oculta problemas reales.
O bien gestiona la membresía del grupo docker explícitamente o usa Docker rootless donde encaje.
3) ¿Es seguro añadirme al grupo docker?
“Seguro” depende de tu modelo de amenazas. Prácticamente, ser miembro del grupo docker es casi equivalente a root en ese host.
Trátalo como acceso administrativo y restríngelo en consecuencia.
4) ¿Por qué /var/run/docker.sock no existe?
O bien Docker no está iniciado, la unidad de socket está deshabilitada, o estás en un entorno (como un contenedor o un runner CI mínimo) donde el socket no está montado.
También ten en cuenta que muchas distros usan /run/docker.sock con /var/run como symlink.
5) Arreglé la pertenencia al grupo pero aún dice permiso denegado. ¿Ahora qué?
Confirma que tu shell actual tiene los grupos actualizados (id). Si no, vuelve a iniciar sesión o usa newgrp docker.
Luego verifica que el grupo del socket sea realmente docker y que el modo sea srw-rw----.
6) Docker Desktop está en ejecución, pero la CLI aún no puede conectar. ¿Cuál es la causa más común?
Contexto equivocado. La gente salta entre “default” y “desktop-linux” (o similar) y lo olvida.
Ejecuta docker context ls y cámbiate al contexto Desktop.
7) ¿Puede un disco lleno causar “No se puede conectar con el daemon de Docker”?
Sí. Un disco lleno (o inodos llenos) puede impedir que dockerd arranque, o dejarlo atascado durante la inicialización del almacenamiento.
Revisa journalctl -u docker, df -h, y df -i.
8) ¿Cuál es la forma más rápida de saber si estoy golpeando al daemon equivocado (local vs remoto)?
Usa docker context inspect para ver el endpoint, luego ejecuta docker info y mira los campos “Operating System” / “Name”.
Desktop y engines remotos a menudo se identifican claramente.
9) ¿Cómo evito esta clase de fallo en producción?
Mantén margen de disco y rotación de logs configurada, monitoriza docker.service y la salud de containerd, evita ubicaciones de almacenamiento exóticas para data-root,
y haz el uso de contextos explícito en scripts operacionales (sin exports de entorno ocultos).
10) ¿Puede ser alguna vez una incompatibilidad de versiones cliente/servidor de Docker?
Raramente para un “no se puede conectar” puro, pero puede aparecer como errores de API después de la conexión.
Si obtienes conexión pero los comandos fallan de forma extraña, compara las versiones de API en la salida de docker version.
Conclusión: próximos pasos prácticos
“No se puede conectar con el daemon de Docker” no es un misterio; es un problema de enrutamiento, de permisos, o de salud del daemon.
El truco es negarse a tratarlo como un único bug.
- Fija el endpoint: contextos y
DOCKER_HOSTantes de cualquier otra cosa. - Revisa salud del servicio y logs: si dockerd no puede arrancar, los logs te dirán por qué.
- Corrige permisos de la manera correcta: pertenencia a grupo o rootless, no sockets world-writable.
- Respeta el almacenamiento: margen de disco, monitorización de inodos y rotación de logs previenen incidentes de “conectividad” que en realidad son incidentes de sistema de archivos.
Haz esas cuatro cosas y este error volverá a ser lo que debería haber sido todo el tiempo: una molestia menor, no una prueba de carácter.