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.yml2services:3 db:4 image: postgres:165 environment:6 POSTGRES_USER: datos7 POSTGRES_PASSWORD: secreto1238 POSTGRES_DB: ventas9 ports:10 - "5432:5432"
Tu primer docker-compose.yml — PostgreSQL en 8 líneas
1# Levantar todos los servicios definidos en docker-compose.yml2docker compose up34# Levantar en background (detached)5docker compose up -d67# Ver qué servicios están corriendo8docker compose ps910# Parar todos los servicios11docker compose down1213# 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-servicio2services:3 db:4 image: postgres:165 environment:6 POSTGRES_USER: datos7 POSTGRES_PASSWORD: secreto1238 POSTGRES_DB: analytics9 ports:10 - "5432:5432"1112 cache:13 image: redis:7-alpine14 ports:15 - "6379:6379"1617 app:18 build: .19 environment:20 DATABASE_URL: postgresql://datos:secreto123@db:5432/analytics21 REDIS_URL: redis://cache:637922 depends_on:23 - db24 - cache25 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 listo2services:3 postgres:4 image: postgres:165 environment:6 POSTGRES_PASSWORD: secreto1237 healthcheck:8 test: ["CMD-SHELL", "pg_isready -U postgres"]9 interval: 3s10 timeout: 3s11 retries: 51213 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 contenedores3# - cache → accesible como "cache" desde otros contenedores4# - app → accesible como "app" desde otros contenedores56# Ejemplo: desde el contenedor "app", PostgreSQL está en:7# host: db (NO localhost)8# port: 5432910# Desde tu ordenador (fuera de Docker), PostgreSQL está en:11# host: localhost12# 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 background2docker compose up -d34# Ver logs de todos los servicios5docker compose logs67# Ver logs de UN servicio específico, en tiempo real8docker compose logs -f db910# Parar servicios sin borrarlos11docker compose stop1213# Parar y borrar contenedores + redes (datos en volúmenes se mantienen)14docker compose down1516# Reconstruir imágenes (cuando cambias tu Dockerfile o código)17docker compose up -d --build1819# Ejecutar un comando dentro de un servicio que ya está corriendo20docker compose exec db psql -U datos -d analytics2122# Escalar un servicio (crear múltiples instancias)23docker compose up -d --scale app=3
Tu toolbox completa de docker-compose
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
Escribe un docker-compose.yml para analytics
PostgreSQL 16 (user: analyst, password: analytics2024, DB: analytics_prod) y Redis 7 alpine, con puertos estándar.
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.
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.
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...