← maurobernal.com.ar

Etiqueta: registry

  • Por dentro del motor: entendiendo la arquitectura de Docker

    La primera vez que ejecuté docker run funcionó. Pero cuando algo falló, no tenía idea de dónde buscar. No entendía quién hacía qué, cómo se comunicaban las piezas ni por qué a veces el daemon parecía tener vida propia. Este artículo es lo que me hubiera gustado leer antes de ese momento.

    Docker no es un solo programa: es un sistema de piezas

    Uno de los errores conceptuales más comunes cuando arrancás con Docker es pensarlo como «el comando que corre contenedores». En realidad, Docker es una arquitectura cliente-servidor compuesta por varios componentes que trabajan juntos. Entenderlos hace que todo lo demás tenga sentido.

    El flujo completo en un diagrama

    ┌─────────────────────────────────────────────────────────────┐
    │                        TU TERMINAL                          │
    │                                                             │
    │   $ docker run nginx        ← Docker Client (CLI)          │
    └──────────────────┬──────────────────────────────────────────┘
                       │  REST API (Unix socket o TCP)
                       ▼
    ┌─────────────────────────────────────────────────────────────┐
    │                    DOCKER DAEMON (dockerd)                   │
    │                                                             │
    │   • Escucha comandos del cliente                            │
    │   • Administra imágenes, contenedores, redes, volúmenes     │
    │   • Delega la ejecución a containerd                        │
    └──────────┬─────────────────────────┬────────────────────────┘
               │                         │
               ▼                         ▼
    ┌──────────────────┐      ┌──────────────────────────────────┐
    │   containerd     │      │         Docker Registry           │
    │                  │      │   (Docker Hub / privado)          │
    │  • Gestiona      │      │                                   │
    │    ciclo de vida │      │  • Almacena imágenes              │
    │    del contenedor│      │  • docker pull baja de acá        │
    │  • Usa runc para │      │  • docker push sube acá           │
    │    crear procesos│      └──────────────────────────────────┘
    └──────────────────┘

    Docker Engine: el corazón del sistema

    El Docker Engine es el conjunto completo: client + daemon + la API REST que los conecta. Cuando instalás Docker en un servidor, lo que instalás es el Engine. En mis nodos SUSE Linux, el daemon corre como servicio systemd y arranca automáticamente con el sistema.

    # Ver estado del daemon
    sudo systemctl status docker
    
    # Ver logs del daemon en tiempo real
    sudo journalctl -u docker -f
    
    # Información completa del sistema Docker
    docker info

    Docker Client: lo que escribís en la terminal

    El cliente es simplemente la CLI: el binario docker que usás en la terminal. Su único trabajo es traducir tus comandos a llamadas a la API REST del daemon. Lo que importa saber: el cliente y el daemon pueden estar en máquinas diferentes. Puedo controlar el daemon de un servidor remoto desde mi notebook sin ningún problema.

    # Conectar el cliente a un daemon remoto
    export DOCKER_HOST=tcp://192.168.1.100:2376
    docker ps  # Lista contenedores del servidor remoto
    
    # O con contextos (la forma moderna)
    docker context create servidor-prod --docker "host=ssh://mbernal@192.168.1.100"
    docker context use servidor-prod
    docker ps  # Ahora habla con el servidor remoto

    Docker Daemon (dockerd): quien realmente hace el trabajo

    El daemon es el proceso que corre en background y gestiona todo: imágenes, contenedores, redes y volúmenes. Cuando ejecutás docker run nginx, es el daemon quien:

    1. Recibe el comando del cliente
    2. Verifica si la imagen nginx existe localmente
    3. Si no existe, la descarga del registry
    4. Crea el contenedor usando containerd y runc
    5. Configura la red y el sistema de archivos
    6. Arranca el proceso principal del contenedor

    Imágenes Docker: plantillas inmutables

    Una imagen es una plantilla de solo lectura que define el sistema de archivos y la configuración inicial de un contenedor. Está compuesta por capas (layers), donde cada instrucción del Dockerfile agrega una capa nueva. Esta arquitectura por capas es brillante: si dos imágenes comparten las mismas capas base, se almacenan una sola vez en disco.

    # Ver imágenes locales
    docker images
    
    # Ver las capas de una imagen
    docker history nginx:latest
    
    # Inspeccionar metadatos completos
    docker inspect nginx:latest

    Contenedores: instancias en ejecución de una imagen

    Un contenedor es una imagen en ejecución. La diferencia clave: la imagen es inmutable (solo lectura), mientras que el contenedor agrega una capa de escritura encima donde los procesos pueden crear y modificar archivos. Cuando el contenedor se destruye, esa capa desaparece. Por eso los datos importantes van en volúmenes — pero eso lo vemos en otro artículo.

    # Relación imagen → contenedor
    docker images ls          # ver imágenes (plantillas)
    docker ps -a              # ver contenedores (instancias)
    
    # Crear contenedor sin arrancarlo
    docker create --name mi-nginx nginx
    
    # Arrancarlo
    docker start mi-nginx
    
    # O directamente: crear + arrancar
    docker run -d --name mi-nginx -p 80:80 nginx

    Docker Registry: el repositorio de imágenes

    El registry es donde viven las imágenes. Docker Hub es el registry público por defecto, pero en producción muchas empresas usan registries privados. En mi entorno on-premise uso un registry privado para no depender de internet en los deploys.

    # Levantar un registry privado local
    docker run -d -p 5000:5000 --name registry-privado   -v /data/registry:/var/lib/registry   registry:2
    
    # Tagear imagen para el registry privado
    docker tag mi-api:latest localhost:5000/mi-api:latest
    
    # Subir al registry privado
    docker push localhost:5000/mi-api:latest
    
    # Bajar desde el registry privado
    docker pull localhost:5000/mi-api:latest

    Docker Compose: orquestación local

    Docker Compose es la herramienta para definir y ejecutar aplicaciones multi-contenedor. En lugar de ejecutar múltiples docker run, definís todos los servicios en un archivo YAML y los gestionás con un solo comando. Lo veremos en profundidad más adelante — te adelanto que cambia completamente la forma de trabajar.

    El flujo completo: qué pasa cuando ejecutás docker pull nginx

    # Esto es lo que pasa internamente:
    $ docker pull nginx
    
    # 1. Docker Client envía petición al daemon via /var/run/docker.sock
    # 2. Daemon consulta: ¿tengo nginx:latest localmente?
    # 3. Si no → contacta Docker Hub (registry.hub.docker.com)
    # 4. Autentica (si la imagen es privada)
    # 5. Descarga cada capa (layer) que no tenga en cache
    # 6. Verifica integridad con el digest SHA256
    # 7. Almacena las capas en /var/lib/docker/overlay2/
    
    Using default tag: latest
    latest: Pulling from library/nginx
    a803e7c4b030: Pull complete   ← cada línea es una capa
    8b625c47d697: Pull complete
    4d3239651a63: Pull complete
    Digest: sha256:bc5eac5eafc581aeda3008b4b1f07ebba230de2f27d47767129a6a905c84f470
    Status: Downloaded newer image for nginx:latest

    Por qué me importa entender esto

    El día que tuve un contenedor que no arrancaba y no sabía por dónde empezar a debuggear, entender la arquitectura me salvó. Saber que el daemon escribe en /var/lib/docker/, que los logs del daemon están en journalctl, que el socket Unix es /var/run/docker.sock — esos detalles marcan la diferencia entre resolver el problema en 5 minutos o perder una hora.

    # Cuando algo falla, estos son mis primeros comandos:
    sudo journalctl -u docker --since "1 hour ago"
    docker info
    docker system df          # ver uso de disco
    docker system events      # stream de eventos del daemon

    Artículo anterior: Cómo Docker cambió la forma en que trabajo | Serie Docker Completo | Próximo: Mi guía para escribir Dockerfiles →


    Artículo anterior: Cómo Docker cambió la forma en que trabajo (y por qué tardé en entenderlo) | Serie Docker Completo | Próximo: Mi guía para escribir Dockerfiles que no me den vergüenza →

Tags

tsql (27)mssql (26)sql (20)devops (20)dotnet (18)docker (15)performance (14)contenedores (11)dotnet10 (10)linux (9)csharp (8)microservicios (7)angular (7)angular21 (7)sql server (6)issabel (6)docker-compose (6)typescript (6)mysql (5).NET (5)