Saltar al contenido

lección 5

docker-compose: orquestar varios servicios juntos

El archivo docker-compose.yml, levantar múltiples servicios con un comando, depends_on y el flujo de trabajo profesional.

55 min

Hasta ahora has ejecutado contenedores individuales con docker run. Está bien para aprender, pero en el mundo real las aplicaciones no viven solas. Un pipeline de datos típico necesita: una base de datos (PostgreSQL), un cache (Redis), una herramienta de visualización (Jupyter), y tu código Python que los conecta todos. ¿Vas a escribir 4 docker run diferentes, recordar todos los flags, los puertos, las variables de entorno, y ejecutarlos en el orden correcto cada mañana? No. Para eso existe docker-compose.

docker-compose es como el DIRECTOR DE ORQUESTA de tus contenedores. Tú escribes una "partitura" (un archivo YAML llamado docker-compose.yml) que describe todos los servicios que necesitas, cómo se conectan entre sí, qué puertos exponen, qué variables de entorno usan — y luego con UN SOLO COMANDO (docker compose up) toda la orquesta empieza a tocar. PostgreSQL arranca, Redis se levanta, Jupyter se conecta a ambos, y tu script puede hablar con todos.

Consejo de senior: docker-compose es probablemente el comando que MÁS usarás en toda tu carrera de data engineering. PostgreSQL para SQL? docker compose up. Airflow para orquestación? docker compose up. Kafka para streaming? docker compose up. LocalStack para AWS? docker compose up. Aprende esto bien porque es tu herramienta diaria.

### Tu primer docker-compose.yml

Un docker-compose.yml es un archivo en formato YAML (un formato legible por humanos, como JSON pero más limpio) que describe tu infraestructura. Veamos uno simple con PostgreSQL:

1# Archivo: docker-compose.yml
2services:
3 db:
4 image: postgres:16
5 environment:
6 POSTGRES_USER: datos
7 POSTGRES_PASSWORD: secreto123
8 POSTGRES_DB: ventas
9 ports:
10 - "5432:5432"

Tu primer docker-compose.yml — PostgreSQL en 8 líneas

1# Levantar todos los servicios definidos en docker-compose.yml
2docker compose up
3
4# Levantar en background (detached)
5docker compose up -d
6
7# Ver qué servicios están corriendo
8docker compose ps
9
10# Parar todos los servicios
11docker compose down
12
13# Parar y BORRAR los volúmenes (borra datos)
14docker compose down -v

Los 4 comandos de docker-compose que usarás a diario

Compara esto con el docker run equivalente: docker run -d --name db -e POSTGRES_USER=datos -e POSTGRES_PASSWORD=secreto123 -e POSTGRES_DB=ventas -p 5432:5432 postgres:16. El docker-compose.yml es infinitamente más legible, versionable (va en Git), y escalable (añadir un servicio más es añadir unas líneas).

### Múltiples servicios: la potencia real

La verdadera magia de docker-compose llega cuando tienes VARIOS servicios que necesitan hablar entre sí. Veamos un ejemplo con PostgreSQL + Redis + una app Python:

1# Archivo: docker-compose.yml — entorno multi-servicio
2services:
3 db:
4 image: postgres:16
5 environment:
6 POSTGRES_USER: datos
7 POSTGRES_PASSWORD: secreto123
8 POSTGRES_DB: analytics
9 ports:
10 - "5432:5432"
11
12 cache:
13 image: redis:7-alpine
14 ports:
15 - "6379:6379"
16
17 app:
18 build: .
19 environment:
20 DATABASE_URL: postgresql://datos:secreto123@db:5432/analytics
21 REDIS_URL: redis://cache:6379
22 depends_on:
23 - db
24 - cache
25 ports:
26 - "8000:8000"

Tres servicios orquestados: DB + Cache + App — un docker compose up los levanta todos

### depends_on: el orden importa

Observa la clave depends_on en el servicio "app". Le dice a Docker Compose: "no arranques la app hasta que db y cache estén levantados". Es como decir "no empieces a cocinar la paella hasta que el fuego esté encendido". Sin depends_on, los servicios arrancan en cualquier orden y tu app podría intentar conectarse a PostgreSQL antes de que esté listo.

