Production Compose: Running Compose in Production
Development Compose files work. But production needs more. Security. Performance. Reliability. Monitoring. That's what production Compose is about.
🎯 The Big Picture​
Think of production Compose like a professional kitchen vs home kitchen. Home kitchen (development) is simple. Professional kitchen (production) has safety standards, quality controls, monitoring systems.
Production Compose files are professional-grade. Secure. Reliable. Monitored. Production-ready.
Development vs Production​
Development Compose:
- Simple configuration
- Bind mounts for code
- Debug mode enabled
- No security hardening
- Works for development
Production Compose:
- Secure configuration
- Named volumes only
- Optimized settings
- Security hardening
- Monitoring enabled
- Production-ready
The difference: Development works. Production is secure and reliable.
Production Best Practices​
1. Use Specific Image Tags​
Don't do this:
services:
app:
image: nginx:latest
Do this:
services:
app:
image: nginx:1.21-alpine
Why: Predictable. Reproducible. No surprises.
2. Use Named Volumes Only​
Don't do this:
services:
app:
volumes:
- ./data:/app/data # Bind mount
Do this:
services:
app:
volumes:
- app-data:/app/data # Named volume
volumes:
app-data:
Why: Portable. Managed. Secure.
3. Set Resource Limits​
Add resource limits:
services:
app:
image: my-app:1.0
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
Why: Prevent resource exhaustion. Fair resource sharing.
4. Use Health Checks​
Add health checks:
services:
app:
image: my-app:1.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Why: Know when service is healthy. Automatic recovery.
5. Set Restart Policies​
Always restart:
services:
app:
image: my-app:1.0
restart: unless-stopped
Options:
no- Don't restartalways- Always restarton-failure- Restart on failureunless-stopped- Restart unless manually stopped
Why: Automatic recovery. High availability.
6. Use Secrets Management​
Don't hard-code secrets:
# BAD
environment:
DB_PASSWORD: my-secret-password
Do use secrets:
# GOOD
secrets:
db_password:
file: ./secrets/db_password.txt
services:
db:
secrets:
- db_password
Or use Docker secrets:
secrets:
db_password:
external: true
services:
db:
secrets:
- db_password
Why: Secure. Not in files. Managed properly.
Real-World Production Compose File​
Let me show you a production-ready file:
services:
# PostgreSQL Database
postgres:
image: postgres:14-alpine
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_DB: ${DB_NAME}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '1.0'
memory: 1G
networks:
- backend
secrets:
- db_password
# Redis Cache
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
networks:
- backend
# Application
app:
build:
context: .
dockerfile: Dockerfile.prod
environment:
NODE_ENV: production
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER}
DB_PASSWORD_FILE: /run/secrets/db_password
DB_NAME: ${DB_NAME}
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
deploy:
replicas: 2
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
networks:
- backend
- frontend
secrets:
- db_password
# Nginx Web Server
nginx:
image: nginx:1.21-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- nginx-cache:/var/cache/nginx
depends_on:
app:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
- frontend
volumes:
postgres-data:
driver: local
redis-data:
driver: local
nginx-cache:
driver: local
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external access
secrets:
db_password:
file: ./secrets/db_password.txt
What makes this production-ready:
- Specific image tags
- Named volumes only
- Resource limits
- Health checks
- Restart policies
- Secrets management
- Network isolation
- Multiple replicas
- Monitoring ready
The Professional Kitchen Analogy​
Think of production Compose like a professional kitchen:
Development: Home kitchen
- Simple setup
- Basic tools
- Works for cooking
Production: Professional kitchen
- Safety standards
- Quality controls
- Monitoring systems
- Professional-grade
Once you see it this way, production Compose makes perfect sense.
Monitoring and Logging​
Add monitoring:
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
ports:
- "9090:9090"
grafana:
image: grafana/grafana
volumes:
- grafana-data:/var/lib/grafana
ports:
- "3000:3000"
depends_on:
- prometheus
Add logging:
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
My Take: Production Compose Strategy​
Here's what I do for production:
Security:
- Secrets management
- Network isolation
- No bind mounts
- Read-only where possible
Reliability:
- Health checks
- Restart policies
- Resource limits
- Multiple replicas
Monitoring:
- Health checks
- Logging
- Metrics
- Alerts
The key: Security first. Reliability second. Monitoring always.
Memory Tip: The Professional Kitchen Analogy​
Production Compose = Professional kitchen
Development: Home kitchen (simple) Production: Professional kitchen (standards, monitoring, quality)
Once you see it this way, production Compose makes perfect sense.
Common Mistakes​
- Using latest tags: Unpredictable
- Bind mounts in production: Not portable, security risk
- No resource limits: Resource exhaustion
- No health checks: Don't know when unhealthy
- Hard-coded secrets: Security risk
Key Takeaways​
- Production needs more than development - Security, reliability, monitoring
- Use specific image tags - Predictable and reproducible
- Use named volumes only - Portable and secure
- Set resource limits - Prevent exhaustion
- Add health checks - Know when healthy
- Use secrets management - Secure configuration
- Monitor everything - Know what's happening
What's Next?​
Congratulations! You've completed the Docker Compose module. Now let's learn about Docker Hub and registries. Next: Docker Hub.
Remember: Production Compose is like a professional kitchen. Security standards. Quality controls. Monitoring systems. Production-ready. Always.