Docker en profundidad: quΓ© es, por quΓ© los contenedores importan y su arquitectura

Docker en profundidad: quΓ© es, por quΓ© los contenedores importan y su arquitectura

[!tip] Docker en una frase Docker es una plataforma para crear, distribuir y ejecutar aplicaciones dentro de contenedores ligeros: paquetes autΓ³nomos que incluyen todo lo que necesita un software para correr β€” cΓ³digo, runtime, herramientas del sistema, bibliotecas y configuraciones β€” garantizando que siempre funcione igual, sin importar dΓ³nde se ejecute.

ΒΏQuΓ© son los contenedores?

Los contenedores son una tecnologΓ­a de virtualizaciΓ³n a nivel de sistema operativo. A diferencia de las mΓ‘quinas virtuales tradicionales que emulan hardware completo y ejecutan un sistema operativo entero por cada instancia, los contenedores comparten el kernel del sistema operativo host pero ejecutan procesos aislados.

La analogΓ­a de los contenedores de envΓ­o

Antes de Docker, entregar software era como enviar mercancΓ­a sin estandarizar: cada empresa tenΓ­a cajas de tamaΓ±o diferente, mΓ©todos de apilamiento diferentes y reglas propias. Los contenedores de envΓ­o estandarizados (inventados en 1956 por Malcom McLean) resolvieron este problema:

Antes de los contenedores (cada app era diferente):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  App "X"         β”‚  β”‚  App "Y"         β”‚  β”‚  App "Z"         β”‚
β”‚  LibrerΓ­a A v1.2 β”‚  β”‚  LibrerΓ­a B v3.0 β”‚  β”‚  LibrerΓ­a C v0.9 β”‚
β”‚  Runtime Java 8  β”‚  β”‚  Runtime Node 12 β”‚  β”‚  Runtime Python 3.7β”‚
β”‚  Config especΓ­ficoβ”‚ β”‚  Config especΓ­ficoβ”‚ β”‚  Config especΓ­ficoβ”‚
β”‚  SO especΓ­fico    β”‚  β”‚  SO especΓ­fico    β”‚  β”‚  SO especΓ­fico    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          ❌ Cada uno necesita un servidor

DespuΓ©s de los contenedores (todos estandarizados):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Container   β”‚  β”‚ Container   β”‚  β”‚ Container   β”‚
β”‚ "App X"     β”‚  β”‚ "App Y"     β”‚  β”‚ "App Z"     β”‚
β”‚ (estΓ‘ndar)  β”‚  β”‚ (estΓ‘ndar)  β”‚  β”‚ (estΓ‘ndar)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                β”‚                β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   Contenedor de  β”‚
              β”‚     envΓ­o ΓΊnico  β”‚
              β”‚   (Docker)       β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β–Ό
              Se puede mover a cualquier servidor
              que tenga Docker instalado

Lo que un contenedor incluye

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       Imagen de Docker (Contenedor)       β”‚
β”‚                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Tu aplicaciΓ³n (cΓ³digo fuente)      β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Runtime (Node, Python, Java...)   β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Dependencias (npm, pip, maven...) β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Bibliotecas del sistema (libc...) β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Configuraciones                    β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Variables de entorno               β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

ΒΏPor quΓ© los contenedores cambiaron la industria?

El problema: "En mi mΓ‘quina funciona"

Antes de Docker, este era uno de los problemas mΓ‘s comunes en desarrollo de software:

Desarrollador: "En mi mΓ‘quina funciona perfectamente"
              β†’ Linux con Node 18, base de datos local,
                configuraciones en /etc/
              
Tester:        "AquΓ­ no funciona, da error de mΓ³dulo faltante"
              β†’ Su mΓ‘quina tiene Node 16, diferente SO,
                diferentes dependencias del sistema

ProducciΓ³n:    "Β‘ERROR EN PRODUCCIΓ“N!"
              β†’ El servidor de producciΓ³n tiene una versiΓ³n
                distinta de todas las bibliotecas

