Production Docker Compose
Configure Docker Compose for production environments.
Production Checklist
- Resource limits
- Health checks
- Restart policies
- Logging configuration
- Security hardening
- Secrets management
- Network isolation
Base Production Configuration
# docker-compose.prod.yml
services:
api:
image: myregistry/api:1.0.0
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
networks:
- frontend
- backend
networks:
frontend:
backend:
internal: trueComplete Production Stack
services:
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- nginx-cache:/var/cache/nginx
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
- frontend
depends_on:
api:
condition: service_healthy
api:
image: ${REGISTRY}/api:${VERSION}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
replicas: 2
environment:
- NODE_ENV=production
secrets:
- db_password
- jwt_secret
logging:
driver: json-file
options:
max-size: "100m"
max-file: "5"
networks:
- frontend
- backend
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
networks:
- backend
redis:
image: redis:alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis-data:/data
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
networks:
- backend
volumes:
postgres-data:
redis-data:
nginx-cache:
networks:
frontend:
backend:
internal: true
secrets:
db_password:
file: ./secrets/db_password.txt
jwt_secret:
file: ./secrets/jwt_secret.txtOverride Files Strategy
# Base + environment specific
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d# docker-compose.yml (base)
services:
api:
build: .
environment:
- NODE_ENV=${NODE_ENV:-development}
# docker-compose.prod.yml (production override)
services:
api:
image: registry/api:${VERSION}
build: !reset null # Don't build in prod
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1.0'
memory: 1GDeployment Script
#!/bin/bash
set -e
# Pull latest images
docker compose -f docker-compose.yml -f docker-compose.prod.yml pull
# Deploy with zero downtime
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-build
# Cleanup old images
docker image prune -f
# Verify deployment
docker compose ps
docker compose logs --tail=50 apiMonitoring Integration
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- monitoring
grafana:
image: grafana/grafana:latest
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring
- frontend
networks:
monitoring:
internal: true - docker compose
- production
- deployment
- scaling
- monitoring