Cuando ejecutaste docker run hello-world en la lección anterior, el propio mensaje del contenedor te resumió lo que había ocurrido: el cliente contactó con el daemon, el daemon descargó una imagen del registro, creó un contenedor a partir de ella y te devolvió su salida. Esa frase esconde una arquitectura completa, y entenderla es lo que separa a quien memoriza comandos de quien sabe diagnosticar problemas. En esta lección vas a abrir la caja: descubrirás que docker no ejecuta contenedores (solo los pide), quién los ejecuta realmente, qué papel juegan containerd y runc, qué es ese socket del que tanto hablamos y por qué el daemon es el verdadero dueño de todas tus imágenes, contenedores, volúmenes y redes. Terminarás interpretando la salida real de docker info y docker system df con ojos nuevos.
Contenido
- Docker es cliente-servidor, no un programa
- El cliente
docker - El daemon
dockerd - La API REST y el socket
/var/run/docker.sock - El flujo completo de un
docker run - containerd y runc: por qué hay tres capas
- Los objetos que gestiona el daemon
- Los registros y su papel
- Demostración práctica:
docker infoydocker system df
- Docker es cliente-servidor, no un programa
El primer malentendido que hay que deshacer: cuando escribes docker run, ese comando no crea ningún contenedor. Lo único que hace es traducir tu orden a una petición HTTP y enviarla a otro proceso, que es el que hace el trabajo de verdad.
Docker sigue una arquitectura cliente-servidor con tres actores:
| Actor | Qué es | Dónde vive |
|---|---|---|
Cliente (docker) |
Un programa de línea de comandos que traduce tus órdenes a llamadas de API | Tu terminal |
Daemon (dockerd) |
Un servicio de larga duración que construye, ejecuta y gestiona todo | Normalmente la misma máquina; puede ser remota |
| Registro | Un servicio que almacena y distribuye imágenes | Internet (Docker Hub) o tu red |
Las consecuencias de este diseño son muy prácticas:
- El cliente puede estar en otra máquina que el daemon. Puedes gestionar un servidor remoto desde tu portátil con el mismo comando
docker. - Puede haber muchos clientes contra un mismo daemon. Tu terminal, tu IDE y una herramienta de CI pueden hablar con el mismo motor a la vez.
- Si el daemon está parado, el cliente no puede hacer nada. De ahí el famoso
Cannot connect to the Docker daemon. - El estado vive en el daemon, no en tu terminal. Cerrar la terminal no para tus contenedores.
- El cliente
docker
dockerEl cliente es sorprendentemente tonto, y eso es bueno. Sus responsabilidades son:
- Parsear lo que escribes (
docker run -d --name web nginx). - Convertirlo en una o varias llamadas a la API REST del daemon.
- Mostrarte la respuesta con formato legible.
Nada más. No sabe crear contenedores, ni descomprimir imágenes, ni hablar con el kernel.
El cliente decide a qué daemon habla mediante los llamados contextos. Puedes verlos así:
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sockLectura: hay un único contexto, default, marcado como activo con el asterisco, y apunta al socket Unix local. Si tuvieras un servidor remoto configurado, verías otra fila con un DOCKER ENDPOINT del tipo ssh://usuario@servidor.
También puedes forzar el destino con la variable de entorno DOCKER_HOST:
Este comando lista los contenedores del servidor remoto, no los tuyos. El cliente es exactamente el mismo binario; solo cambia con quién habla. Es una demostración perfecta de que el cliente no ejecuta nada.
- El daemon
dockerd
dockerddockerd es el proceso que hace el trabajo. Corre como servicio del sistema (en Linux, gestionado por systemd) con privilegios de root, porque necesita manipular el kernel: crear espacios de nombres, configurar interfaces de red virtuales, montar sistemas de archivos.
Puedes verlo con las herramientas normales del sistema:
La primera línea te muestra el estado del servicio (active (running)); la segunda, el proceso real y sus argumentos. Verás algo como /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock, donde -H fd:// indica que escucha en el socket que le pasa systemd y --containerd= señala con qué containerd habla (lo veremos en el apartado 6).
Sus responsabilidades:
- Exponer la API REST y atender a los clientes.
- Gestionar el ciclo de vida de imágenes, contenedores, volúmenes y redes.
- Descargar y subir imágenes desde y hacia los registros.
- Construir imágenes (delegando en BuildKit, tema del módulo 2 y de la lección 05-05).
- Configurar la red virtual de los contenedores.
- Delegar la ejecución real en containerd.
Un detalle importante: si dockerd se reinicia, tus contenedores no tienen por qué morir. Gracias a la separación con containerd que verás enseguida, los contenedores en ejecución pueden sobrevivir a un reinicio del daemon.
- La API REST y el socket
/var/run/docker.sock
/var/run/docker.sockToda la comunicación entre el cliente y el daemon es una API REST sobre HTTP. Lo llamativo es que, por defecto, ese HTTP no viaja por la red: viaja por un socket Unix, un fichero especial del sistema de archivos:
Léelo con atención, porque explica cosas de la lección anterior:
- La
sinicial indica que es un socket, no un fichero normal. - El propietario es
rooty el grupo esdocker. - Los permisos
rw-rw----significan: root puede leer y escribir, el grupodockertambién, y nadie más.
Ahí está, en una línea, por qué necesitabas sudo o pertenecer al grupo docker. Y también por qué pertenecer al grupo docker equivale a ser root: quien puede escribir en ese socket puede pedirle al daemon (que es root) lo que quiera.
Que la API sea HTTP tiene una consecuencia divertida: puedes hablar con Docker sin usar el cliente. Con curl:
{"Platform":{"Name":"Docker Engine - Community"},"Version":"28.1.1","ApiVersion":"1.49","Os":"linux","Arch":"amd64"}Qué acabas de hacer: --unix-socket le dice a curl que en vez de abrir una conexión TCP use ese fichero socket; http://localhost/version es la ruta del endpoint (el host es irrelevante, solo hace falta para formar una URL válida). La respuesta es JSON crudo: exactamente lo mismo que docker version te muestra bonito.
Otro ejemplo, listando contenedores:
Devuelve un array JSON con los contenedores en ejecución: el equivalente exacto de docker ps. Esto no es un truco de fiesta: es cómo funcionan por dentro las herramientas gráficas, los plugins de IDE y los sistemas de monitorización.
Advertencia de seguridad. Montar
/var/run/docker.sockdentro de un contenedor es una práctica que verás en tutoriales (herramientas de CI, dashboards). Equivale a darle root sobre el anfitrión a ese contenedor. Se trata en detalle en la lección 05-03.
El daemon puede además escuchar en TCP (-H tcp://0.0.0.0:2376), imprescindible para acceso remoto, pero nunca sin TLS y autenticación: un daemon expuesto sin proteger en Internet se compromete en minutos.
- El flujo completo de un
docker run
docker runAhora sí, el recorrido completo de la orden más habitual del curso:
sequenceDiagram
participant U as Tú (terminal)
participant C as Cliente docker
participant D as Daemon dockerd
participant R as Registro (Docker Hub)
participant CD as containerd
participant RC as runc
participant K as Kernel Linux
U->>C: docker run -d -p 8080:80 nginx:alpine
C->>D: POST /images/create (si falta la imagen)
D->>D: ¿Está nginx:alpine en local?
alt No está
D->>R: GET manifest + capas
R-->>D: Manifiesto y capas (blobs)
D->>D: Descomprime y guarda capas
end
C->>D: POST /containers/create
D->>D: Prepara sistema de archivos y config de red
C->>D: POST /containers/{id}/start
D->>CD: Crear y arrancar contenedor
CD->>RC: Crear proceso aislado según spec OCI
RC->>K: namespaces + cgroups + montajes
K-->>RC: Proceso en ejecución
RC-->>CD: Listo (runc termina)
CD-->>D: ID del contenedor y estado
D-->>C: ID del contenedor
C-->>U: 3f2a9c1b7e4d...
Paso a paso, en palabras:
- Tú escribes el comando. El cliente lo parsea y valida las opciones.
- El cliente llama a la API. Traduce tu orden a peticiones HTTP contra el socket.
- El daemon busca la imagen en local. Si
nginx:alpineya está descargada, salta al paso 5. - Si falta, el daemon contacta con el registro. Pide primero el manifiesto (la lista de capas que componen la imagen) y luego descarga las capas que no tenga ya. Son estas descargas las que ves como
Pull complete. - El daemon crea el contenedor. Prepara su sistema de archivos apilando las capas de la imagen y añadiendo encima una capa de escritura, reserva el nombre
aurora-web-demo, y configura la red virtual y la regla de mapeo del puerto 8080 del host al 80 del contenedor. - El daemon pide a containerd que lo arranque.
- containerd invoca a runc, que es quien realmente le dice al kernel: crea estos espacios de nombres, aplica estos límites de recursos, monta este sistema de archivos y lanza este proceso.
- runc termina y desaparece. Su trabajo era arrancar el proceso, no supervisarlo.
- El daemon devuelve el ID al cliente, que te lo imprime.
Que runc desaparezca tras arrancar el contenedor es la razón de que Docker pueda actualizarse o reiniciarse sin matar contenedores: el proceso del contenedor ya no cuelga de él.
- containerd y runc: por qué hay tres capas
A primera vista, tres componentes para arrancar un proceso parece exagerado. La razón es histórica y estratégica.
En los primeros años, Docker era un binario monolítico que lo hacía todo. A medida que los contenedores se convirtieron en infraestructura crítica, la industria pidió estándares para no depender de un único proveedor. De ahí nació la OCI (Open Container Initiative), que publicó dos especificaciones clave:
- OCI Image Spec: cómo se estructura una imagen (capas, manifiesto, configuración).
- OCI Runtime Spec: cómo se describe y arranca un contenedor a partir de un sistema de archivos y un fichero de configuración JSON.
Docker se troceó para encajar en esos estándares:
| Componente | Nivel | Responsabilidad |
|---|---|---|
dockerd |
Alto | API REST, construcción de imágenes, redes, volúmenes, orquestación local |
containerd |
Medio | Gestión del ciclo de vida de contenedores, almacenamiento de imágenes, transferencia desde registros, supervisión |
runc |
Bajo | Crear un contenedor a partir de una spec OCI hablando con el kernel, y salir |
Míralo como una cadena de delegación, cada eslabón más específico y más simple que el anterior:
flowchart TB
CLI["Cliente docker"] -->|API REST| DAEMON["dockerd<br/>(alto nivel)"]
DAEMON -->|gRPC| CTRD["containerd<br/>(nivel medio, estándar del ecosistema)"]
CTRD -->|ejecuta| SHIM["containerd-shim<br/>(supervisa el contenedor)"]
SHIM -->|invoca una vez| RUNC["runc<br/>(bajo nivel, OCI Runtime)"]
RUNC -->|syscalls| KERNEL["Kernel Linux<br/>namespaces · cgroups · capabilities"]
KERNEL --> PROC["Proceso del contenedor"]
SHIM -.supervisa.-> PROC
Ese containerd-shim intermedio es la pieza que explica el "reinicio sin muertes": hay un shim por contenedor que se queda vivo supervisándolo, recoge su código de salida y mantiene abiertos sus flujos de entrada/salida, de modo que ni dockerd ni runc necesitan seguir presentes.
¿Por qué te importa esto como usuario?
- Porque containerd es hoy un estándar del ecosistema, y lo usan otras plataformas directamente (Kubernetes, por ejemplo, habla con containerd sin pasar por Docker). Lo verás en el módulo 6.
- Porque explica que existan alternativas compatibles a Docker que ejecutan exactamente las mismas imágenes (tema de la lección 07-05).
- Porque cuando leas un error que mencione
containerdorunc, sabrás a qué nivel está fallando algo.
Lo que ocurre exactamente en la flecha final —qué son los namespaces, los cgroups y cómo se apilan las capas del sistema de archivos— es el contenido de la lección 05-07. Aquí nos quedamos en el mapa.
- Los objetos que gestiona el daemon
El daemon mantiene cuatro tipos de objeto. Todo lo que harás en el curso es crear, listar, inspeccionar y borrar objetos de estos cuatro tipos, y la CLI moderna está organizada literalmente así (lo verás en la lección 01-04).
| Objeto | Qué es | Comando raíz | Dónde se profundiza |
|---|---|---|---|
| Imágenes | Plantillas inmutables de solo lectura | docker image |
Lección 01-05 y módulo 2 |
| Contenedores | Instancias en ejecución de una imagen | docker container |
Lección 01-06 y módulo 3 |
| Volúmenes | Almacenamiento persistente independiente del ciclo de vida del contenedor | docker volume |
Lección 03-06 |
| Redes | Redes virtuales que conectan contenedores entre sí y con el exterior | docker network |
Lección 03-05 |
Todos ellos se materializan en el disco bajo el directorio de datos del daemon, normalmente /var/lib/docker:
Qué es cada cosa relevante:
overlay2: las capas de las imágenes y las capas de escritura de los contenedores. Es lo que más ocupa con diferencia.image: los metadatos que relacionan imágenes con sus capas.containers: configuración y logs de cada contenedor.volumes: los datos de los volúmenes.network: la configuración de las redes virtuales.buildkit: la caché de construcción de imágenes.
Regla de oro: nunca toques a mano nada de /var/lib/docker. El daemon mantiene ahí bases de datos internas de estado; editar o borrar ficheros directamente es la forma más rápida de corromper la instalación. Todo se gestiona con comandos.
- Los registros y su papel
Un registro es un servicio que almacena y distribuye imágenes. Es la tercera pata de la arquitectura y la que da a Docker su capacidad de distribución.
El registro por defecto es Docker Hub (docker.io). Cuando escribes docker pull nginx:alpine, el cliente completa silenciosamente el nombre:
Donde docker.io es el registro, library es el espacio de nombres de las imágenes oficiales y nginx el repositorio. Por eso en la salida de hello-world viste Pulling from library/hello-world.
Para usar otro registro basta con nombrarlo explícitamente:
docker pull ghcr.io/aurora-libros/aurora-api:1.0.0
docker pull registry.interno.auroralibros.local:5000/aurora-api:1.0.0- El primero descarga del GitHub Container Registry.
- El segundo, de un registro privado autoalojado en la red de la empresa, que escucha en el puerto 5000.
Tipos habituales de registro:
| Tipo | Ejemplos | Cuándo se usa |
|---|---|---|
| Público gestionado | Docker Hub, GitHub Container Registry, Quay | Imágenes base y proyectos abiertos |
| Privado gestionado en la nube | Amazon ECR, Google Artifact Registry, Azure ACR | Imágenes de empresa desplegadas en esa nube |
| Privado autoalojado | Harbor, el registro oficial registry:2, Nexus |
Control total, redes aisladas, cumplimiento normativo |
El papel del registro en la arquitectura es el de almacén y punto de intercambio: el daemon sube (push) y baja (pull) imágenes, pero no lo necesita para ejecutar lo que ya tiene descargado. Un servidor sin conexión a Internet puede levantar contenedores perfectamente si sus imágenes ya están en local.
La autenticación (docker login), la publicación y la organización de repositorios se tratan en el módulo 2, especialmente en las lecciones 02-01 y 02-06.
- Demostración práctica:
docker info y docker system df
docker info y docker system dfVamos a leer la arquitectura reflejada en la salida real de dos comandos.
docker info
Client: Docker Engine - Community
Version: 28.1.1
Context: default
Plugins:
buildx: Docker Buildx (Docker Inc.) v0.23.0
compose: Docker Compose (Docker Inc.) v2.35.1
Server:
Containers: 4
Running: 2
Paused: 0
Stopped: 2
Images: 7
Server Version: 28.1.1
Storage Driver: overlay2
Backing Filesystem: extfs
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
containerd version: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc version: v1.2.5-0-g59923ef
Kernel Version: 6.8.0-52-generic
Operating System: Ubuntu 24.04.2 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 15.35GiB
Docker Root Dir: /var/lib/docker
Registry: https://index.docker.io/v1/
Live Restore Enabled: falseAhora que conoces la arquitectura, cada bloque tiene sentido:
| Campo | Qué te dice |
|---|---|
Bloques Client: / Server: |
La separación cliente-servidor en persona. Son dos entidades distintas |
Context: default |
A qué daemon está hablando el cliente |
Containers / Running / Stopped |
El inventario de objetos "contenedor" que custodia el daemon. Nota que hay 2 parados: existen y ocupan disco |
Images: 7 |
Los objetos "imagen" almacenados |
Storage Driver: overlay2 |
Cómo apila las capas de imagen (lección 01-05) |
Logging Driver: json-file |
Dónde van los logs de los contenedores (lección 05-06) |
Cgroup Driver / Version |
Cómo se aplican los límites de recursos (lecciones 03-07 y 05-07) |
Network: bridge host ipvlan... |
Los drivers de red disponibles (lecciones 03-05 y 05-01) |
containerd version / runc version |
Las dos capas inferiores del apartado 6, listadas explícitamente |
Kernel Version |
El kernel del anfitrión, que es el que usarán tus contenedores |
Docker Root Dir |
El directorio del apartado 7 |
Registry: https://index.docker.io/v1/ |
El registro por defecto del apartado 8 |
Live Restore Enabled |
Si está en true, los contenedores sobreviven a un reinicio del daemon |
En Windows o macOS, fíjate en que Operating System y Kernel Version no son los de tu equipo, sino los de la máquina virtual Linux de Docker Desktop. Es la demostración más clara de lo que se explicó en la lección 01-02.
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 7 2 1.842GB 1.376GB (74%)
Containers 4 2 12.4MB 8.2MB (66%)
Local Volumes 3 1 248.6MB 102.3MB (41%)
Build Cache 18 0 421.7MB 421.7MB (100%)Este comando responde a "¿en qué se me está yendo el disco?". Columna a columna:
- TYPE: los tipos de objeto del apartado 7, más la caché de construcción.
- TOTAL: cuántos objetos hay de ese tipo.
- ACTIVE: cuántos están en uso. Una imagen está activa si algún contenedor (aunque esté parado) la usa; un volumen, si está montado por algún contenedor.
- SIZE: espacio total ocupado. Ojo: en
Images, este número tiene en cuenta que las capas compartidas se cuentan una sola vez (lección 01-05). - RECLAIMABLE: cuánto recuperarías limpiando lo no usado. En el ejemplo, 1,376 GB de imágenes que ningún contenedor referencia.
Para el detalle por objeto:
Añade tablas desglosadas: cada imagen con su tamaño y cuántos contenedores la usan, cada contenedor con el tamaño de su capa de escritura, cada volumen con sus enlaces. Es la herramienta para localizar al culpable concreto de un disco lleno.
La limpieza (docker system prune) la verás en la lección 01-04.
Errores Comunes y Consejos
- Creer que
docker"es" Docker. El comando es solo un cliente. Si te acostumbras a pensar "yo pido, el daemon hace", entenderás por qué el daemon puede estar en otra máquina, por qué cerrar la terminal no para nada y por qué el estado no está donde escribes. - Confundir "no encuentro el contenedor" con "no existe". Si tienes varios contextos o un
DOCKER_HOSTpuesto en el entorno, puedes estar consultando otro daemon. Verifícalo condocker context lsyecho $DOCKER_HOST. - Exponer el daemon por TCP sin TLS. Abrir
-H tcp://0.0.0.0:2375es entregar la máquina. Existen botnets que rastrean ese puerto continuamente. Si necesitas acceso remoto, usa el contexto por SSH (docker context create --docker host=ssh://...), que es simple y seguro. - Montar
/var/run/docker.sockdentro de un contenedor a la ligera. Es una escalada a root del anfitrión. A veces es necesario, pero debe ser una decisión consciente (lección 05-03). - Tocar
/var/lib/dockera mano. Borrar directorios ahí para "liberar espacio" corrompe el estado del daemon. Usa siempre los comandos de la CLI. - Consejo:
docker infoes tu primer diagnóstico. Ante cualquier comportamiento raro, mira ahí: versión, driver de almacenamiento, cgroups, arquitectura y espacio. Muchos problemas "misteriosos" se explican con una línea de esa salida. - Consejo: recuerda la cadena de delegación. dockerd → containerd → shim → runc → kernel. Con ese esquema en la cabeza, los mensajes de error de bajo nivel dejan de ser ruido.
Ejercicios
Ejercicio 1: habla con la API sin usar el cliente
Sin ejecutar ningún comando docker (salvo para comparar al final), consigue mediante curl sobre el socket Unix: (a) la versión del daemon, (b) el número de contenedores en ejecución, y (c) la lista de imágenes locales. Después, compara cada resultado con su comando docker equivalente y explica qué relación hay entre ambos.
Ejercicio 2: sigue el rastro de las capas
Ejecuta estos comandos y responde a las preguntas:
(a) ¿Qué cifras cambian y por qué? (b) ¿Cuántos objetos de tipo imagen hay ahora activos y cuántos totales? (c) Si RECLAIMABLE de imágenes es alto, ¿qué significa exactamente eso en términos de la arquitectura que has estudiado?
Ejercicio 3: dibuja el fallo
Para cada uno de estos tres síntomas, indica en qué punto exacto de la cadena cliente → API/socket → daemon → registro → containerd → runc → kernel está el problema, y qué comprobarías:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?Error response from daemon: pull access denied for aurora-api, repository does not exist or may require 'docker login'docker: Error response from daemon: driver failed programming external connectivity on endpoint aurora-web-demo: Bind for 0.0.0.0:8080 failed: port is already allocated.
Soluciones
Solución al ejercicio 1
# (a) versión del daemon
curl -s --unix-socket /var/run/docker.sock http://localhost/version
# (b) contenedores en ejecución (cuenta de elementos del array JSON)
curl -s --unix-socket /var/run/docker.sock http://localhost/v1.49/containers/json | grep -o '"Id"' | wc -l
# (c) imágenes locales
curl -s --unix-socket /var/run/docker.sock http://localhost/v1.49/images/jsonComentarios:
-ssilencia la barra de progreso decurlpara dejar solo el JSON.--unix-socketes lo que hace posible todo: en lugar de una conexión TCP,curlescribe HTTP directamente en el fichero socket. Elhttp://localhostes solo un relleno sintáctico para formar una URL válida; el nombre de host se ignora./v1.49/es la versión de la API; puedes omitirla y el daemon usará la más reciente que soporte. Si tu versión difiere, mírala en la salida dedocker version(campoAPI version).- En (b), el
grep -o '"Id"' | wc -lcuenta cuántos objetos trae el array. Conjqinstalado sería más limpio:| jq 'length'.
Los equivalentes son docker version, docker ps y docker image ls. La relación es directa: el cliente docker hace exactamente estas mismas llamadas HTTP y se limita a formatear la respuesta en tablas legibles. Comprobarlo de primera mano es la mejor forma de interiorizar que el cliente no ejecuta nada.
Solución al ejercicio 2
(a) Cambian dos cosas en la fila Images: el TOTAL sube en 1 (hay una imagen más) y el SIZE aumenta, pero normalmente menos que el tamaño anunciado de la imagen, porque las capas que ya tuvieras de otras imágenes basadas en Alpine no se descargan ni se cuentan dos veces. Además, RECLAIMABLE sube en el tamaño de la nueva imagen, porque acabas de descargarla y todavía ningún contenedor la usa.
(b) TOTAL es el número de imágenes almacenadas; ACTIVE cuenta solo las referenciadas por algún contenedor (aunque esté parado). La recién descargada suma al total pero no a las activas.
(c) Un RECLAIMABLE alto significa que el daemon está custodiando en /var/lib/docker capas de imágenes que ningún contenedor referencia. No hacen daño más allá del disco que ocupan, y sirven de caché: si vuelves a usar esa imagen, no hay que descargarla. Se liberan con docker system prune -a, que verás en la lección 01-04.
Solución al ejercicio 3
-
Fallo entre el cliente y el socket/daemon. El cliente no logra siquiera establecer la conversación. Dos causas posibles: el daemon está parado (comprueba con
systemctl status docker; en Windows/macOS, que Docker Desktop esté iniciado) o tu contexto apunta a un endpoint que no responde (compruebadocker context lsyecho $DOCKER_HOST). Ojo a la diferencia conpermission denied: ese sería un problema de permisos sobre el socket, no de conexión. -
Fallo entre el daemon y el registro. El mensaje empieza por
Error response from daemon, así que el cliente llegó al daemon sin problema; fue el daemon quien no pudo obtener la imagen. Comprobarías: que el nombre y la etiqueta sean correctos, que el repositorio exista, si es privado (entonces faltadocker login), y si el registro es interno, que sea alcanzable desde la máquina. -
Fallo en el daemon, en la fase de configuración de red previa al arranque. El contenedor ni siquiera ha llegado a containerd/runc: el daemon intentó reservar el puerto 8080 del anfitrión y el sistema operativo se lo negó porque ya está ocupado. Comprobarías qué lo ocupa (
ss -tlnp | grep 8080, odocker pspor si es otro contenedor tuyo) y, o bien liberas ese puerto, o publicas el contenedor en otro (-p 8081:80).
Conclusión
Docker no es un programa: es un sistema cliente-servidor. El cliente docker solo traduce tus órdenes a llamadas de una API REST que viaja por el socket /var/run/docker.sock —cuyos permisos explican, de un vistazo, tanto el uso de sudo como el hecho de que el grupo docker equivalga a root—. Al otro lado, el daemon dockerd hace el trabajo real y delega hacia abajo en containerd (ciclo de vida y almacenamiento) y runc (creación del proceso aislado según la especificación OCI), una separación en capas que existe para respetar estándares y que permite que el ecosistema no dependa de un único producto.
El daemon custodia cuatro tipos de objeto —imágenes, contenedores, volúmenes y redes— en /var/lib/docker, y usa los registros solo para intercambiar imágenes, no para ejecutarlas. Todo eso está reflejado, literalmente, en la salida de docker info y docker system df, que ahora sabes leer.
Con el mapa mental completo, ya puedes empezar a dar órdenes con criterio. En la siguiente lección, Comandos Básicos de Docker, verás que la CLI está organizada exactamente según esos cuatro objetos (docker <objeto> <acción>), aprenderás los comandos esenciales sobre imágenes, contenedores y sistema, y recorrerás una sesión completa comentada de principio a fin.
Docker: De Principiante a Avanzado
Módulo 1: Introducción a Docker
- ¿Qué es Docker?
- Instalando Docker
- Arquitectura de Docker
- Comandos Básicos de Docker
- Entendiendo las Imágenes de Docker
- Creando tu Primer Contenedor Docker
- El Proyecto del Curso: la Plataforma Aurora Libros
Módulo 2: Trabajando con Imágenes Docker
- Docker Hub y Repositorios
- Construyendo Imágenes Docker
- Conceptos Básicos de Dockerfile
- Instrucciones Avanzadas del Dockerfile
- Gestionando Imágenes Docker
- Etiquetado y Publicación de Imágenes
Módulo 3: Contenedores Docker
- Ejecutando Contenedores
- Ciclo de Vida del Contenedor
- Gestionando Contenedores
- Inspección y Depuración de Contenedores
- Redes en Docker
- Persistencia de Datos con Volúmenes
- Límites de Recursos y Políticas de Reinicio
Módulo 4: Docker Compose
- Introducción a Docker Compose
- Definiendo Servicios en Docker Compose
- Comandos de Docker Compose
- Aplicaciones Multi-Contenedor
- Variables de Entorno en Docker Compose
- Perfiles, Overrides y Múltiples Entornos
- Desarrollo Local con Docker Compose
Módulo 5: Conceptos Avanzados de Docker
- Profundización en Redes Docker
- Opciones de Almacenamiento Docker
- Mejores Prácticas de Seguridad en Docker
- Optimizando Imágenes Docker
- Builds Avanzadas con BuildKit y Buildx
- Registro y Monitoreo en Docker
- El Runtime por Dentro: Namespaces, Cgroups y Capas
Módulo 6: Docker en Producción
- Preparar una Imagen para Producción
- CI/CD con Docker
- Orquestando Contenedores con Docker Swarm
- Introducción a Kubernetes
- Desplegando Contenedores Docker en Kubernetes
- Escalado y Balanceo de Carga
- Estrategias de Despliegue y Rollback
