name: pechub # ───────────────────────────────────────────────────────────────────────────── # docker-compose.prod.yml – Configurazione PRODUZIONE # # Differenze rispetto a docker-compose.yml (sviluppo): # - Backend: uvicorn con N worker, senza --reload, senza volume mount # - Frontend: build statica servita da nginx (niente Vite dev server) # - Porte DB, Redis, MinIO NON esposte sull'host (solo rete interna) # - Tutte le credenziali lette da .env (obbligatorie) # - MinIO console disabilitata (porta 9001 non esposta) # - GreenMail e pgadmin esclusi # - Healthcheck ottimizzati per produzione # # Utilizzo: # docker compose -f docker-compose.prod.yml up -d # ───────────────────────────────────────────────────────────────────────────── services: # ─── PostgreSQL 16 ────────────────────────────────────────────────────────── db: image: postgres:16-alpine restart: always environment: POSTGRES_DB: ${POSTGRES_DB:-pechub} POSTGRES_USER: ${POSTGRES_USER:-pechub} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD non impostata} # PRODUZIONE: porte DB non esposte sull'host volumes: - postgres_data:/var/lib/postgresql/data - ./database/init:/docker-entrypoint-initdb.d/init:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-pechub} -d ${POSTGRES_DB:-pechub}"] interval: 10s timeout: 5s retries: 10 start_period: 30s networks: - pechub_net # ─── Redis 7 ──────────────────────────────────────────────────────────────── redis: image: redis:7-alpine restart: always command: redis-server /usr/local/etc/redis/redis.conf # PRODUZIONE: porta Redis non esposta sull'host volumes: - redis_data:/data - ./infra/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 10 start_period: 10s networks: - pechub_net # ─── MinIO (Object Storage S3-compatible) ─────────────────────────────────── minio: image: minio/minio:latest restart: always # PRODUZIONE: solo API S3 (9000), console (9001) non esposta command: server /data environment: MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY non impostata} MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY non impostata} volumes: - minio_data:/data healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 15s timeout: 5s retries: 5 start_period: 20s networks: - pechub_net # ─── MinIO bucket initializer ─────────────────────────────────────────────── minio-init: image: minio/mc:latest depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set local http://minio:9000 ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY} && mc mb --ignore-existing local/${MINIO_BUCKET:-pechub} && mc anonymous set none local/${MINIO_BUCKET:-pechub} && echo 'MinIO bucket creato' " networks: - pechub_net # ─── Backend FastAPI (produzione) ──────────────────────────────────────────── backend: build: context: ./backend dockerfile: Dockerfile restart: always env_file: .env environment: APP_ENV: production APP_DEBUG: "false" LOG_JSON: "true" DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-pechub}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-pechub} DATABASE_URL_SYNC: postgresql://${POSTGRES_USER:-pechub}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-pechub} REDIS_URL: redis://redis:6379/0 MINIO_ENDPOINT: minio:9000 # PRODUZIONE: N worker, senza --reload, senza volume mount del codice command: > uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4 --loop uvloop --http httptools --access-log --log-level warning depends_on: db: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 15s timeout: 5s retries: 5 start_period: 30s networks: - pechub_net # ─── Frontend React (build statica servita da nginx) ───────────────────────── frontend: build: context: ./frontend dockerfile: Dockerfile target: runner # stage nginx con build statica (dist/) restart: always expose: - "3000" depends_on: - backend networks: - pechub_net # ─── Nginx reverse proxy (produzione) ──────────────────────────────────────── nginx: image: nginx:alpine restart: always ports: - "80:80" # Per HTTPS: decommentare e configurare certificati # - "443:443" volumes: - ./infra/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./infra/nginx/conf.d/pecflow.prod.conf:/etc/nginx/conf.d/default.conf:ro # Per HTTPS: montare i certificati # - /etc/letsencrypt:/etc/letsencrypt:ro depends_on: backend: condition: service_healthy frontend: condition: service_started networks: - pechub_net # ─── Worker IMAP Sync (arq) ────────────────────────────────────────────────── worker: build: context: ./worker dockerfile: Dockerfile restart: always env_file: .env environment: APP_ENV: production LOG_LEVEL: WARNING DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-pechub}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-pechub} REDIS_URL: redis://redis:6379/0 MINIO_ENDPOINT: minio:9000 # PRODUZIONE: niente volume mount del codice depends_on: db: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy networks: - pechub_net volumes: postgres_data: redis_data: minio_data: networks: pechub_net: driver: bridge