version: "3.9" # Deployment profile with dedicated frontend container. # Use this when you want an external nginx (or another edge proxy) # to only reverse-proxy traffic to the internal frontend service. services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: training POSTGRES_USER: training POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U training"] interval: 5s timeout: 5s retries: 10 networks: - internal redis: image: redis:7-alpine restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 10 networks: - internal web: image: training-software:local build: context: . restart: unless-stopped env_file: - .env command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4 --timeout 60 volumes: - staticfiles:/app/staticfiles environment: DJANGO_SETTINGS_MODULE: config.settings.prod DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:?DJANGO_SECRET_KEY is required} DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:?DJANGO_ALLOWED_HOSTS is required} DATABASE_URL: "postgres://training:${DB_PASSWORD}@db:5432/training" REDIS_URL: "redis://redis:6379/0" SECURE_SSL_REDIRECT: ${SECURE_SSL_REDIRECT:-false} OIDC_RP_CLIENT_ID: ${OIDC_RP_CLIENT_ID:-} OIDC_RP_CLIENT_SECRET: ${OIDC_RP_CLIENT_SECRET:-} OIDC_OP_AUTHORIZATION_ENDPOINT: ${OIDC_OP_AUTHORIZATION_ENDPOINT:-} OIDC_OP_TOKEN_ENDPOINT: ${OIDC_OP_TOKEN_ENDPOINT:-} OIDC_OP_USER_ENDPOINT: ${OIDC_OP_USER_ENDPOINT:-} OIDC_OP_JWKS_ENDPOINT: ${OIDC_OP_JWKS_ENDPOINT:-} depends_on: db: condition: service_healthy redis: condition: service_healthy networks: - internal celery: image: training-software:local build: context: . restart: unless-stopped env_file: - .env command: celery -A config worker --loglevel=info environment: DJANGO_SETTINGS_MODULE: config.settings.prod DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS} DATABASE_URL: "postgres://training:${DB_PASSWORD}@db:5432/training" REDIS_URL: "redis://redis:6379/0" SECURE_SSL_REDIRECT: "false" OIDC_RP_CLIENT_ID: ${OIDC_RP_CLIENT_ID:-} OIDC_RP_CLIENT_SECRET: ${OIDC_RP_CLIENT_SECRET:-} OIDC_OP_AUTHORIZATION_ENDPOINT: ${OIDC_OP_AUTHORIZATION_ENDPOINT:-} OIDC_OP_TOKEN_ENDPOINT: ${OIDC_OP_TOKEN_ENDPOINT:-} OIDC_OP_USER_ENDPOINT: ${OIDC_OP_USER_ENDPOINT:-} OIDC_OP_JWKS_ENDPOINT: ${OIDC_OP_JWKS_ENDPOINT:-} depends_on: db: condition: service_healthy redis: condition: service_healthy networks: - internal celery-beat: image: training-software:local build: context: . restart: unless-stopped env_file: - .env command: celery -A config beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler environment: DJANGO_SETTINGS_MODULE: config.settings.prod DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS} DATABASE_URL: "postgres://training:${DB_PASSWORD}@db:5432/training" REDIS_URL: "redis://redis:6379/0" SECURE_SSL_REDIRECT: "false" OIDC_RP_CLIENT_ID: ${OIDC_RP_CLIENT_ID:-} OIDC_RP_CLIENT_SECRET: ${OIDC_RP_CLIENT_SECRET:-} OIDC_OP_AUTHORIZATION_ENDPOINT: ${OIDC_OP_AUTHORIZATION_ENDPOINT:-} OIDC_OP_TOKEN_ENDPOINT: ${OIDC_OP_TOKEN_ENDPOINT:-} OIDC_OP_USER_ENDPOINT: ${OIDC_OP_USER_ENDPOINT:-} OIDC_OP_JWKS_ENDPOINT: ${OIDC_OP_JWKS_ENDPOINT:-} depends_on: db: condition: service_healthy redis: condition: service_healthy networks: - internal frontend: build: context: . dockerfile: frontend/Dockerfile restart: unless-stopped depends_on: - web environment: FRONTEND_API_BASE_URL: ${FRONTEND_API_BASE_URL:-http://localhost:8000} ports: - "${FRONTEND_PORT:-8080}:80" networks: - internal volumes: postgres_data: staticfiles: networks: internal: driver: bridge