Docker Compose te permite definir y levantar múltiples contenedores con un solo comando usando un archivo YAML.
El problema de manejar todo a mano
Imagina que trabajas en el equipo de tecnología de Liverpool. Tienes una aplicación web, una base de datos PostgreSQL y un servidor de caché Redis. Sin Docker Compose, tendrías que levantar cada contenedor por separado, crear la red manualmente y escribir docenas de flags en la terminal. Si alguien nuevo entra al equipo, tendría que repetir ese proceso completo. Un solo error y nada funciona.
Eso era la realidad antes de Docker Compose. Ahora existe una mejor forma.
El sistema YAML de orquestación local
Docker Compose usa un archivo llamado docker-compose.yml. En ese archivo describes todos tus servicios, redes y volúmenes. Docker los levanta todos juntos con un comando.
Piensa en el archivo como una receta de cocina. La receta lista los ingredientes y los pasos. Cualquiera que tenga la receta puede preparar el mismo platillo exacto. Tu docker-compose.yml es esa receta para tu entorno de desarrollo.
Este sistema tiene un nombre concreto: la arquitectura de servicios declarativa. Declaras qué quieres. Docker Compose se encarga del cómo.
Anatomía de un archivo docker-compose.yml
Veamos la estructura básica:
version: "3.9"
services:
app:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://usuario:clave@db:5432/tienda
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
networks:
- red_interna
db:
image: postgres:15
environment:
- POSTGRES_USER=usuario
- POSTGRES_PASSWORD=clave
- POSTGRES_DB=tienda
volumes:
- datos_db:/var/lib/postgresql/data
networks:
- red_interna
cache:
image: redis:7
networks:
- red_interna
volumes:
datos_db:
networks:
red_interna:
Este archivo define tres servicios: tu aplicación, la base de datos y Redis. Todos comparten la misma red red_interna. Nadie expone puertos innecesarios hacia el exterior.
Los tres comandos que usarás todos los días
Con tu archivo listo, solo necesitas tres comandos.
Levantar todo el entorno:
docker compose up -d
El flag -d corre los contenedores en segundo plano. Tu terminal queda libre.
Ver los logs de todos los servicios:
docker compose logs -f
El flag -f sigue los logs en tiempo real. Muy útil para depurar errores al inicio.
Apagar y limpiar todo:
docker compose down
Este comando detiene y elimina los contenedores. Los volúmenes se conservan a menos que agregues --volumes.
Ejemplo real: sistema de pedidos estilo FEMSA
Supón que estás construyendo un sistema de pedidos para una cadena de tiendas como las de FEMSA. Necesitas tres piezas: una API en Python, una base de datos para guardar pedidos y Redis para guardar sesiones de usuarios.
Tu archivo quedaría así:
version: "3.9"
services:
api_pedidos:
build: ./api
ports:
- "8080:8080"
environment:
- DB_HOST=base_datos
- DB_PORT=5432
- DB_NAME=pedidos
- DB_USER=admin
- DB_PASSWORD=secreto123
- REDIS_HOST=sesiones
depends_on:
- base_datos
- sesiones
networks:
- red_app
base_datos:
image: postgres:15
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secreto123
- POSTGRES_DB=pedidos
volumes:
- volumen_pedidos:/var/lib/postgresql/data
networks:
- red_app
sesiones:
image: redis:7-alpine
networks:
- red_app
volumes:
volumen_pedidos:
networks:
red_app:
Con este archivo, un desarrollador nuevo en el equipo solo necesita clonar el repositorio y ejecutar docker compose up -d. En menos de dos minutos tiene el entorno completo corriendo en su máquina. No importa si usa Windows, Mac o Linux.
La clave de depends_on
La directiva depends_on le dice a Docker Compose el orden en que debe iniciar los servicios. En el ejemplo anterior, api_pedidos espera a que base_datos y sesiones estén listos antes de arrancar.
Ojo: depends_on espera que el contenedor inicie, no que el servicio esté listo. PostgreSQL puede tardar unos segundos en aceptar conexiones después de que el contenedor arranca. Para eso existen healthchecks, que veremos más adelante.
Una solución práctica es que tu aplicación intente reconectarse automáticamente si falla al inicio. La mayoría de los frameworks modernos tienen esta opción.
Variables de entorno con archivo .env
Escribir contraseñas directamente en el docker-compose.yml es un error de seguridad. Si subes ese archivo a GitHub, cualquiera puede ver tus credenciales.
La solución es usar un archivo .env:
# archivo .env
DB_USER=admin
DB_PASSWORD=secreto123
DB_NAME=pedidos
Luego tu docker-compose.yml referencia esas variables así:
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
Agrega .env a tu .gitignore y comparte solo .env.example con los valores vacíos. Tu equipo sabrá qué variables necesita sin exponer datos reales.
Errores comunes al usar Docker Compose
Error 1: El orden de indentación en YAML YAML es muy estricto con los espacios. Un tabulador en lugar de dos espacios rompe todo el archivo. Usa siempre dos espacios para indentar. Muchos editores como VS Code tienen plugins para validar YAML automáticamente.
Error 2: Olvidar el volumen para la base de datos
Si no defines un volumen para PostgreSQL o MySQL, todos tus datos se pierden cuando haces docker compose down. Siempre declara un volumen nombrado para persistir datos. En el ejemplo de FEMSA usamos volumen_pedidos exactamente por esto.
Error 3: Publicar puertos de la base de datos
No agregues ports a tu servicio de base de datos. La comunicación entre api_pedidos y base_datos ocurre dentro de la red red_app. Publicar el puerto 5432 hacia tu máquina es un riesgo de seguridad innecesario en producción.
Error 4: Usar latest como tag de imagen
Escribir image: postgres:latest puede romperte el entorno cuando Postgres lance una nueva versión mayor. Siempre fija la versión: image: postgres:15. Así todos en el equipo usan exactamente la misma versión.
Error 5: No revisar los logs cuando algo falla
Cuando un servicio no arranca, el instinto es editar el archivo y volver a intentar. Pero primero revisa los logs con docker compose logs nombre_del_servicio. El mensaje de error casi siempre te dice exactamente qué está mal.
Comparación: sin Compose vs. con Compose
| Tarea | Sin Docker Compose | Con Docker Compose |
|---|---|---|
| Levantar 3 servicios | 3 comandos largos con flags | docker compose up -d |
| Compartir el entorno | Documentación manual | Un solo archivo YAML |
| Variables de entorno | Copiar y pegar en cada comando | Archivo .env centralizado |
| Apagar todo | docker stop uno por uno |
docker compose down |
| Ver logs | docker logs por servicio |
docker compose logs -f |
La diferencia en productividad es enorme. Un equipo como el de Mercado Libre México que trabaja con decenas de microservicios no podría operar sin orquestación.
Cómo aplicar esto en tu proyecto hoy
Sigue estos pasos en orden:
- Crea un archivo
docker-compose.ymlen la raíz de tu proyecto. - Define cada servicio que necesitas: app, base de datos, caché.
- Crea un archivo
.envcon tus credenciales reales. - Agrega
.enva tu.gitignore. - Ejecuta
docker compose up -dy revisa los logs condocker compose logs -f. - Verifica que tu aplicación responde en el puerto que configuraste.
Empezar con un entorno sencillo de dos servicios es suficiente. Agrega Redis o cualquier otro servicio cuando lo necesites.
Docker Compose convierte un proceso de configuración repetitivo y frágil en un archivo reproducible que cualquier persona de tu equipo puede usar en minutos.