Este problema se llama "incompatibilidad de entornos", y costaba a las empresas billones de dΓ³lares en productividad perdida.

La soluciΓ³n: contenedores = entornos reproducibles

Contenedor creado en desarrollo β†’ Se envΓ­a a testing β†’ Se ejecuta en producciΓ³n
        ═══════════════════════════════════════════════════════════
                           MISMO ENTORNOS SIEMPRE

Los tres pilares de la revoluciΓ³n Docker

Problema anterior SoluciΓ³n con Docker Impacto
Incompatibilidad de entornos Contenedores con todo incluido "Funciona en cualquier parte"
Servidores sobrecargados MΓΊltiples contenedores en un solo servidor ReducciΓ³n de 5-10x en infraestructura
Despliegues lentos y riesgosos ImΓ‘genes versionadas, despliegue en segundos Despliegues mΓΊltiples veces al dΓ­a

Docker: historia rΓ‘pida

AΓ±o Evento
2008 Docker Inc. (entonces dotCloud) es fundada por Solomon Hykes
2013 Docker 0.1 lanzado como proyecto open source
2014 Docker 1.0 β€” primer lanzamiento estable
2015 Docker Swarm (orquestaciΓ³n nativa), Docker Compose
2016 Google, Microsoft y otros forman el OCI (Open Container Initiative)
2017 Kubernetes gana como estΓ‘ndar de orquestaciΓ³n
2020 Docker Desktop cambia licencia (empresas grandes pagan)
2021+ Podman, Buildah, Kaniko ganan popularidad como alternativas

[!note] Docker no es el ΓΊnico Docker popularizΓ³ los contenedores, pero no los inventΓ³. TecnologΓ­as anteriores como LXC (Linux Containers) ya existΓ­an. Docker mejorΓ³ la experiencia de usuario, el ecosistema de registros y la herramienta docker CLI que todos conocemos.

Arquitectura de Docker

Docker se basa en una arquitectura cliente-servidor. Esta es la clave para entender cΓ³mo funciona:

                    Docker Architecture
                    ────────────────

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Docker CLI  │────▢│           Docker Daemon              β”‚
β”‚  (docker)    β”‚     β”‚         (dockerd)                    β”‚
β”‚              β”‚     β”‚                                      β”‚
β”‚ docker run   β”‚     β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ docker build β”‚     β”‚  β”‚ Images  β”‚  β”‚ Container Engine β”‚  β”‚
β”‚ docker ps    β”‚     β”‚  β”‚ (cache) β”‚  β”‚  (runc)          β”‚  β”‚
β”‚ docker exec  β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚              β”‚     β”‚                                      β”‚
β”‚ docker push  β”‚     β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ docker pull  β”‚     β”‚  β”‚   Containers (procesos aislados) β”‚ β”‚
β”‚              β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β–Ό
                     Sistema Operativo Host
                     (Kernel Linux, cgroups,
                      namespaces, overlay fs)

Los componentes principales

1. Docker CLI (el cliente)

Es la herramienta que usas desde la terminal. Todo lo que escribes con el prefijo docker va aquΓ­:

docker run nginx                    # Iniciar un contenedor
docker build -t mi-app .            # Construir una imagen
docker ps                           # Listar contenedores
docker images                       # Listar imΓ‘genes
docker-compose up                   # Levantar aplicaciones multi-container

ΒΏQuΓ© hace internamente?

  • Parsea tu comando
  • Lo convierte en una solicitud API (HTTP/Unix socket)
  • La envΓ­a al Docker Daemon
  • Muestra la respuesta en la terminal
# Los comandos CLI se comunican con el daemon asΓ­:
docker CLI ──── HTTP API / Unix Socket ────▢ Docker Daemon (dockerd)
# En Linux: /var/run/docker.sock
# En Windows/Mac: Docker Desktop expone un socket Unix virtualizado

2. Docker Daemon (dockerd)

Es el cerebro de Docker. Se ejecuta como un servicio en segundo plano y es responsable de:

Responsabilidad DescripciΓ³n
Construir imΓ‘genes Procesa el Dockerfile y crea capas
Ejecutar contenedores Crea y gestiona contenedores a partir de imΓ‘genes
Redes Configura redes bridge, overlay, etc.
VolΓΊmenes Gestiona almacenamiento persistente
ComunicaciΓ³n Escucha solicitudes de la CLI y de otros Docker daemons
OrquestaciΓ³n Si usas Docker Swarm, gestiona el cluster
# Verificar que el daemon estΓ‘ corriendo
sudo systemctl status docker
# ● docker.service - Docker Application Container Engine
#     Active: active (running) since Lun 2024-01-15 10:30:00 UTC
 
# Verificar la versiΓ³n del daemon
docker info
# Client:
#  Version:           25.0.3
#  Context:           default
# Server:
#  Engine:
#   Version:          25.0.3
#   Architecture:     x86_64
#   Operating System: Ubuntu 22.04.3 LTS
#   CPUs:             8
#   Total Memory:     15.6GiB

3. Registros de Docker (Docker Registries)

Un registro es un almacΓ©n de imΓ‘genes Docker. El mΓ‘s conocido es Docker Hub (hub.docker.com), pero puedes usar cualquier registro:

Registros de Docker populares:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Docker Hub      β”‚  β”‚  GitHub GHCR     β”‚  β”‚  Google GCR      β”‚
β”‚  hub.docker.com  β”‚  β”‚  ghcr.io         β”‚  β”‚  gcr.io          β”‚
β”‚  - MΓ‘s grande     β”‚  β”‚  - Integrado con β”‚  β”‚  - Nativo de GCP   β”‚
β”‚  - PΓΊblico/priv. β”‚  β”‚    repos         β”‚  β”‚  - IAM integrado  β”‚
β”‚  - Comunidades   β”‚  β”‚  - Acceso con GH β”‚  β”‚  - Cloud NATI    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  AWS ECR         β”‚  β”‚  GitLab Registry β”‚  β”‚  Registry propio  β”‚  β”‚  Quay.io        β”‚
β”‚  amazonaws.com   β”‚  β”‚  registry.gitlab β”‚  β”‚  (Harbor,        β”‚  β”‚  - OCI comp.   β”‚
β”‚  - Nativo de AWS  β”‚  β”‚  - GitLab CI/CD β”‚  β”‚   Docker Reg.)   β”‚  β”‚  - CNCF project β”‚
β”‚  - IAM           β”‚  β”‚    integrado    β”‚  β”‚  - Open source   β”‚  β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

4. ImΓ‘genes Docker

Una imagen es una plantilla de solo lectura que contiene todo lo necesario para ejecutar una aplicaciΓ³n. Piensa en ella como la plantilla para crear contenedores:

RelaciΓ³n Imagen β†’ Contenedor:

  Imagen                    Contenedores
  (solo lectura)     ────── (ejecutables, mΓΊltiples)
  ══════════════          ═══════════════════════
  Plantilla de cocina     Platos servidos a clientes
  (receta, ingredientes)  (cada uno puede modificarse)

  nginx:latest   ───▢  Contenedor1 (nginx) β€” puerto 80
  nginx:latest   ───▢  Contenedor2 (nginx) β€” puerto 81
  nginx:latest   ───▢  Contenedor3 (nginx) β€” puerto 82
  mi-app:v1.2    ───▢  Contenedor4 (mi-app)
  postgres:16    ───▢  Contenedor5 (postgres)

5. Contenedores

Un contenedor es una instancia ejecutable de una imagen. Es donde tu aplicaciΓ³n realmente corre:

Ciclo de vida de un contenedor:
─────────────────────────────

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  creado  │────▢│  ejecut. │────▢│  detenido│────▢│  elimin. β”‚     β”‚  elimin. β”‚
β”‚ created  β”‚     β”‚  running β”‚     β”‚  stopped β”‚     β”‚  removed β”‚     β”‚  exited  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚                β”‚                β”‚                β”‚
     β”‚ docker create  β”‚ docker start   β”‚ docker stop    β”‚ docker rm
     β”‚                β”‚                β”‚                β”‚
  Estado:   Estado:    Estado:          Estado:
  No corre   Corre      No corre,       Borrado
  nada       datos      existe en       completamente
             persisten  disco

ΒΏCΓ³mo funciona Docker internamente?

Docker no usa mΓ‘quinas virtuales. Usa funciones nativas de Linux para crear el aislamiento. Esta es la magia:

Namespaces: aislamiento de procesos

Linux tiene namespaces que permiten que grupos de procesos se vean a sΓ­ mismos como si fueran los ΓΊnicos en el sistema:

Namespaces que usa Docker:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Namespace      β”‚  ΒΏQuΓ© aΓ­sla?                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  PID            β”‚  Procesos (cada contenedor ve solo     β”‚
β”‚                 β”‚  sus procesos)                           β”‚
β”‚  Network        β”‚  Interfaces de red, puertos, routes      β”‚
β”‚  Mount          β”‚  Sistema de archivos                     β”‚
β”‚  UTS            β”‚  Nombre de host y dominio               β”‚
β”‚  IPC            β”‚  ComunicaciΓ³n entre procesos (semΓ‘foros) β”‚
β”‚  User           β”‚  Mapeo de usuarios (UID/GID)            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ejemplo: Namespace PID

En el host:
  PID 1    β†’   Init (systemd)
  PID 100  β†’   docker container A
  PID 200  β†’   docker container B
  PID 300  β†’   docker container C

Dentro del container A:
  PID 1    β†’   Tu proceso principal (ej. nginx)
  PID 2    β†’   nginx worker process
  (PID 100 del host NO se ve desde dentro del container)

Dentro del container B:
  PID 1    β†’   Tu proceso principal (ej. postgres)
  (PID 100 y 200 del host NO se ven desde dentro del container)

cgroups: lΓ­mite de recursos

Los control groups (cgroups) permiten limitar, contar y aislar el uso de recursos (CPU, memoria, disco, red):

cgroups en acciΓ³n:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Host Server: 16 GB RAM, 8 CPU Cores        β”‚
β”‚                                             β”‚
β”‚  cgroup docker                              β”‚
β”‚  β”œβ”€β”€ container-db (limitado a:              β”‚
β”‚  β”‚    4 GB RAM, 2 CPU cores)                β”‚
β”‚  β”œβ”€β”€ container-web (limitado a:             β”‚
β”‚  β”‚    2 GB RAM, 1 CPU core)                 β”‚
β”‚  └── container-worker (limitado a:          β”‚
β”‚       2 GB RAM, 1 CPU core)                 β”‚
β”‚                                             β”‚
β”‚  Total asignado: 8 GB, 4 cores              β”‚
β”‚  Restante: 8 GB, 4 cores β†’ para otros usos  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Overlay2: sistema de archivos en capas

Docker usa overlay2 como su driver de almacenamiento por defecto. Las imΓ‘genes se construyen en capas de solo lectura y los contenedores aΓ±aden una capa de escritura:

Estructura de capas de una imagen:

  Imagen: node:20-alpine

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  ← Capa superior (solo lectura)
  β”‚  Capa: node bin       β”‚  (ΓΊltimo comando del Dockerfile)
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: npm + yarn     β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: Python         β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: Alpine base    β”‚  ← Capa inferior
  β”‚  (alpine:3.19)        β”‚     (~5 MB, sistema base mΓ­nimo)
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Contenedor creado a partir de esta imagen:
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  ← Capa de escritura (rw) β€” solo existe en este contenedor
  β”‚  Contenedor rw       β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  ← Capas de solo lectura (compartidas con otros contenedores)
  β”‚  Capa: node bin       β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: npm + yarn     β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: Python         β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  Capa: Alpine base    β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚑ Ventaja de capas: Si dos contenedores usan node:20-alpine, las 4 capas
   de solo lectura se comparten en disco. Solo la capa de escritura es
   ΓΊnica por contenedor.

runc: el motor de contenedores

Por debajo, Docker usa runc (del runtime de Docker) para crear y gestionar contenedores. runc sigue el OCI (Open Container Initiative):

Flujo completo de un "docker run":

  1.  docker CLI envΓ­a "docker run nginx" a dockerd
  2.  dockerd busca la imagen "nginx" localmente
  3.  Si no estΓ‘, dockerd la descarga de Docker Hub
  4.  dockerd le dice a runc: "crea un contenedor con esta imagen"
  5.  runc:
      a. Crea un nuevo namespace PID
      b. Crea un nuevo namespace Network
      c. Configura cgroups (lΓ­mites de recursos)
      d. Monta el sistema de archivos overlay
      e. Ejecuta el proceso principal (CMD del Dockerfile)
  6.  El contenedor estΓ‘ corriendo βœ“

Docker vs MΓ‘quinas Virtuales

Esta es la comparaciΓ³n mΓ‘s importante para entender por quΓ© Docker es diferente:

MÁQUINAS VIRTUALES (VM) vs CONTENEDORES (Docker)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CaracterΓ­stica     β”‚  MΓ‘quina Virtual      β”‚  Contenedor Docker   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  QuΓ© virtualiza    β”‚  Hardware completo    β”‚  Sistema operativo   β”‚
β”‚  Guest OS          β”‚  SΓ­ (SO completo)     β”‚  No (comparte host)  β”‚
β”‚  TamaΓ±o            β”‚  GBs (5-40 GB)        β”‚  MBs (10-500 MB)     β”‚
β”‚  Inicio            β”‚  Minutos              β”‚  Milisegundos        β”‚
β”‚  Overhead          β”‚  Alto (Hipervisor)    β”‚  Muy bajo            β”‚
β”‚  Aislamiento       β”‚  Fuerte (SO diferente)β”‚  Bueno (mismo SO)    β”‚
β”‚  ImΓ‘genes          β”‚  ISOs de SO           β”‚  Capas de imagen     β”‚
β”‚  Rendimiento       β”‚  Ligera penalizaciΓ³n  β”‚  Nativo casi 1:1     β”‚
β”‚  Ejemplo           β”‚  VirtualBox, KVM,     β”‚  Docker, Podman      β”‚
β”‚                     β”‚  VMware               β”‚                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Diagrama comparativo

MÁQUINA VIRTUAL:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  Host OS (Linux)
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Hypervisor (KVM/VMware)           β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚  β”‚
β”‚  β”‚  β”‚  Guest OS (Ubuntu)             β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  Node.js + App          β”‚  β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Hypervisor (KVM/VMware)           β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚  β”‚
β”‚  β”‚  β”‚  Guest OS (Windows)            β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  .NET + App             β”‚  β”‚β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↑            ↑
     4 GB RAM       4 GB RAM
     2 cores        2 cores
     Inicio: 2 min  Inicio: 2 min


CONTENEDOR (Docker):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  Host OS (Linux)
β”‚  Kernel Linux (compartido)              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Container 1 (node:20)             β”‚  β”‚
β”‚  β”‚  Node.js + App                     β”‚  β”‚
β”‚  β”‚  ~150 MB RAM                       β”‚  β”‚
β”‚  β”‚  Inicio: 0.5 seg                   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Container 2 (postgres:16)         β”‚  β”‚
β”‚  β”‚  PostgreSQL                        β”‚  β”‚
β”‚  β”‚  ~50 MB RAM                        β”‚  β”‚
β”‚  β”‚  Inicio: 0.3 seg                   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Container 3 (nginx:latest)        β”‚  β”‚
β”‚  β”‚  Nginx                             β”‚  β”‚
β”‚  β”‚  ~10 MB RAM                        β”‚  β”‚
β”‚  β”‚  Inicio: 0.2 seg                   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        ↑
     ~215 MB total
     Inicio: < 1 seg total

