Files
michaelschiemer/deployment/docs/reference/docker-compose-production.md
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

10 KiB

Docker Compose Production Configuration

Stand: 2025-11-07
Status: Vollständige Dokumentation der Production-Konfiguration


Übersicht

Dieses Dokument erklärt die Production-spezifische Docker Compose Konfiguration (docker-compose.production.yml). Diese Datei überschreibt die Basis-Konfiguration (docker-compose.base.yml) mit Production-spezifischen Einstellungen.

📖 Verwandte Dokumentation:


Verwendung

# Production Stack starten
docker compose -f docker-compose.base.yml -f docker-compose.production.yml up -d

# Mit .env Datei
docker compose -f docker-compose.base.yml -f docker-compose.production.yml --env-file .env up -d

Wichtig: Die Production-Konfiguration wird immer zusammen mit der Basis-Konfiguration verwendet.


Security Settings

Capabilities

Web Container:

cap_drop:
  - ALL
cap_add:
  - CHOWN
  - DAC_OVERRIDE
  - NET_BIND_SERVICE  # Required for binding to ports 80/443
  - SETGID  # Required for PHP-FPM to switch to www-data
  - SETUID  # Required for PHP-FPM to switch to www-data

PHP Container:

cap_drop:
  - ALL
cap_add:
  - CHOWN
  - DAC_OVERRIDE

Wichtig: SETGID und SETUID sind für den web Container erforderlich, damit PHP-FPM zum www-data User (UID 33) wechseln kann.

Trade-off: no-new-privileges: true ist für den web Container deaktiviert, um PHP-FPM User Switching zu ermöglichen. Dies ist ein bewusster Security Trade-off.

no-new-privileges

Web Container:

# security_opt:
#   - no-new-privileges:true  # ← Kommentiert

PHP Container:

security_opt:
  - no-new-privileges:true  # ← Aktiv

Grund: Der web Container benötigt Privilege Escalation für PHP-FPM, während der php Container nach dem User Switch (gosu) keine weiteren Privileges benötigt.


Environment Variables

env_file vs. environment

env_file (Empfohlen):

env_file:
  - /home/deploy/deployment/stacks/production/.env  # ← Absoluter Pfad

Wichtig: Immer absolute Pfade verwenden, um sicherzustellen, dass die .env Datei gefunden wird, unabhängig vom Working Directory.

environment (Override):

environment:
  - APP_ENV=production
  - APP_DEBUG=false
  - PHP_MEMORY_LIMIT=512M

Reihenfolge: env_file wird zuerst geladen, dann werden environment Variablen als Override angewendet.

Docker Secrets Integration

Pattern: *_FILE Environment Variables

environment:
  - DB_PASSWORD_FILE=/run/secrets/db_user_password
  - REDIS_PASSWORD_FILE=/run/secrets/redis_password
  - APP_KEY_FILE=/run/secrets/app_key
  - VAULT_ENCRYPTION_KEY_FILE=/run/secrets/vault_encryption_key
secrets:
  - db_user_password
  - redis_password
  - app_key
  - vault_encryption_key

Funktionsweise:

  1. Docker Secrets werden in /run/secrets/<secret-name> gemountet
  2. Framework liest automatisch *_FILE Variablen und lädt den Inhalt
  3. Secrets werden nie als Environment Variables exponiert

Siehe auch: Application Stack Deployment - Secret Handling


Entrypoint Overrides

Queue Worker

queue-worker:
  entrypoint: ""  # ← Leerer Entrypoint überschreibt Image Entrypoint
  command: ["php", "/var/www/html/worker.php"]

Grund: Der Image Entrypoint (/usr/local/bin/entrypoint.sh) startet PHP-FPM und Nginx. Der Queue Worker benötigt nur PHP CLI.

Scheduler

scheduler:
  entrypoint: ""  # ← Leerer Entrypoint überschreibt Image Entrypoint
  command: php console.php scheduler:run

Grund: Gleicher Grund wie Queue Worker - nur PHP CLI erforderlich.

Siehe auch: Troubleshooting Guide - Container Entrypoint Override


Health Checks

Web Container

healthcheck:
  test: ["CMD", "curl", "-f", "https://localhost/health"]
  interval: 15s
  timeout: 5s
  retries: 5
  start_period: 30s

Funktionsweise:

  • Prüft /health Endpoint via HTTPS
  • Startet nach 30 Sekunden (Container Startup Time)
  • Prüft alle 15 Sekunden
  • 5 Retries bei Fehlschlag

PHP Container

healthcheck:
  test: ["CMD", "php", "-v"]
  interval: 15s
  timeout: 5s
  retries: 5
  start_period: 30s

Funktionsweise:

  • Prüft PHP Verfügbarkeit
  • Einfacher Check für Container-Health

Scheduler

healthcheck:
  test: ["CMD-SHELL", "php -r 'exit(0);' && test -f /var/www/html/console.php || exit 1"]
  interval: 60s
  timeout: 10s
  retries: 3
  start_period: 30s

Funktionsweise:

  • Prüft PHP Verfügbarkeit und console.php Existenz
  • Längeres Interval (60s) da Scheduler weniger kritisch

Volume Mounts

Application Code

