352.3 Docker

Introducción

Docker es la plataforma de contenedores más extendida. Con un peso de 9 puntos (junto con libvirt), es uno de los subtemas más importantes del examen LPIC-3 305. Docker empaqueta aplicaciones y sus dependencias en contenedores portátiles y reproducibles.

Arquitectura de Docker

┌─────────────────────────────────────────────┐
│  Docker CLI (docker)                         │
├─────────────────────────────────────────────┤
│  Docker Daemon (dockerd)                     │
├──────────────┬──────────────────────────────┤
│  containerd  │  Docker Registry              │
├──────────────┤  (Docker Hub, privado)        │
│  runc        │                               │
├──────────────┴──────────────────────────────┤
│  Kernel Linux (namespaces, cgroups, overlay) │
└─────────────────────────────────────────────┘
ComponenteFunción
Docker CLIInterfaz de línea de comandos del usuario
dockerdDemonio que gestiona imágenes, contenedores, redes y volúmenes
containerdRuntime de alto nivel que gestiona el ciclo de vida
runcRuntime OCI de bajo nivel que crea los contenedores
RegistryAlmacén de imágenes (Docker Hub, Harbor, etc.)

Dockerfile

El Dockerfile define cómo construir una imagen de contenedor paso a paso.

Instrucciones principales

# Imagen base
FROM ubuntu:22.04
 
# Metadatos
LABEL maintainer="admin@ejemplo.com"
LABEL version="1.0"
 
# Variables de entorno
ENV APP_HOME=/app
ENV NODE_ENV=production
 
# Variables de build (solo disponibles durante la construcción)
ARG VERSION=1.0
ARG DEBIAN_FRONTEND=noninteractive
 
# Directorio de trabajo
WORKDIR $APP_HOME
 
