anthropic-skills/docker-compose.production.yml

340 lines
8.6 KiB
YAML

version: '3.8'
# ============================================
# Production Environment Configuration
# Blue-Green Deployment Ready
# ============================================
services:
# Frontend service
frontend:
image: ${REGISTRY:-ghcr.io}/${FRONTEND_IMAGE:-piano-tutor/frontend}:${VERSION:-latest}
container_name: piano-tutor-frontend-${DEPLOYMENT_COLOR:-blue}
restart: always
ports:
- "${FRONTEND_PORT:-3000}:80"
environment:
- NODE_ENV=production
- VITE_API_URL=https://api.piano-tutor.com
- VITE_WS_URL=wss://api.piano-tutor.com
- VITE_SENTRY_DSN=${SENTRY_DSN}
- VITE_ANALYTICS_ID=${ANALYTICS_ID}
networks:
- piano-tutor-network
depends_on:
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
labels:
- "com.piano-tutor.environment=production"
- "com.piano-tutor.service=frontend"
- "com.piano-tutor.version=${VERSION}"
- "com.piano-tutor.deployment-color=${DEPLOYMENT_COLOR:-blue}"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Backend service
backend:
image: ${REGISTRY:-ghcr.io}/${BACKEND_IMAGE:-piano-tutor/backend}:${VERSION:-latest}
container_name: piano-tutor-backend-${DEPLOYMENT_COLOR:-blue}
restart: always
ports:
- "${BACKEND_PORT:-8000}:8000"
environment:
- ENVIRONMENT=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
- JWT_SECRET=${JWT_SECRET}
- CORS_ORIGINS=https://piano-tutor.com,https://www.piano-tutor.com
- LOG_LEVEL=info
- SENTRY_DSN=${SENTRY_DSN}
- MAX_UPLOAD_SIZE=20971520 # 20MB
networks:
- piano-tutor-network
depends_on:
- postgres
- redis
volumes:
- uploads-data:/app/uploads
- logs-data:/app/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: '4.0'
memory: 4G
reservations:
cpus: '1.0'
memory: 1G
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
labels:
- "com.piano-tutor.environment=production"
- "com.piano-tutor.service=backend"
- "com.piano-tutor.version=${VERSION}"
- "com.piano-tutor.deployment-color=${DEPLOYMENT_COLOR:-blue}"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
# PostgreSQL database with replication
postgres:
image: postgres:15-alpine
container_name: piano-tutor-db-production
restart: always
environment:
- POSTGRES_DB=${POSTGRES_DB:-piano_tutor}
- POSTGRES_USER=${POSTGRES_USER:-piano_tutor}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
- postgres-data:/var/lib/postgresql/data
- ./backend/migrations:/docker-entrypoint-initdb.d
- ./backups:/backups
networks:
- piano-tutor-network
command: >
postgres
-c max_connections=200
-c shared_buffers=256MB
-c effective_cache_size=1GB
-c maintenance_work_mem=64MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c default_statistics_target=100
-c random_page_cost=1.1
-c effective_io_concurrency=200
-c work_mem=2621kB
-c min_wal_size=1GB
-c max_wal_size=4GB
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-piano_tutor}"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Redis cache with persistence
redis:
image: redis:7-alpine
container_name: piano-tutor-redis-production
restart: always
command: >
redis-server
--appendonly yes
--appendfsync everysec
--maxmemory 2gb
--maxmemory-policy allkeys-lru
--save 900 1
--save 300 10
--save 60 10000
volumes:
- redis-data:/data
networks:
- piano-tutor-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
deploy:
resources:
limits:
cpus: '1.0'
memory: 2G
reservations:
cpus: '0.25'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Celery worker for async tasks (multiple workers)
celery-worker:
image: ${REGISTRY:-ghcr.io}/${BACKEND_IMAGE:-piano-tutor/backend}:${VERSION:-latest}
container_name: piano-tutor-celery-${DEPLOYMENT_COLOR:-blue}
restart: always
command: >
celery -A app.celery.tasks worker
--loglevel=info
--concurrency=4
--max-tasks-per-child=100
--time-limit=300
--soft-time-limit=240
environment:
- ENVIRONMENT=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
- CELERY_BROKER_URL=${REDIS_URL:-redis://redis:6379/0}
- CELERY_RESULT_BACKEND=${REDIS_URL:-redis://redis:6379/0}
- SENTRY_DSN=${SENTRY_DSN}
networks:
- piano-tutor-network
depends_on:
- postgres
- redis
volumes:
- uploads-data:/app/uploads
- logs-data:/app/logs
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
labels:
- "com.piano-tutor.environment=production"
- "com.piano-tutor.service=celery"
- "com.piano-tutor.version=${VERSION}"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Celery beat for scheduled tasks
celery-beat:
image: ${REGISTRY:-ghcr.io}/${BACKEND_IMAGE:-piano-tutor/backend}:${VERSION:-latest}
container_name: piano-tutor-celery-beat-${DEPLOYMENT_COLOR:-blue}
restart: always
command: celery -A app.celery.tasks beat --loglevel=info
environment:
- ENVIRONMENT=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
- CELERY_BROKER_URL=${REDIS_URL:-redis://redis:6379/0}
networks:
- piano-tutor-network
depends_on:
- postgres
- redis
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Nginx reverse proxy (optional - if not using external load balancer)
nginx:
image: nginx:1.25-alpine
container_name: piano-tutor-nginx-production
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx-production.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- nginx-cache:/var/cache/nginx
networks:
- piano-tutor-network
depends_on:
- frontend
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 3s
retries: 3
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
piano-tutor-network:
driver: bridge
ipam:
config:
- subnet: 172.25.0.0/16
volumes:
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: /var/lib/piano-tutor/postgres
redis-data:
driver: local
driver_opts:
type: none
o: bind
device: /var/lib/piano-tutor/redis
uploads-data:
driver: local
driver_opts:
type: none
o: bind
device: /var/lib/piano-tutor/uploads
logs-data:
driver: local
driver_opts:
type: none
o: bind
device: /var/log/piano-tutor
nginx-cache:
driver: local