volumes:
  - /home/deploy/michaelschiemer/current:/var/www/html:rw

Wichtig:

  • Absoluter Pfad auf dem Host
  • Read-Write für storage/ und var/ Verzeichnisse
  • Code wird via rsync oder git synchronisiert

Siehe auch: Code Deployment Workflow

Certbot Volumes

volumes:
  - certbot-conf:/etc/letsencrypt:ro
  - certbot-www:/var/www/certbot:ro

Funktionsweise:

  • certbot-conf: SSL Zertifikate (Read-Only für Web Container)
  • certbot-www: Webroot für Let's Encrypt Challenge

Resource Limits

Web Container

deploy:
  resources:
    limits:
      memory: 512M
      cpus: '1.0'
    reservations:
      memory: 256M
      cpus: '0.5'

Grund: Nginx ist leichtgewichtig, benötigt wenig Ressourcen.

PHP Container

deploy:
  resources:
    limits:
      memory: 1G
      cpus: '2.0'
    reservations:
      memory: 512M
      cpus: '1.0'

Grund: PHP-FPM benötigt mehr Ressourcen für Request-Verarbeitung.

Queue Worker

deploy:
  resources:
    limits:
      memory: 2G
      cpus: '2.0'
    reservations:
      memory: 1G
      cpus: '1.0'

Grund: Queue Worker verarbeitet lange Jobs, benötigt mehr Memory.

Scheduler

deploy:
  resources:
    limits:
      memory: 512M
      cpus: '0.5'
    reservations:
      memory: 256M
      cpus: '0.25'

Grund: Scheduler läuft periodisch, benötigt wenig Ressourcen.


Logging

JSON Logging mit Rotation

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "5"
    compress: "true"
    labels: "service,environment"

Funktionsweise:

  • max-size: Maximale Größe pro Log-Datei
  • max-file: Anzahl der Log-Dateien (Rotation)
  • compress: Komprimierung alter Log-Dateien
  • labels: Metadaten für Log-Aggregation

Beispiel: Bei 5 Dateien à 10MB = max. 50MB Log-Speicher pro Container.


Restart Policies

restart: always

Funktionsweise:

  • Container wird automatisch neu gestartet bei:
    • Container Exit (auch bei Fehlern)
    • Docker Daemon Restart
    • System Reboot

Alternative Policies:

  • no: Kein automatischer Restart
  • on-failure: Nur bei Fehlern
  • unless-stopped: Immer, außer manuell gestoppt

Dependencies

Service Dependencies

depends_on:
  php:
    condition: service_healthy
  certbot:
    condition: service_started

Funktionsweise:

  • service_healthy: Wartet auf erfolgreichen Health Check
  • service_started: Wartet nur auf Container Start

Wichtig: queue-worker und scheduler warten auf php Container Health, da sie die gleiche Codebase verwenden.


External Services

PostgreSQL

# Database service removed - using external PostgreSQL Stack
# Connection via app-internal network using docker-compose.postgres-override.yml

Grund: PostgreSQL läuft in separatem Stack (deployment/stacks/postgresql/) für bessere Isolation.

Redis

# Redis service removed - using external Redis Stack
# Connection via app-internal network using docker-compose.redis-override.yml

Grund: Redis läuft in separatem Stack (deployment/stacks/redis/) für bessere Isolation.

Verbindung: Via app-internal Network (siehe docker-compose.base.yml).


Networks

Cache Network

networks:
  cache:
    internal: true  # Cache network is internal in production

Funktionsweise:

  • Internal: Keine externe Verbindung möglich
  • Nur für Container-zu-Container Kommunikation
  • Erhöht Security (Redis nicht von außen erreichbar)

Best Practices

1. Absolute Pfade für env_file

Richtig:

env_file:
  - /home/deploy/deployment/stacks/production/.env

Falsch:

env_file:
  - .env  # Relativer Pfad - funktioniert nur im richtigen Verzeichnis

2. Entrypoint Override für CLI-Container

Richtig:

queue-worker:
  entrypoint: ""
  command: ["php", "/var/www/html/worker.php"]

Falsch:

queue-worker:
  # Kein Entrypoint Override - startet PHP-FPM/Nginx unnötig

3. Capabilities für PHP-FPM

Richtig:

web:
  cap_add:
    - SETGID
    - SETUID

Falsch:

web:
  security_opt:
    - no-new-privileges:true  # Verhindert PHP-FPM User Switching

Troubleshooting

Problem: Container startet nicht / unhealthy

Lösung: Siehe Troubleshooting Guide

Häufige Ursachen:

  • Missing Environment Variables → env_file mit absolutem Pfad prüfen
  • PHP-FPM Permission Errors → Capabilities (SETGID/SETUID) prüfen
  • Missing Application Code → Code-Sync prüfen

Problem: Environment Variables werden nicht geladen

Ursache: Relativer Pfad in env_file

Lösung: Absoluten Pfad verwenden:

env_file:
  - /home/deploy/deployment/stacks/production/.env

Problem: Queue Worker startet PHP-FPM

Ursache: Entrypoint Override fehlt

Lösung:

queue-worker:
  entrypoint: ""
  command: ["php", "/var/www/html/worker.php"]

Referenz