# Ejecutar comandos durante la construcción
RUN apt-get update && apt-get install -y \
    nginx \
    curl \
    && rm -rf /var/lib/apt/lists/*
 
# Copiar archivos del contexto de build
COPY ./src/ /app/src/
COPY nginx.conf /etc/nginx/nginx.conf
 
# ADD: Similar a COPY pero soporta URLs y descompresión automática de tar
ADD https://ejemplo.com/archivo.tar.gz /tmp/
ADD archivo.tar.gz /app/
 
# Exponer puertos (documentación)
EXPOSE 80 443
 
# Definir volúmenes
VOLUME ["/data", "/logs"]
 
# Usuario para ejecutar el contenedor
USER nginx
 
# Healthcheck
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1
 
# Comando por defecto (puede ser sobrescrito)
CMD ["nginx", "-g", "daemon off;"]
 
# Punto de entrada (no se sobrescribe fácilmente)
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]

CMD vs ENTRYPOINT

AspectoCMDENTRYPOINT
PropósitoComando por defectoEjecutable principal
Overridedocker run imagen comandodocker run --entrypoint X imagen
CombinaciónCMD proporciona argumentos a ENTRYPOINTENTRYPOINT define el ejecutable
Forma shellCMD comando arg1ENTRYPOINT comando arg1
Forma execCMD ["cmd", "arg1"]ENTRYPOINT ["cmd", "arg1"]

Para el examen: Siempre usar la forma exec (con corchetes JSON). La forma shell ejecuta el comando a través de /bin/sh -c, lo que impide que las señales lleguen correctamente al proceso.

COPY vs ADD

AspectoCOPYADD
Copiar archivos locales
Descomprimir tar automáticamenteNo
Descargar URLsNo
RecomendadoSí (preferible)Solo cuando se necesita descompresión

Multi-stage Builds

Permiten construir en múltiples etapas para reducir el tamaño final de la imagen:

# Etapa de compilación
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o mi-app
 
# Etapa final (imagen mínima)
FROM alpine:3.18
COPY --from=builder /app/mi-app /usr/local/bin/
EXPOSE 8080
CMD ["mi-app"]

Para el examen: Los multi-stage builds son esenciales para crear imágenes pequeñas y seguras. La imagen final solo contiene lo necesario para ejecutar la aplicación, sin herramientas de compilación.

Comandos Docker Principales

Imágenes

# Construir imagen
docker build -t mi-app:v1 .
docker build -t mi-app:v1 -f Dockerfile.prod .
 
# Listar imágenes
docker images
docker image ls
 
# Descargar imagen
docker pull nginx:latest
 
# Subir imagen a registry
docker push mi-registry/mi-app:v1
 
# Etiquetar imagen
docker tag mi-app:v1 mi-registry/mi-app:v1
 
# Eliminar imagen
docker rmi mi-app:v1
 
# Historial de capas
docker history mi-app:v1
 
# Inspeccionar imagen
docker inspect mi-app:v1

Contenedores

# Ejecutar contenedor
docker run -d --name web -p 8080:80 nginx
 
# Ejecutar interactivo
docker run -it --rm ubuntu bash
 
# Listar contenedores activos
docker ps
 
# Listar todos (incluyendo detenidos)
docker ps -a
 
# Detener contenedor
docker stop web
 
# Iniciar contenedor detenido
docker start web
 
# Reiniciar
docker restart web
 
# Eliminar contenedor
docker rm web
 
# Forzar eliminación
docker rm -f web
 
# Logs
docker logs web
docker logs -f web          # Follow
docker logs --tail 100 web  # Últimas 100 líneas
 
# Ejecutar comando en contenedor existente
docker exec -it web bash
docker exec web cat /etc/nginx/nginx.conf
 
# Inspeccionar contenedor
docker inspect web
 
# Copiar archivos
docker cp archivo.txt web:/tmp/
docker cp web:/etc/nginx/nginx.conf ./
 
# Crear imagen desde contenedor modificado
docker commit web mi-imagen-custom:v1
 
# Estadísticas en tiempo real
docker stats

Opciones de run importantes

OpciónDescripción
-dModo daemon (background)
-itInteractivo con terminal
--rmEliminar al salir
--name <nombre>Asignar nombre
-p <host>:<cont>Mapear puertos
-PMapear todos los puertos expuestos
-v <host>:<cont>Bind mount
--mount type=X,...Montar volumen/bind/tmpfs
-e VAR=valorVariable de entorno
--env-file <file>Variables de entorno desde archivo
--network <red>Conectar a red
--restart <política>Política de reinicio (no, always, unless-stopped, on-failure)
--memory <límite>Límite de memoria
--cpus <N>Límite de CPUs

Docker Networking

Tipos de red

DriverDescripción
bridgeRed privada interna (por defecto). Contenedores se comunican entre sí.
hostEl contenedor comparte la red del host directamente.
noneSin red.
overlayRed que abarca múltiples hosts Docker (Swarm).
macvlanAsigna MAC real al contenedor, aparece como dispositivo físico.
# Listar redes
docker network ls
 
# Crear red bridge personalizada
docker network create mi-red
 
# Crear red con subnet específica
docker network create --subnet 172.20.0.0/16 mi-red
 
# Ejecutar contenedor en red personalizada
docker run -d --network mi-red --name web nginx
 
# Conectar contenedor existente a red
docker network connect mi-red web
 
# Desconectar de red
docker network disconnect mi-red web
 
# Inspeccionar red
docker network inspect mi-red
 
# Eliminar red
docker network rm mi-red

Para el examen: En redes bridge personalizadas, los contenedores pueden resolverse por nombre (DNS interno). En la red bridge por defecto (docker0), solo se pueden comunicar por IP.

Volúmenes y Bind Mounts

Volúmenes Docker (gestionados por Docker)

# Crear volumen
docker volume create mis-datos
 
# Listar volúmenes
docker volume ls
 
# Inspeccionar
docker volume inspect mis-datos
 
# Usar volumen en contenedor
docker run -d -v mis-datos:/data nginx
 
# Eliminar volumen
docker volume rm mis-datos
 
# Eliminar volúmenes no utilizados
docker volume prune

Bind Mounts (directorios del host)

# Bind mount
docker run -d -v /host/path:/container/path nginx
 
# Con --mount (más explícito)
docker run -d --mount type=bind,source=/host/path,target=/container/path nginx
 
# Solo lectura
docker run -d -v /host/path:/container/path:ro nginx
AspectoVolúmenesBind Mounts
GestiónDocker gestiona ubicaciónRuta del host explícita
PortabilidadAltaDepende del host
BackupFácil con docker commandsManual
RendimientoMejor en algunos driversDirecto al host
Uso típicoDatos persistentesDesarrollo, configuración

Docker Compose

Define aplicaciones multi-contenedor en un archivo YAML:

# docker-compose.yml
version: '3.8'
 
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    environment:
      - DB_HOST=db
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - db
    restart: unless-stopped
    networks:
      - app-net
 
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: miapp
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secreto
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-net
 
volumes:
  db-data:
 
networks:
  app-net:
    driver: bridge
# Levantar todos los servicios
docker compose up -d
 
# Ver estado
docker compose ps
 
# Ver logs
docker compose logs -f
 
# Detener servicios
docker compose down
 
# Detener y eliminar volúmenes
docker compose down -v
 
# Reconstruir imágenes
docker compose build
 
# Escalar servicio
docker compose up -d --scale web=3

.dockerignore

Excluye archivos del contexto de build:

# .dockerignore
.git
.gitignore
node_modules
*.md
.env
Dockerfile
docker-compose.yml
.dockerignore
__pycache__
*.pyc

Para el examen: .dockerignore reduce el tamaño del contexto de build enviado al daemon Docker, acelerando la construcción y evitando incluir archivos sensibles en la imagen.

Seguridad en Docker

Docker Rootless

# Instalar Docker rootless
dockerd-rootless-setuptool.sh install
 
# Configurar variable de entorno
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

User Namespaces

# Habilitar user namespaces en dockerd
# /etc/docker/daemon.json
{
  "userns-remap": "default"
}
 
# Verificar
docker info | grep -i userns

Buenas prácticas de seguridad

# No ejecutar como root
docker run --user 1000:1000 nginx
 
# Eliminar capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
 
# Filesystem de solo lectura
docker run --read-only nginx
 
# Sin acceso a nuevos privilegios
docker run --security-opt=no-new-privileges nginx
 
# NUNCA usar --privileged en producción

Limpieza del Sistema

# Eliminar contenedores detenidos, redes no usadas, imágenes sin referencia, caché
docker system prune
 
# Incluir volúmenes
docker system prune --volumes
 
# Ver uso de disco
docker system df
 
# Limpiar imágenes no referenciadas
docker image prune -a

Resumen

ConceptoDetalle clave
DockerfileFROM, RUN, COPY, CMD, ENTRYPOINT, EXPOSE, VOLUME
CMD vs ENTRYPOINTCMD = defecto sobrescribible; ENTRYPOINT = ejecutable fijo
Multi-stageMúltiples FROM para imagen final mínima
bridge personalizadoDNS automático entre contenedores
Volúmenes vs Bind MountsDocker-managed vs ruta del host
Docker ComposeAplicaciones multi-contenedor en YAML
.dockerignoreExcluir archivos del contexto de build
RootlessDocker sin privilegios de root

Trampas del examen

Errores comunes y distinciones criticas que LPI suele evaluar en este subtema:

  • docker stop vs docker killstop envia SIGTERM al proceso principal y espera 10 segundos (configurable con --time) antes de enviar SIGKILL. kill envia SIGKILL inmediatamente. El examen preguntara cual permite al contenedor hacer cleanup antes de terminar.
  • CMD vs ENTRYPOINT — CMD define el comando por defecto que se puede sobrescribir facilmente con docker run imagen otro-comando. ENTRYPOINT define el ejecutable fijo que solo se sobrescribe con --entrypoint. Cuando ambos coexisten, CMD proporciona argumentos por defecto a ENTRYPOINT. El examen mostrara un Dockerfile y preguntara que se ejecuta.
  • Forma exec ["cmd"] vs forma shell cmd — La forma exec (CMD ["nginx", "-g", "daemon off;"]) ejecuta el proceso directamente como PID 1. La forma shell (CMD nginx -g daemon off;) lo ejecuta via /bin/sh -c, lo que impide que las senales (SIGTERM) lleguen correctamente al proceso. Siempre usar forma exec.
  • COPY vs ADDCOPY solo copia archivos locales. ADD ademas descomprime tar automaticamente y soporta URLs. La mejor practica es usar siempre COPY excepto cuando se necesita descompresion. El examen puede preguntar cual instruccion descomprime un tar.gz automaticamente.
  • Red bridge default vs bridge personalizada — En la red docker0 (bridge por defecto), los contenedores solo se comunican por IP. En una red bridge personalizada (docker network create mi-red), los contenedores se resuelven por nombre via DNS interno automatico. El examen preguntara por que un contenedor no puede resolver el nombre de otro.
  • docker compose down -v borra volumenesdocker compose down detiene y elimina contenedores y redes. Agregar -v TAMBIEN elimina los volumenes con datos persistentes. Es una trampa comun en el examen: preguntar como se pierden datos accidentalmente.
  • .dockerignore reduce contexto de build, no la imagen.dockerignore evita que archivos se envien al daemon Docker como contexto de build. Si un archivo esta en .dockerignore, no puede usarse con COPY/ADD. Pero los archivos no afectan al tamano final de la imagen si no se copian, con o sin .dockerignore.
  • Multi-stage builds: solo la ultima etapa cuenta — En un multi-stage build, la imagen final solo contiene lo que esta en la ultima etapa (o la especificada con --target). Las herramientas de compilacion de etapas anteriores no se incluyen. El examen puede preguntar el tamano final de una imagen multi-stage.
  • Volumenes Docker vs bind mounts — Los volumenes (docker volume create) son gestionados por Docker y almacenados en /var/lib/docker/volumes/. Los bind mounts (-v /host:/container) montan un directorio del host directamente. El examen puede preguntar cual persiste tras docker system prune (respuesta: ambos, a menos que se use --volumes).
  • EXPOSE no publica puertosEXPOSE en el Dockerfile es solo documentacion; no abre puertos. Para publicar puertos se necesita -p host:container en docker run. El examen puede preguntar por que un servicio no es accesible desde fuera aunque el Dockerfile tiene EXPOSE.