Comandos esenciales de Docker

GestiΓ³n de contenedores

# Descargar una imagen
docker pull nginx:latest
 
# Ejecutar un contenedor en segundo plano (-d = detached)
docker run -d --nombre web-server -p 8080:80 nginx:latest
 
# Listar contenedores en ejecuciΓ³n
docker ps
 
# Listar TODOS los contenedores (incluidos los detenidos)
docker ps -a
 
# Ver logs de un contenedor
docker logs web-server
 
# Ver logs en tiempo real (follow mode)
docker logs -f web-server
 
# Entrar a un contenedor en ejecuciΓ³n
docker exec -it web-server sh
 
# Detener un contenedor
docker stop web-server
 
# Iniciar un contenedor detenido
docker start web-server
 
# Eliminar un contenedor
docker rm web-server
 
# Eliminar un contenedor y sus volΓΊmenes
docker rm -v web-server

GestiΓ³n de imΓ‘genes

# Listar imΓ‘genes locales
docker images
 
# Construir una imagen desde un Dockerfile
docker build -t mi-app:1.0 .
 
# Etiqueta una imagen con una versiΓ³n
docker tag mi-app:1.0 mi-app:latest
 
# Eliminar una imagen
docker rmi mi-app:1.0
 
# Limpiar imΓ‘genes no usadas
docker image prune
 
# Limpiar TODO lo no usado (imΓ‘genes, contenedores, volΓΊmenes)
docker system prune -a

GestiΓ³n de redes

# Listar redes
docker network ls
 
# Crear una red personalizada
docker network create mi-red
 
# Conectar un contenedor a una red
docker network connect mi-red web-server
 
# Ver informaciΓ³n de una red
docker network inspect mi-red

GestiΓ³n de volΓΊmenes

# Listar volΓΊmenes
docker volume ls
 
# Crear un volumen
docker volume create mi-volumen
 
# Montar un volumen en un contenedor
docker run -d -v mi-volumen:/data nginx:latest
 
# Mount directo de carpeta (bind mount)
docker run -d -v $(pwd)/datos:/data nginx:latest

Conceptos clave para dominar Docker

ImΓ‘genes vs Contenedores

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Imagen           β”‚  Contenedor                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Plantilla estΓ‘ticaβ”‚  Instancia en ejecuciΓ³n                β”‚
β”‚  Solo lectura      β”‚  Lectura/escritura (capa extra)        β”‚
β”‚  En disco          β”‚  En memoria (RAM)                      β”‚
β”‚  Nombre:tag        β”‚  Nombre ΓΊnico + ID                     β”‚
β”‚  Ejemplo           β”‚  Ejemplo                               β”‚
β”‚  node:20-alpine    β”‚  "confused_swanson" (node:20-alpine)   β”‚
β”‚  nginx:latest      β”‚  "jolly_brown" (nginx:latest)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Puertos: mapeo de puertos

Docker expone puertos usando el flag -p:

# Sintaxis: -p [host-puerto]:[contenedor-puerto]
docker run -d -p 8080:80 nginx:latest
#           ↑          ↑
#           β”‚          └── Puertopuerto interno del contenedor (nginx escucha en 80)
#           └── Puerto en tu mΓ‘quina (accesible en http://localhost:8080)

Variables de entorno

# Pasar variables de entorno a un contenedor
docker run -d \
  --name mi-app \
  -e DATABASE_HOST=postgres \
  -e DATABASE_PORT=5432 \
  -e DATABASE_NAME=mibase \
  -e DATABASE_USER=usuario \
  -e DATABASE_PASSWORD=secreto123 \
  mi-app:latest
 
# Dentro de la app, se accede como variables normales:
# Python: os.environ['DATABASE_HOST']
# Node: process.env.DATABASE_HOST
# Java: System.getenv("DATABASE_HOST")

Health checks

