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
- 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
494 lines
10 KiB
Markdown
494 lines
10 KiB
Markdown
# 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:**
|
|
- [Application Stack Deployment](./application-stack.md) - Detaillierter Deployment-Ablauf
|
|
- [Initial Deployment Guide](../guides/initial-deployment-guide.md) - Schritt-für-Schritt Anleitung
|
|
- [Troubleshooting Guide](../troubleshooting/initial-deployment-issues.md) - Häufige Probleme und Lösungen
|
|
|
|
---
|
|
|
|
## Verwendung
|
|
|
|
```bash
|
|
# 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:**
|
|
```yaml
|
|
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:**
|
|
```yaml
|
|
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:**
|
|
```yaml
|
|
# security_opt:
|
|
# - no-new-privileges:true # ← Kommentiert
|
|
```
|
|
|
|
**PHP Container:**
|
|
```yaml
|
|
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):**
|
|
```yaml
|
|
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):**
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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](./application-stack.md) - Secret Handling
|
|
|
|
---
|
|
|
|
## Entrypoint Overrides
|
|
|
|
### Queue Worker
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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](../troubleshooting/initial-deployment-issues.md) - Container Entrypoint Override
|
|
|
|
---
|
|
|
|
## Health Checks
|
|
|
|
### Web Container
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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](../guides/code-deployment-workflow.md)
|
|
|
|
### Certbot Volumes
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 512M
|
|
cpus: '1.0'
|
|
reservations:
|
|
memory: 256M
|
|
cpus: '0.5'
|
|
```
|
|
|
|
**Grund:** Nginx ist leichtgewichtig, benötigt wenig Ressourcen.
|
|
|
|
### PHP Container
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```yaml
|
|
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:**
|
|
```yaml
|
|
env_file:
|
|
- /home/deploy/deployment/stacks/production/.env
|
|
```
|
|
|
|
**❌ Falsch:**
|
|
```yaml
|
|
env_file:
|
|
- .env # Relativer Pfad - funktioniert nur im richtigen Verzeichnis
|
|
```
|
|
|
|
### 2. Entrypoint Override für CLI-Container
|
|
|
|
**✅ Richtig:**
|
|
```yaml
|
|
queue-worker:
|
|
entrypoint: ""
|
|
command: ["php", "/var/www/html/worker.php"]
|
|
```
|
|
|
|
**❌ Falsch:**
|
|
```yaml
|
|
queue-worker:
|
|
# Kein Entrypoint Override - startet PHP-FPM/Nginx unnötig
|
|
```
|
|
|
|
### 3. Capabilities für PHP-FPM
|
|
|
|
**✅ Richtig:**
|
|
```yaml
|
|
web:
|
|
cap_add:
|
|
- SETGID
|
|
- SETUID
|
|
```
|
|
|
|
**❌ Falsch:**
|
|
```yaml
|
|
web:
|
|
security_opt:
|
|
- no-new-privileges:true # Verhindert PHP-FPM User Switching
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Problem: Container startet nicht / unhealthy
|
|
|
|
**Lösung:** Siehe [Troubleshooting Guide](../troubleshooting/initial-deployment-issues.md)
|
|
|
|
**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:
|
|
```yaml
|
|
env_file:
|
|
- /home/deploy/deployment/stacks/production/.env
|
|
```
|
|
|
|
### Problem: Queue Worker startet PHP-FPM
|
|
|
|
**Ursache:** Entrypoint Override fehlt
|
|
|
|
**Lösung:**
|
|
```yaml
|
|
queue-worker:
|
|
entrypoint: ""
|
|
command: ["php", "/var/www/html/worker.php"]
|
|
```
|
|
|
|
---
|
|
|
|
## Referenz
|
|
|
|
- [Application Stack Deployment](./application-stack.md) - Detaillierter Ablauf
|
|
- [Initial Deployment Guide](../guides/initial-deployment-guide.md) - Schritt-für-Schritt Anleitung
|
|
- [Troubleshooting Guide](../troubleshooting/initial-deployment-issues.md) - Probleme und Lösungen
|
|
- [Code Deployment Workflow](../guides/code-deployment-workflow.md) - Code-Synchronisation
|
|
|