Docker Compose Advanced: Multi-Container Applications
Master Docker Compose for complex multi-container applications with advanced configuration, networking, and orchestration.
Docker Compose Advanced: Multi-Container Applications
Docker Compose is a powerful tool for defining and running multi-container Docker applications. This advanced guide covers complex scenarios, networking, and production-ready configurations.
Advanced Docker Compose Features
Environment Variables
Use environment variables for configuration:
version: '3.8'
services:
web:
build: .
environment:
- NODE_ENV=${NODE_ENV:-development}
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
env_file:
- .env
- .env.local
Volume Management
Advanced volume configurations:
version: '3.8'
services:
web:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- static_files:/var/www/static
- logs:/var/log/nginx
database:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
postgres_data:
driver: local
static_files:
driver: local
logs:
driver: local
Networking
Custom network configurations:
version: '3.8'
services:
web:
build: .
networks:
- frontend
- backend
api:
build: ./api
networks:
- backend
- database
db:
image: postgres:13
networks:
- database
networks:
frontend:
driver: bridge
backend:
driver: bridge
database:
driver: bridge
Production-Ready Configurations
Health Checks
Implement health checks for reliability:
version: '3.8'
services:
web:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
database:
image: postgres:13
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 30s
timeout: 10s
retries: 3
Resource Limits
Set resource constraints:
version: '3.8'
services:
web:
build: .
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
database:
image: postgres:13
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
Restart Policies
Configure restart behavior:
version: '3.8'
services:
web:
build: .
restart: unless-stopped
database:
image: postgres:13
restart: on-failure:3
cache:
image: redis:6
restart: always
Complex Application Examples
Full-Stack Application
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
environment:
- REACT_APP_API_URL=http://backend:5000
depends_on:
- backend
backend:
build: ./backend
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://user:password@database:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
- database
- cache
database:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
cache:
image: redis:6
volumes:
- redis_data:/data
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- frontend
- backend
volumes:
postgres_data:
redis_data:
Microservices Architecture
version: '3.8'
services:
api-gateway:
build: ./api-gateway
ports:
- "8080:8080"
environment:
- USER_SERVICE_URL=http://user-service:3001
- ORDER_SERVICE_URL=http://order-service:3002
- PRODUCT_SERVICE_URL=http://product-service:3003
user-service:
build: ./user-service
environment:
- DATABASE_URL=postgresql://user:password@user-db:5432/users
depends_on:
- user-db
order-service:
build: ./order-service
environment:
- DATABASE_URL=postgresql://user:password@order-db:5432/orders
depends_on:
- order-db
product-service:
build: ./product-service
environment:
- DATABASE_URL=postgresql://user:password@product-db:5432/products
depends_on:
- product-db
user-db:
image: postgres:13
environment:
POSTGRES_DB: users
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- user_data:/var/lib/postgresql/data
order-db:
image: postgres:13
environment:
POSTGRES_DB: orders
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- order_data:/var/lib/postgresql/data
product-db:
image: postgres:13
environment:
POSTGRES_DB: products
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- product_data:/var/lib/postgresql/data
volumes:
user_data:
order_data:
product_data:
Development vs Production
Development Configuration
# docker-compose.dev.yml
version: '3.8'
services:
web:
build: .
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
ports:
- "3000:3000"
database:
image: postgres:13
environment:
POSTGRES_DB: myapp_dev
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
ports:
- "5432:5432"
Production Configuration
# docker-compose.prod.yml
version: '3.8'
services:
web:
build: .
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
restart: unless-stopped
database:
image: postgres:13
environment:
POSTGRES_DB: myapp_prod
POSTGRES_USER: prod
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
Best Practices
1. Use Multiple Compose Files
# Development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# Production
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
2. Environment-Specific Configurations
# docker-compose.override.yml (automatically loaded)
version: '3.8'
services:
web:
volumes:
- .:/app
environment:
- DEBUG=true
3. Secrets Management
version: '3.8'
services:
web:
build: .
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true
Monitoring and Logging
Log Configuration
version: '3.8'
services:
web:
build: .
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
database:
image: postgres:13
logging:
driver: "syslog"
options:
syslog-address: "tcp://logs:514"
Health Monitoring
version: '3.8'
services:
web:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
Troubleshooting
Common Issues
Port Conflicts
bash# Check what's using the port lsof -i :3000 # Use different port docker-compose up -p 3001Volume Issues
bash# List volumes docker volume ls # Remove unused volumes docker volume pruneNetwork Issues
bash# List networks docker network ls # Inspect network docker network inspect <network_name>
Debugging Commands
# View logs
docker-compose logs -f web
# Execute commands in running container
docker-compose exec web bash
# Scale services
docker-compose up --scale web=3
# View service status
docker-compose ps
Conclusion
Docker Compose is essential for managing complex multi-container applications. By following these advanced patterns and best practices, you can create robust, scalable, and maintainable containerized applications.
Remember to:
- Use environment-specific configurations
- Implement proper health checks
- Set resource limits
- Configure logging and monitoring
- Follow security best practices
Happy composing! 🐳