Docker puede verificar si un contenedor estΓ‘ funcionando:

docker run -d \
  --name mi-app \
  --health-cmd="curl -f http://localhost:3000/health || exit 1" \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  mi-app:latest
 
# Ver estado de health
docker inspect --format='{{.State.Health.Status}}' mi-app
# healthcheck β†’ healthy | unhealthy | starting

Docker: buenas prΓ‘cticas iniciales

1. Usa imΓ‘genes oficiales

# βœ… Buena: imΓ‘genes oficiales verificadas
docker pull nginx:latest
docker pull node:20-alpine
docker pull postgres:16
 
# ❌ Mala: imÑgenes de usuarios no verificados
docker pull someuser/nginx

2. Nunca ejecutes como root dentro del contenedor

# ❌ Malo
FROM node:20-alpine
RUN npm install
CMD ["node", "server.js"]
 
# βœ… Bueno: crear un usuario no root
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
CMD ["node", "server.js"]

3. Usa .dockerignore

# .dockerignore
node_modules
.git
*.md
.env
dist/
.next/

4. Usa versiones especΓ­ficas (no solo latest)

# ❌ Malo: "latest" puede cambiar sin avisar
docker pull node:latest
 
# βœ… Bueno: versiΓ³n especΓ­fica, reproducible
docker pull node:20.11.0-alpine
 
# En Dockerfile:
# ❌ FROM node:latest
# βœ… FROM node:20.11.0-alpine

Errores comunes de principiantes

Error Causa SoluciΓ³n
permission denied while trying to connect to the Docker daemon socket Usuario no estΓ‘ en el grupo docker sudo usermod -aG docker $USER y reiniciar sesiΓ³n
port is already allocated Otro proceso usando ese puerto lsof -i :8080 para encontrar quΓ© lo usa
image does not have a sha256digest Imagen corrupta o descarga incompleta docker system prune y docker pull de nuevo
Contenedor se detiene inmediatamente El CMD/CMD no estΓ‘ corriendo o falla docker logs nombre-contenedor para ver el error
No se puede acceder a la app por puerto 80 Puerto no mapeado Agregar -p 80:80 al docker run
Datos se pierden al borrar contenedor No se usaron volΓΊmenes Usar docker volume o bind mounts

Resumen

  • Docker es una plataforma de contenedores que permite empaquetar aplicaciones con todo su entorno
  • Los contenedores comparten el kernel del host pero estΓ‘n aislados (namespaces, cgroups)
  • Arquitectura: CLI (cliente) β†’ Daemon (dockerd) β†’ runc (motor) β†’ Kernel Linux
  • ImΓ‘genes son plantillas de solo lectura; contenedores son instancias ejecutables
  • Registros (Docker Hub, GHCR, GCR, ECR) almacenan imΓ‘genes para distribuir
  • Docker vs VM: contenedores son mΓ‘s ligeros, mΓ‘s rΓ‘pidos, y comparten el SO
  • Capas de imagen: se comparten entre contenedores, ahorrando espacio en disco
  • Buenas prΓ‘cticas: imΓ‘genes oficiales, versiΓ³n fija, .dockerignore, no root, health checks

[!quote] La clave Docker no es magia: es una forma estandarizada de empaquetar software usando funciones nativas de Linux. Una imagen es la receta (Dockerfile), el contenedor es el plato cocinado, y un registro es el restaurante que sirve el plato a otros. Entender esta metΓ‘fora te ayuda a dominar Docker: imagenes = plantillas, contenedores = instancias, registros = distribuciΓ³n.

ConexiΓ³n con el resto de la wiki

Concepto tocado ArtΓ­culo en profundidad
Redes (puertos, TCP/IP) [[01-redes-internet/01-que-es-internet]]
Servidores y procesos [[01-redes-internet/014-servidores-procesos]]
Firewalls [[01-redes-internet/017-firewalls-proxies-loadbalancers]]
VPS [[01-redes-internet/020-vps]] (donde correrΓ‘s tus contenedores)