depends_on solo garantiza que el CONTENEDOR ha arrancado, no que el SERVICIO dentro esté listo. PostgreSQL tarda unos segundos en inicializarse después de que su contenedor arranque. Para producción se usan healthchecks, pero para desarrollo local depends_on suele ser suficiente.

1# Healthcheck: Compose espera a que el servicio esté DE VERDAD listo
2services:
3 postgres:
4 image: postgres:16
5 environment:
6 POSTGRES_PASSWORD: secreto123
7 healthcheck:
8 test: ["CMD-SHELL", "pg_isready -U postgres"]
9 interval: 3s
10 timeout: 3s
11 retries: 5
12
13 etl:
14 build: .
15 depends_on:
16 postgres:
17 condition: service_healthy # ← espera al healthcheck, no solo al arranque

Con healthcheck + condition, Compose imprime Waiting → Healthy antes de arrancar el ETL.

### La magia del DNS interno: los servicios se encuentran por nombre

Fíjate en DATABASE_URL: postgresql://datos:secreto123@db:5432/analytics. El "db" en esa URL NO es localhost — es el NOMBRE del servicio definido en docker-compose.yml. Docker Compose crea una red interna donde cada servicio puede encontrar a los demás por su nombre. Es como si en un edificio de oficinas cada empresa tuviera un buzón con su nombre en el hall — no necesitas saber el número de puerta, solo el nombre.

1# Dentro de docker-compose, los servicios se encuentran POR NOMBRE:
2# - db → accesible como "db" desde otros contenedores
3# - cache → accesible como "cache" desde otros contenedores
4# - app → accesible como "app" desde otros contenedores
5
6# Ejemplo: desde el contenedor "app", PostgreSQL está en:
7# host: db (NO localhost)
8# port: 5432
9
10# Desde tu ordenador (fuera de Docker), PostgreSQL está en:
11# host: localhost
12# port: 5432 (el que mapeaste con ports)

DNS interno de docker-compose: nombre-del-servicio = hostname

### build vs image: usar tu propio Dockerfile

Has visto que "db" y "cache" usan image: (imágenes pre-hechas de Docker Hub), pero "app" usa build: . (construye una imagen desde tu Dockerfile local). Puedes mezclar ambos estilos libremente:

  • image: postgres:16 → "Usa la imagen postgres:16 de Docker Hub tal cual"
  • build: . → "Construye una imagen usando el Dockerfile que está en el directorio actual"
  • build: ./mi-servicio → "Construye usando el Dockerfile dentro de la carpeta mi-servicio"

### Comandos esenciales de docker-compose

1# Levantar servicios en background
2docker compose up -d
3
4# Ver logs de todos los servicios
5docker compose logs
6
7# Ver logs de UN servicio específico, en tiempo real
8docker compose logs -f db
9
10# Parar servicios sin borrarlos
11docker compose stop
12
13# Parar y borrar contenedores + redes (datos en volúmenes se mantienen)
14docker compose down
15
16# Reconstruir imágenes (cuando cambias tu Dockerfile o código)
17docker compose up -d --build
18
19# Ejecutar un comando dentro de un servicio que ya está corriendo
20docker compose exec db psql -U datos -d analytics
21
22# Escalar un servicio (crear múltiples instancias)
23docker compose up -d --scale app=3

Tu toolbox completa de docker-compose

Los contenedores hablan entre sí por nombre dentro de la red Docker, y exponen puertos a tu ordenador.

Consejo de senior: guarda tu docker-compose.yml en Git SIEMPRE. Es parte de tu proyecto tanto como el código. Cuando un nuevo miembro llega al equipo, el onboarding ideal es: (1) git clone, (2) docker compose up, (3) a trabajar. Si eso no funciona en menos de 5 minutos, tu docker-compose.yml necesita trabajo.

## ejercicios

[01]

Escribe un docker-compose.yml para analytics

PostgreSQL 16 (user: analyst, password: analytics2024, DB: analytics_prod) y Redis 7 alpine, con puertos estándar.

Cargando editor...
[02]

Añade el ETL con depends_on

El fichero entero: postgres y redis ya resueltos. Rellena el servicio etl: se construye con build, se conecta por nombre de servicio (no localhost) y arranca después de los otros dos.

Cargando editor...
[03]

Comandos del día a día con compose

Levantar, inspeccionar, entrar en la base de datos y limpiar. Los cinco comandos que usarás cada mañana.

Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...