Ir al contenido

8.5 Contenedores con Docker

Los contenedores han cambiado cómo se despliegan los servicios: en lugar de instalar software directamente en el servidor, lo empaquetas junto con todas sus dependencias en una imagen reproducible. Como sysadmin ya no basta con saber gestionar servicios con systemd — necesitas saber gestionar contenedores Docker que corren junto a ellos.


1. Qué es Docker y cómo se relaciona con el kernel

Sección titulada “1. Qué es Docker y cómo se relaciona con el kernel"

Docker no es un hipervisor: los contenedores comparten el kernel del host. Docker usa dos características del kernel Linux para aislarlos:

  • Namespaces: cada contenedor tiene su propio árbol de procesos, interfaces de red, usuarios y sistema de ficheros.
  • Cgroups: limitan la CPU, memoria y I/O que puede usar cada contenedor.
Host Linux (kernel compartido)
├── Proceso: nginx (contenedor 1 — namespace propio)
├── Proceso: postgres (contenedor 2 — namespace propio)
└── Proceso: sshd (servicio del host — sin contenedor)

ventana terminal
# Método oficial (repositorio Docker)
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg \
-o /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Verificar instalación
sudo docker run hello-world
# Permitir al usuario actual usar Docker sin sudo (requiere cerrar sesión)
sudo usermod -aG docker $USER

La relación imagen → contenedor es la misma que clase → instancia en programación.

ventana terminal
# Buscar imágenes en Docker Hub
docker search nginx
# Descargar una imagen
docker pull nginx:latest
docker pull nginx:1.26-alpine # versión específica
# Listar imágenes descargadas
docker images
# Ver información de una imagen
docker inspect nginx:latest
# Eliminar una imagen
docker rmi nginx:latest

ventana terminal
# Ejecutar un contenedor (descarga la imagen si no está local)
docker run nginx
# Modo detached (en segundo plano) con nombre y puerto mapeado
docker run -d --name mi-nginx -p 8080:80 nginx
# -d = background
# --name = nombre identificativo
# -p host:contenedor = mapeo de puertos
# Listar contenedores en ejecución
docker ps
# Listar todos (incluidos parados)
docker ps -a
# Ver logs del contenedor
docker logs mi-nginx
docker logs -f mi-nginx # Follow (en tiempo real)
# Ejecutar un comando dentro del contenedor
docker exec -it mi-nginx bash
# -i = interactivo, -t = terminal
# Detener / iniciar / reiniciar
docker stop mi-nginx
docker start mi-nginx
docker restart mi-nginx
# Eliminar un contenedor (debe estar parado)
docker rm mi-nginx
# Parar y eliminar en un solo paso
docker rm -f mi-nginx

Por defecto, los datos dentro de un contenedor se pierden cuando se elimina. Los volúmenes persisten los datos fuera del contenedor.

ventana terminal
# Montar un directorio del host dentro del contenedor
docker run -d \
--name nginx-web \
-p 80:80 \
-v /var/www/html:/usr/share/nginx/html:ro \
nginx
# /var/www/html = ruta en el HOST
# /usr/share/nginx/html = ruta en el CONTENEDOR
# :ro = solo lectura (opcional)

ventana terminal
# Ver redes disponibles
docker network ls
# bridge (por defecto — contenedores aislados pero pueden comunicarse por IP)
# host (el contenedor usa la red del host directamente)
# none (sin red)
# Crear una red personalizada (los contenedores se comunican por nombre)
docker network create mi-red
# Iniciar contenedores en la misma red
docker run -d --name app --network mi-red mi-app:latest
docker run -d --name db --network mi-red postgres:16
# Dentro de "app", puede conectarse a "db" por nombre:
# psql -h db -U postgres

7. Docker Compose — varios contenedores coordinados

Sección titulada “7. Docker Compose — varios contenedores coordinados"

docker compose define y levanta aplicaciones multi-contenedor con un fichero YAML.

ventana terminal
# Verificar instalación (viene con docker-compose-plugin)
docker compose version

Ejemplo de compose.yaml para una pila web+base de datos:

compose.yaml
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- db
db:
image: mariadb:11
environment:
MARIADB_ROOT_PASSWORD: rootpass
MARIADB_DATABASE: miapp
MARIADB_USER: appuser
MARIADB_PASSWORD: apppass
volumes:
- datos-db:/var/lib/mysql
volumes:
datos-db:
ventana terminal
# Levantar todos los servicios (en background)
docker compose up -d
# Ver estado
docker compose ps
# Ver logs de todos los servicios
docker compose logs -f
# Parar sin eliminar contenedores
docker compose stop
# Parar y eliminar contenedores, redes y volúmenes anónimos
docker compose down
# Eliminar también los volúmenes nombrados
docker compose down -v

Para que un contenedor arranque automáticamente con el servidor sin depender del daemon Docker directamente:

ventana terminal
# Crear un unit de systemd que use docker compose
sudo nano /etc/systemd/system/mi-app.service
[Unit]
Description=Mi aplicación Docker
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/opt/mi-app
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
ventana terminal
sudo systemctl daemon-reload
sudo systemctl enable mi-app
sudo systemctl start mi-app

ventana terminal
# Ver cuánto espacio ocupa Docker
docker system df
# Eliminar todo lo que no está en uso (imágenes, contenedores parados, redes, caché)
docker system prune
# Eliminar también volúmenes sin uso (¡cuidado con datos!)
docker system prune --volumes
# Eliminar solo imágenes sin tag (dangling images)
docker image prune
# Actualizar una imagen y recrear el contenedor
docker pull nginx:latest
docker compose up -d --pull always