services: api: image: ${CALMINER_IMAGE:-calminer-api:latest} build: context: . dockerfile: Dockerfile restart: unless-stopped env_file: - config/setup_production.env environment: UVICORN_WORKERS: ${UVICORN_WORKERS:-2} UVICORN_LOG_LEVEL: ${UVICORN_LOG_LEVEL:-info} command: [ "sh", "-c", "uvicorn main:app --host 0.0.0.0 --port 8000 --workers ${UVICORN_WORKERS:-2} --log-level ${UVICORN_LOG_LEVEL:-info}", ] ports: - "${CALMINER_API_PORT:-8000}:8000" deploy: resources: limits: cpus: ${API_LIMIT_CPUS:-1.0} memory: ${API_LIMIT_MEMORY:-1g} reservations: memory: ${API_RESERVATION_MEMORY:-512m} healthcheck: test: - "CMD-SHELL" - 'python -c "import urllib.request; urllib.request.urlopen(''http://127.0.0.1:8000/health'').read()"' interval: 30s timeout: 10s retries: 5 start_period: 30s networks: - calminer_backend logging: driver: json-file options: max-size: "10m" max-file: "3" labels: - "traefik.enable=true" - "traefik.http.routers.calminer.rule=Host(`${CALMINER_DOMAIN}`)" - "traefik.http.routers.calminer.entrypoints=websecure" - "traefik.http.routers.calminer.tls.certresolver=letsencrypt" - "traefik.http.services.calminer.loadbalancer.server.port=8000" traefik: image: traefik:v3.1 restart: unless-stopped command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL:?TRAEFIK_ACME_EMAIL not set}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" deploy: resources: limits: cpus: ${TRAEFIK_LIMIT_CPUS:-0.5} memory: ${TRAEFIK_LIMIT_MEMORY:-512m} volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - traefik_letsencrypt:/letsencrypt networks: - calminer_backend profiles: - reverse-proxy healthcheck: test: - "CMD" - "traefik" - "healthcheck" - "--entrypoints=web" - "--entrypoints=websecure" interval: 30s timeout: 10s retries: 5 postgres: image: postgres:16 profiles: - local-db restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB:-calminer} POSTGRES_USER: ${POSTGRES_USER:-calminer} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme} LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 POSTGRES_INITDB_ARGS: --encoding=UTF8 --locale=en_US.UTF-8 ports: - "${CALMINER_DB_PORT:-5432}:5432" deploy: resources: limits: cpus: ${POSTGRES_LIMIT_CPUS:-1.0} memory: ${POSTGRES_LIMIT_MEMORY:-2g} reservations: memory: ${POSTGRES_RESERVATION_MEMORY:-1g} volumes: - pg_data_prod:/var/lib/postgresql/data - ./backups:/backups healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-calminer} -d ${POSTGRES_DB:-calminer}", ] interval: 30s timeout: 10s retries: 5 networks: - calminer_backend networks: calminer_backend: name: ${CALMINER_NETWORK:-calminer_backend} driver: bridge volumes: pg_data_prod: traefik_letsencrypt: