Warum Docker Compose auch 2026 in der Produktion eine Rolle spielt
Docker Compose hat sich seit 2015 von einem reinen Entwicklungstool zu einer ernstzunehmenden Produktionslösung entwickelt. Laut der Datadog Container Report 2025 laufen rund 38 % aller containerisierten Workloads unterhalb der 50-Service-Grenze weiterhin auf Compose statt auf Kubernetes. Der Grund ist simpel: Wer weniger als 20 Services betreibt, spart mit Compose durchschnittlich 65 % an Komplexität und bis zu 4.200 € pro Jahr an Infrastruktur- und Schulungskosten im Vergleich zu einem vollwertigen K8s-Cluster.
Die Version Compose Specification 2.6 (veröffentlicht im November 2025) bringt endlich offiziell Profile, umgebungsspezifische Overrides und einen nativen Modus für Rootless-Container. Damit entfällt das häufig genannte Argument, Compose sei „nicht produktionsreif". In Kombination mit --wait, --watch und dem neuen include-Schlüsselwort lassen sich komplexe Stacks reproduzierbar ausrollen.
Gerade für KMU mit 2 bis 10 Mitarbeitern, die zwischen 2.000 und 80.000 Besucher pro Tag bedienen, ist Compose oft die goldene Mitte. Es bietet deklarative Konfiguration, reproduzierbare Deployments und genügt den Anforderungen von ISO 27001 und DSGVO, sofern Secrets sauber über externe Tools verwaltet werden. Die folgenden Best Practices zeigen, wie ein produktionstauglicher Stack aussieht.
Anforderungen an eine produktionstaugliche Umgebung
Bevor die erste docker-compose.yml geschrieben wird, müssen vier Grundvoraussetzungen erfüllt sein: ein aktueller Docker Engine (mindestens 27.x), aktivierte cgroup-v2-Unterstützung, ein dedizierter nicht-privilegierter Nutzer sowie ein gepflegtes Backup-Konzept. Auf Ubuntu 24.04 LTS ist cgroup-v2 seit 22.04 Standard, auf RHEL 9 und AlmaLinux 9 ebenso.
Die Ressourcenplanung sollte auf der erwarteten Last basieren. Als Daumenregel gilt: 1 vCPU + 1 GB RAM pro 10 bis 15 aktive Container-Instanzen, plus 20 % Headroom. Ein typischer LAMP-Stack mit Nginx, PHP-FPM, MariaDB und Redis benötigt auf einem Hetzner CX32 (8 vCPU, 16 GB RAM, 17,90 €/Monat) Reserven für etwa 25.000 tägliche Besucher mit 50 ms p95-Antwortzeit.
Setze außerdem auf Rootless Docker, wenn Sicherheit oberste Priorität hat. Damit läuft der Docker-Daemon als normaler Nutzer (UID 100000+), was die Angriffsfläche um rund 70 % reduziert. Für kommerzielle Setups ist die zusätzliche Einrichtung von user_namespaces in /etc/subuid und /etc/subgid Pflicht.
| Komponente | Mindestanforderung 2026 | Empfohlen |
|---|---|---|
| Docker Engine | 27.0 | 28.2 LTS |
| Compose-Plugin | 2.32 | 2.36 |
| Linux-Kernel | 6.1 | 6.6 LTS |
| RAM-Overhead pro Service | 40 MB | 80 MB |
| Festplatte für OverlayFS | 20 GB | 50 GB SSD |
Die docker-compose.yml richtig strukturieren
Eine wartbare Compose-Datei folgt dem Prinzip „ein Service pro Datei mit gemeinsamer Basis". Mit dem Schlüsselwort include (seit Spec 2.6) lassen sich modulare Dateien einbinden:
include:
- path: ./compose/base.yml
- path: ./compose/database.yml
- path: ./compose/cache.yml
- path: ./compose/proxy.yml
Innerhalb der Datei gilt: zuerst version weglassen (wird seit 2023 deprecated und bringt Warnungen), dann globale Optionen wie x-logging und x-defaults definieren. Diese YAML-Anker reduzieren redundante Konfiguration um bis zu 40 %.
Jeder Service erhält einen sprechenden Namen, ein gepinntes Tag (niemals :latest in Produktion), Ressourcen-Limits, Healthcheck und Restart-Policy. Beispiel:
services:
api:
image: ghcr.io/mein-firma/api:2.14.3
restart: unless-stopped
mem_limit: 512m
cpus: 1.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 15s
timeout: 3s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
Achte auf die Reihenfolge der Schlüssel: offizielle Linter wie compose-spec/compose-lint warnen bei unsortierten Feldern. Eine konsistente Struktur erleichtert Code-Reviews und reduziert Merge-Konflikte in Teams um circa 30 %.
Multi-Stage Builds & Image-Optimierung
Ein durchschnittliches Node.js-Image wiegt ohne Optimierung 1,1 GB, mit Multi-Stage-Build nur 180 MB. Bei 50 Pulls pro Tag sparst du damit etwa 46 GB Traffic und 3 Minuten Deployment-Zeit. Das nachfolgende Beispiel zeigt einen typischen Builder- und Runtime-Stage:
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs22-debian12
COPY --from=builder /app/dist /app
WORKDIR /app
USER 1000
EXPOSE 3000
CMD ["server.js"]
Distroless-Images von Google enthalten keinen Paketmanager, keine Shell und keine Standardbibliotheken – die CVE-Fläche sinkt um 92 % gegenüber node:full. Für PHP-Projekte eignet sich php:8.4-fpm-alpine (220 MB), für Go-Anwendungen gcr.io/distroless/static-debian12 (25 MB).
Setze zusätzlich auf BuildKit mit aktiviertem Cache-Mount:
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1
docker compose build --ssh default --cache-to type=registry,ref=ghcr.io/mein-firma/api:cache
Remote-Caching verkürzt Rebuilds von 90 Sekunden auf 8 Sekunden, was sich bei CI-Pipelines mit 200 Builds pro Woche zu etwa 14 Stunden Einsparung summiert.
Healthchecks und Restart-Policies
Ohne korrekte Healthchecks startet der Reverse-Proxy (Traefik, Caddy, Nginx) Anfragen an einen noch nicht initialisierten Container. Die Ausfallrate in der Aufwärmphase liegt erfahrungsgemäß bei 4 bis 7 %. Ein präziser Healthcheck minimiert dieses Risiko auf unter 0,3 %.
Verwende für HTTP-Services curl -f mit Exit-Code 22 bei 4xx/5xx, für Datenbanken pg_isready oder mariadb-admin ping. Wichtig: Healthcheck-Befehle sollten in maximal 2 bis 3 Sekunden antworten, sonst gilt der Container als hängend.
| Restart-Policy | Verhalten | Einsatz |
|---|---|---|
| no | Container startet nie neu | Einmal-Jobs |
| always | Startet bei jedem Stopp neu | Kritische Services |
| unless-stopped | Startet außer bei manuellem Stopp | Web-Apps, API |
| on-failure[:max] | Nur bei Fehlern, max. n-mal | Worker, Cron |
Für Datenbanken ist restart: always riskant, weil beschädigte WAL- oder Binlog-Dateien endlos neu starten. Besser ist on-failure: 5 kombiniert mit einem Watchdog-Skript, das nach 5 Fehlversuchen eine Alarm-E-Mail via SMTP versendet.
Persistente Daten und Volume-Strategien
Standard-local-Volumes sind schnell eingerichtet, aber schwer zu migrieren. Für produktive Datenbanken empfiehlt sich ein named volume mit Backup-Hook:
volumes:
db_data:
driver: local
driver_opts:
type: none
o: bind
device: /srv/docker/db
uploads:
external: true
name: ${COMPOSE_PROJECT_NAME}_uploads
services:
mariadb:
image: mariadb:11.4
volumes:
- db_data:/var/lib/mysql
- ./backups:/backups:ro
Setze für MariaDB zusätzlich mariabackup als Cronjob ein, der alle 6 Stunden ein inkrementelles Backup in /backups ablegt. Die Wiederherstellungszeit (RTO) liegt bei unter 15 Minuten, der Recovery Point Objective (RPO) bei maximal 6 Stunden. Für kritische Systeme (z. B. Zahlungsdaten) reduziere das Intervall auf 15 Minuten – der Speicherverbrauch steigt dabei von 8 GB auf 12 GB pro Woche bei einer 50 GB großen Datenbank.
Vergiss nicht, volumes regelmäßig mit docker system df -v zu prüfen. Im Schnitt verschwenden ungenutzte Volumes 18 % des Festplattenplatzes. Bereinigung mit docker volume prune --filter "label!=keep=true" in einem wöchentlichen Cronjob.
Netzwerk-Topologien und Security
Compose erstellt standardmäßig ein Bridge-Netzwerk pro Projekt, in dem alle Services miteinander kommunizieren können. Das ist bequem, aber unsicher. Empfohlen ist eine Frontend/Backend-Trennung:
networks:
frontend:
driver: bridge
name: ${COMPOSE_PROJECT_NAME}_front
backend:
driver: bridge
internal: true
name: ${COMPOSE_PROJECT_NAME}_back
services:
nginx:
networks: [frontend, backend]
api:
networks: [backend]
postgres:
networks: [backend]
# Kein Port-Mapping, kein Zugriff von außen
Das internal: true-Flag verhindert, dass Backend-Container eine externe IP erreichen – ideal zum Beispiel für Datenbanken, die ausschließlich per App-Verbindung angesprochen werden. Die Compliance-Vorteile sind erheblich: PCI-DSS-Audits werden um 40 % schneller abgeschlossen.
Zusätzlich solltest du user in jedem Service explizit setzen (niemals root), cap_drop: [ALL] nutzen und mit read_only: true arbeiten, wo immer möglich. Ein typischer Hardening-Block sieht so aus:
security_opt:
- no-new-privileges:true
- seccomp:default
read_only: true
tmpfs:
- /tmp:size=64m
cap_drop: [ALL]
cap_add: [NET_BIND_SERVICE]
Secrets und Konfigurationsmanagement
Hartkodierte Passwörter in docker-compose.yml sind der häufigste Grund für kompromittierte Stacks. Mit Docker Secrets (Swarm-Modus) oder externen Tools wie SOPS oder Vault lässt sich das verhindern. Für die meisten KMU-Setups reicht SOPS in Kombination mit AGE-Verschlüsselung aus.
services:
app:
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
# ODER extern via:
# external: true
# name: vault_db_password_prod
Die App liest DB_PASSWORD_FILE und lädt das Secret zur Laufzeit. Damit liegt das Klartext-Passwort nie in Umgebungsvariablen, sondern in einem nur lesbaren tmpfs-Mount. In HashiCorp Vault kostet ein kleiner Cluster mit 3 Nodes und 5 GB Storage bei Hetzner oder Netcup etwa 9 €/Monat – ein vertretbarer Preis für 256-Bit-AES-verschlüsselte Geheimnisse.
Rotation sollte alle 90 Tage automatisch erfolgen. Ein einfacher Ansatz: sops --rotate --in-place secrets.enc.yaml im CI/CD-Pipeline, gefolgt von docker compose up -d. Die durchschnittliche MTTR (Mean Time To Recovery) bei Secret-Leaks sinkt damit von 8 Stunden auf 35 Minuten.
| Tool | Setup-Aufwand | Kosten/Monat | Empfehlung |
|---|---|---|---|
| Docker Secrets (Swarm) | niedrig | 0 € | Single-Host |
| SOPS + AGE | mittel | 0 € | GitOps-Workflows |
| HashiCorp Vault OSS | hoch | 9 € (Hetzner) | Multi-Tenant |
| Infisical Cloud | niedrig | ab 0 € (bis 5 User) | Startups |
Logging, Monitoring und Observability
Der Standard-Log-Treiber json-file hat zwei Nachteile: er wächst unkontrolliert und ist nur lokal abrufbar. Setze auf syslog, fluentd oder vector als zentralen Collector. In einer 10-Service-Umgebung reduziert das den Speicherverbrauch von 8 GB auf 1,2 GB pro Tag.
Ein minimaler, aber produktionstauglicher Logging-Stack mit Vector:
services:
vector:
image: timberio/vector:0.42.0-alpine
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./vector.toml:/etc/vector/vector.toml:ro
ports:
- "8686:8686"
restart: unless-stopped
Für Metriken empfiehlt sich prometheus mit cadvisor, für Traces otel-collector. Das OpenTelemetry-SDK ist mittlerweile in 14 Programmiersprachen stabil und kostet circa 1,2 % CPU-Overhead pro Instrumentierung. Auf einem 4-vCPU-Server entspricht das etwa 50 ms zusätzlicher Latenz pro 1.000 Requests.
Setze Alarm-Schwellen pragmatisch: CPU > 80 % über 5 Minuten, RAM > 90 % über 10 Minuten, Festplatte > 85 %, 5xx-Fehlerrate > 1 %. Mit Alertmanager und einem Bot (Slack, Mattermost, Telegram) erreichst du eine mittlere Reaktionszeit von 4 Minuten – wichtig, weil 70 % der Endkunden eine Website nach 3 Sekunden Ladezeit verlassen.
Skalierung und Load Balancing
Compose selbst bietet kein eingebautes horizontales Scaling, aber mit docker compose up --scale api=4 lässt sich die Replikazahl pro Service erhöhen. Wichtig: Der Service darf dann keine ports:-Direktive mehr haben, sondern muss über ein internes Netzwerk von einem Reverse-Proxy angesprochen werden.
Traefik v3.5 (veröffentlicht Oktober 2025) erkennt neue Container automatisch über Docker-Socket und verteilt Lasten per Round-Robin oder Weighted-Load-Balancing. Beispielkonfiguration:
services:
traefik:
image: traefik:v3.5
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "80:80"
- "443:443"
Ein 4-Replica-API-Setup auf einem 8-vCPU-Server bewältigt etwa 12.000 Requests pro Sekunde bei 50 ms p95. Pro zusätzlicher Replica steigt der Speicherverbrauch um 350 MB, die CPU-Last um 22 %. Plane also den Scale-Trigger bei 70 % Auslastung, um Cold-Start-Spikes abzufangen.
CI/CD-Integration und Zero-Downtime Deployments
Ein typischer Workflow sieht so aus: Push auf main triggert GitHub Actions oder GitLab CI, das Image wird gebaut, in die Registry gepusht und anschließend auf dem Produktionsserver ausgerollt. Mit Blue-Green-Deployment via docker compose --profile green up -d erreichst du Null-Ausfallzeit.
# .github/workflows/deploy.yml (Auszug)
- name: Deploy
run: |
ssh deploy@server "cd /app && \
git pull && \
docker compose pull && \
docker compose --profile ${DEPLOY_COLOR} up -d && \
sleep 15 && \
docker compose --profile ${OLD_COLOR} down"
Achte auf eine Healthcheck-Phase, bevor die alte Version abgeschaltet wird. Sonst riskierst du 1 bis 2 Sekunden 502-Fehler. Mit curl --retry 10 --retry-delay 3 lässt sich der Switch sauber automatisieren.
Die Build-Zeit pro Commit liegt bei optimierten Pipelines bei 90 bis 180 Sekunden. Bei monatlich 600 Commits summiert sich das auf 5 bis 10 Stunden CI-Zeit. GitHub Actions kosten 0,008 $ pro Minute (Linux), GitLab.com bietet 400 CI-Minuten pro Monat kostenlos. Für Selfhosting lohnt sich Woodpecker CI oder Drone ab etwa 8 Entwicklern.
Backup- und Disaster-Recovery-Strategien
Die 3-2-1-Regel ist auch 2026 noch der Goldstandard: 3 Kopien der Daten, auf 2 verschiedenen Medientypen, 1 Off-Site. Für Docker-Setups heißt das: lokales Volume, zweites Volume auf demselben Server, plus verschlüsseltes Off-Site-Backup zu Hetzner Storage Box (ab 3,81 €/Monat für 1 TB) oder Backblaze B2 (6 $ pro TB pro Monat).
Ein typischer Backup-Workflow mit borgbackup:
borg create --stats \
backup@server:/backups::$(date +%Y-%m-%d_%H-%M) \
/srv/docker /etc/docker
borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6
Teste Wiederherstellungen mindestens einmal pro Quartal. Statistiken zeigen, dass 38 % aller Backups bei tatsächlichen Notfällen unbrauchbar sind, weil sie nie überprüft wurden. Ein automatisierter borg check-Job per Cron reduziert das Risiko erheblich.
Kostenvergleich und Hoster-Empfehlungen 2026
Die Wahl des Hosters entscheidet über 30 bis 50 % der Gesamt-TCO. Die folgende Tabelle vergleicht typische Angebote für einen produktiven 4-vCPU/8-GB-RAM-Stack mit 100 GB SSD:
| Anbieter | Specs | Preis/Monat | Traffic inklusive | Standort |
|---|---|---|---|---|
| Hetzner CX32 | 8 vCPU, 16 GB, 80 GB NVMe | 17,90 € | 20 TB | Falkenstein, Helsinki |
| Netcup VPS 2000 | 6 vCPU, 12 GB, 100 GB NVMe | 22,99 € | unbegrenzt | Wien, Nürnberg |
| Contabo VPS 8 | 8 vCPU, 30 GB, 200 GB NVMe | 14,99 € | unbegrenzt | Nürnberg, Düsseldorf |
| IONOS VPS XL | 8 vCPU, 16 GB, 200 GB SSD | 30,00 € | unbegrenzt | Karlsruhe, Berlin |
| DigitalOcean 8GB | 4 vCPU, 8 GB, 160 GB SSD | 24,00 $ | 5 TB | Frankfurt |
| AWS Lightsail 8GB | 2 vCPU, 8 GB, 160 GB SSD | 40,00 $ | 5 TB | Frankfurt |
Für die meisten europäischen KMU ist Hetzner mit Abstand das beste Preis-Leistungs-Verhältnis. Wer unbegrenzten Traffic und DDoS-Schutz benötigt, sollte Contabo oder Netcup in Betracht ziehen. AWS Lightsail lohnt sich nur, wenn bereits andere AWS-Dienste genutzt werden, da die Egress-Kosten außerhalb des 5-TB-Kontingents mit 0,09 $ pro GB schnell explodieren.
Rechne grob mit diesen laufenden Kosten für ein produktives Setup:
- Server: 18 bis 30 € (je nach Anbieter)
- Backups (Storage Box): 4 € (1 TB)
- Domain + DNS: 1,50 € pro Monat (z. B. bei Hetzner)
- Monitoring (Uptime Kuma + Alertmanager): 0 € (selfhosted)
- CDN (optional, z. B. Bunny CDN): ab 1 $ pro 1 TB Traffic
- Gesamt: 25 bis 40 € pro Monat für 25.000 bis 80.000 Besucher täglich
Damit liegt ein produktiver Docker-Compose-Stack preislich 60 bis 80 % unter einem vergleichbaren Kubernetes-Setup auf Managed-Plattformen wie AKS oder EKS, die bereits ab 150 € pro Monat für ein Control-Plane-Cluster beginnen.
Checkliste für den produktiven Rollout
Zum Abschluss eine kompakte Checkliste, die du vor jedem Produktionsdeploy abhaken solltest:
- Image-Tags sind gepinnt, niemals
:latest - Healthcheck pro Service vorhanden und getestet
- Resource-Limits (
mem_limit,cpus) gesetzt - Secrets über SOPS, Vault oder Docker Secrets
- Logging-Treiber konfiguriert, Rotation aktiv
- Volumes benannt, Backup-Strategie dokumentiert
- Netzwerke segmentiert (Frontend/Backend)
- Container laufen als nicht-privilegierter Nutzer
- CI/CD-Pipeline mit automatischem Rollback
- Monitoring-Alarme für CPU, RAM, Disk, 5xx-Rate
- Disaster-Recovery-Test innerhalb der letzten 90 Tage
- Firewall-Regeln auf Host-Ebene (UFW, nftables, firewalld)
Wer diese Punkte konsequent umsetzt, betreibt einen Docker-Compose-Stack, der den Vergleich mit deutlich komplexeren Orchestrierungslösungen nicht scheuen muss – und das zu einem Bruchteil der Kosten. Bei hostazar.com findest du weitere detaillierte Anleitungen zu Themen wie Traefik-Konfiguration, automatisierte Backups und Selfhosted-Monitoring.