YAML para Docker Compose: Patrones de Configuración y Consejos
Docker Compose usa YAML para definir aplicaciones multi-contenedor. Un docker-compose.yml bien estructurado es la diferencia entre un entorno de desarrollo fluido y horas depurando problemas de contenedores. Esta guía cubre patrones esenciales y errores comunes.
Estructura Básica
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- api
api:
build: ./api
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://db:5432/myapp
depends_on:
- db
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: secret
volumes:
pgdata:
Variables de Entorno
En Línea
services:
api:
environment:
NODE_ENV: production
PORT: "3000"
DEBUG: "false"
Desde Archivo
services:
api:
env_file:
- .env
- .env.local # Overrides .env values
Sustitución de Variables
Referencia variables de entorno del host:
services:
api:
image: myapp:${TAG:-latest} # Default to "latest"
environment:
API_KEY: ${API_KEY} # Required - fails if not set
LOG_LEVEL: ${LOG_LEVEL:-info} # Default to "info"
Redes
Redes Personalizadas
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
internal: true # No external access
Los servicios en la misma red pueden comunicarse entre sí por nombre de servicio. El servicio db solo es accesible desde api, no desde web.
Mapeo de Puertos
ports:
- "8080:80" # host:container
- "443:443"
- "127.0.0.1:3000:3000" # Bind to localhost only
- "3000" # Random host port
Volúmenes
Volúmenes con Nombre (Persistentes)
services:
db:
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
driver: local
Montajes Bind (Desarrollo)
services:
api:
volumes:
- ./src:/app/src # Source code
- /app/node_modules # Anonymous volume (prevent override)
El patrón de volumen anónimo (/app/node_modules) evita que el montaje bind del host sobreescriba las dependencias instaladas en el contenedor.
Verificaciones de Salud
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
api:
depends_on:
db:
condition: service_healthy
Esto asegura que api solo se inicie después de que db pase las verificaciones de salud — no solo cuando el contenedor arranque.
Campos de Extensión (Patrones DRY)
Usa campos con prefijo x- con anchors YAML para reducir la repetición:
x-common: &common
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
x-env: &common-env
TZ: UTC
LOG_FORMAT: json
services:
api:
<<: *common
build: ./api
environment:
<<: *common-env
PORT: "3000"
worker:
<<: *common
build: ./worker
environment:
<<: *common-env
QUEUE: default
Para más información sobre anchors YAML, consulta nuestra guía de anchors y aliases YAML.
Compose Multi-Etapa
Desarrollo vs Producción
# docker-compose.yml (base)
services:
api:
build: ./api
environment:
DATABASE_URL: postgres://db:5432/myapp
# docker-compose.override.yml (dev - auto-loaded)
services:
api:
volumes:
- ./api/src:/app/src
environment:
NODE_ENV: development
DEBUG: "true"
ports:
- "3000:3000"
- "9229:9229" # Debug port
# docker-compose.prod.yml
services:
api:
environment:
NODE_ENV: production
deploy:
replicas: 3
# Development (auto-loads override)
docker compose up
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
Errores Comunes
1. Números de Puerto Sin Comillas
# RISKY - YAML interprets 80:80 as a base-60 number
ports:
- 80:80
# SAFE - always quote
ports:
- "80:80"
2. Variables de Entorno Booleanas
# WRONG - YAML converts to boolean
environment:
DEBUG: true # Becomes Python True, not string "true"
# CORRECT - quote all env values
environment:
DEBUG: "true"
3. Temporización de depends_on
depends_on solo espera a que el contenedor inicie, no a que esté listo:
# Container starts but DB might not be ready
depends_on:
- db
# Wait for health check
depends_on:
db:
condition: service_healthy
Valida tus archivos Docker Compose con nuestro Validador YAML.
FAQ
¿Cuál es la diferencia entre docker-compose.yml y compose.yml?
Ambos nombres de archivo funcionan. compose.yml es la convención más reciente recomendada por Docker. docker-compose.yml es el nombre heredado. Docker Compose v2+ busca ambos, prefiriendo compose.yml si ambos existen. Para proyectos nuevos, usa compose.yml.
¿Debería usar Docker Compose en producción?
Docker Compose es excelente para desarrollo y despliegues simples. Para producción a escala, considera Docker Swarm (usa archivos Compose de forma nativa) o Kubernetes. La ventaja de Compose es que tu configuración de desarrollo informa directamente a producción, reduciendo las diferencias entre entornos.
Recursos Relacionados
- Validador YAML — Valida YAML de Docker Compose
- Anchors y Aliases YAML — Patrones de configuración DRY
- Tutorial de Sintaxis YAML — Fundamentos de YAML