Docker Compose permite definir y ejecutar aplicaciones multi-contenedor con un solo archivo YAML.
Estructura del archivo
Un archivo docker-compose.yml consta de cuatro secciones principales:
# docker-compose.yml
services: # Container definitions
web:
image: nginx:alpine
api:
build: ./api
volumes: # Persistent storage
db-data:
networks: # Custom networks
frontend:
backend:Configuración de servicios
Image vs Build
services:
# Use a pre-built image
db:
image: postgres:16
# Build from Dockerfile
api:
build: ./api
# Build with custom options
web:
build:
context: ./frontend
dockerfile: Dockerfile.prod
args:
NODE_ENV: productionMapeo de puertos
services:
web:
ports:
- "80:80" # host:container
- "443:443"
- "3000:3000" # Expose to localhost
- "127.0.0.1:8080:80" # Bind to specific interfaceVariables de entorno
services:
api:
# Inline environment variables
environment:
- NODE_ENV=production
- DB_HOST=db
- DB_PORT=5432
# From external file
env_file:
- .env
- .env.productionPolíticas de reinicio
services:
web:
restart: "no" # Default: never restart
api:
restart: always # Always restart
db:
restart: unless-stopped # Restart unless manually stopped
worker:
restart: on-failure # Restart only on failure
# restart: on-failure:5 # Max 5 retriesHealth Checks
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30sVolúmenes
services:
db:
volumes:
# Bind mount (host path : container path)
- ./data:/var/lib/postgresql/data
# Named volume
- db-data:/var/lib/postgresql/data
# Read-only mount
- ./config:/etc/app/config:ro
volumes:
db-data: # Named volume declaration
driver: localRedes
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external accessEjemplos de stacks completos
Node.js + MongoDB + Redis
services:
app:
build: .
ports:
- "3000:3000"
environment:
- MONGO_URL=mongodb://mongo:27017/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- mongo
- redis
mongo:
image: mongo:7
volumes:
- mongo-data:/data/db
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
mongo-data:Django + PostgreSQL
services:
web:
build: .
command: gunicorn myapp.wsgi:application --bind 0.0.0.0:8000
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgres://postgres:secret@db:5432/myapp
depends_on:
db:
condition: service_healthy
volumes:
- static:/app/static
db:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: secret
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 5s
retries: 5
volumes:
pg-data:
static:WordPress + MySQL + phpMyAdmin
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_pass
WORDPRESS_DB_NAME: wordpress
volumes:
- wp-content:/var/www/html
depends_on:
- db
db:
image: mysql:8
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_pass
MYSQL_ROOT_PASSWORD: root_secret
volumes:
- db-data:/var/lib/mysql
phpmyadmin:
image: phpmyadmin:latest
ports:
- "8081:80"
environment:
PMA_HOST: db
volumes:
wp-content:
db-data:Comandos CLI esenciales
| Comando | Descripción |
|---|---|
| docker compose up -d | Start services in background |
| docker compose down | Stop and remove containers |
| docker compose down -v | Stop and remove containers + volumes |
| docker compose logs -f | Follow service logs |
| docker compose logs api | Logs for specific service |
| docker compose ps | List running containers |
| docker compose exec api sh | Shell into running container |
| docker compose build | Build/rebuild images |
| docker compose pull | Pull latest images |
| docker compose restart api | Restart specific service |
| docker compose config | Validate and view config |
| docker compose top | Show running processes |
Archivos de entorno (.env)
Docker Compose lee automáticamente un archivo .env:
# .env file
POSTGRES_VERSION=16
POSTGRES_PASSWORD=my_secret_pass
APP_PORT=3000
# docker-compose.yml
services:
db:
image: postgres:${POSTGRES_VERSION}
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
app:
ports:
- "${APP_PORT}:3000"Errores comunes
| Error | Solución |
|---|---|
| Tag `latest` en producción | Usar tags de versión específicos |
| Secrets en docker-compose.yml | Usar archivos .env o Docker secrets |
| No usar volúmenes nombrados | Persisten después de down |
| Sin política de reinicio | Agregar `restart: unless-stopped` |
| Sin límites de recursos | Usar `deploy.resources.limits` |
FAQ
¿Diferencia entre docker-compose y docker compose?
docker-compose (con guión) es la herramienta Python antigua. docker compose (espacio) es el nuevo plugin Go (V2).
¿Cómo persistir datos?
Usar volúmenes nombrados.
¿Cómo se comunican los contenedores?
Comparten una red por defecto y usan nombres de servicio.
¿Se puede usar en producción?
Sí, pero para grandes despliegues considere Kubernetes.