Docker Compose¶
Dokumenttyp: Developer Playbook
Status: Draft v0.2
Stand: 2026-06-30
Prinzip: Allgemeine Anleitung mit Praxisbeispiel aus Immohai
Ziel¶
Dieses Dokument erklärt, was Docker Compose ist, warum es für Webprojekte verwendet wird und wie mehrere Container über eine zentrale docker-compose.yml verwaltet werden.
Die konkrete Port-Strategie und Veröffentlichung über Nginx und HTTPS wird im Kapitel 06 Veröffentlichung beschrieben.
Kurz erklärt¶
Docker startet einzelne Container.
Docker Compose startet mehrere zusammengehörige Container über eine gemeinsame Datei.
Diese Datei heißt meistens:
docker-compose.yml
Darin wird beschrieben:
- welche Dienste es gibt,
- welche Images verwendet werden,
- welche Container-Namen gesetzt werden,
- welche Ports verwendet werden,
- welche Ordner eingebunden werden,
- ob Container automatisch neu starten,
- mit welchem Befehl ein Dienst gestartet wird.
Warum Docker Compose?¶
Ohne Docker Compose müsste jeder Container einzeln mit langen docker run-Befehlen gestartet werden.
Das wird schnell unübersichtlich.
Mit Docker Compose liegt die Projektkonfiguration in einer Datei.
Vorteile:
- mehrere Dienste gemeinsam starten
- Konfiguration versionierbar machen
- Ports und Volumes dokumentieren
- Container reproduzierbar starten
- Start, Stopp und Logs vereinheitlichen
- Projekt leichter auf andere Server übertragen
Grundprinzip¶
Projektordner
↓
docker-compose.yml
↓
docker compose up -d
↓
mehrere Container laufen
Beispiel:
docker-compose.yml
├── web
└── docs
Daraus entstehen zum Beispiel:
immohai-web
immohai-docs
Wichtige Begriffe¶
| Begriff | Bedeutung |
|---|---|
| Service | Dienst in der Compose-Datei |
| Image | Vorlage für einen Container |
| Container Name | fester Name des laufenden Containers |
| Port Mapping | Verbindung zwischen Server-Port und Container-Port |
| Volume | eingebundener Ordner oder Speicherbereich |
| Restart Policy | Verhalten nach Neustart oder Fehler |
| Command | Startbefehl im Container |
| Environment | Umgebungsvariablen für den Container |
Grundstruktur einer Compose-Datei¶
Ein einfaches Beispiel:
services:
web:
image: nginx:latest
container_name: app-web
restart: unless-stopped
ports:
- "127.0.0.1:8200:80"
volumes:
- ./frontend:/usr/share/nginx/html:ro
Bedeutung:
| Abschnitt | Bedeutung |
|---|---|
services |
Liste aller Dienste |
web |
Name des Dienstes innerhalb von Compose |
image |
verwendetes Docker Image |
container_name |
Name des Containers |
restart |
Neustartverhalten |
ports |
Port-Zuordnung |
volumes |
eingebundene Ordner |
Services¶
Ein Service beschreibt einen Dienst.
Beispiele:
services:
web:
image: nginx:latest
docs:
image: squidfunk/mkdocs-material:latest
Hier gibt es zwei Services:
| Service | Zweck |
|---|---|
web |
Webapp |
docs |
Dokumentation |
Images¶
Ein Image ist die Vorlage für einen Container.
Beispiele:
nginx:latest
squidfunk/mkdocs-material:latest
postgres:16
python:3.12
Images sollten bewusst gewählt und dokumentiert werden.
Für produktive Projekte kann es sinnvoll sein, statt latest feste Versionen zu verwenden.
Beispiel:
image: postgres:16
Feste Versionen machen Deployments besser nachvollziehbar.
Container-Namen¶
Mit container_name bekommt ein Container einen festen Namen.
Beispiel:
container_name: immohai-web
Vorteile:
- besser lesbar in
docker ps - einfacher in Logs zu finden
- klarer Bezug zum Projekt
Prüfen:
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
Restart Policy¶
Mit restart wird festgelegt, ob ein Container automatisch neu startet.
Typische Optionen:
| Wert | Bedeutung |
|---|---|
no |
kein automatischer Neustart |
always |
startet immer neu |
unless-stopped |
startet neu, außer er wurde bewusst gestoppt |
on-failure |
startet nur nach Fehler neu |
Empfehlung für kleine Webdienste:
restart: unless-stopped
Für einfache Setups ist unless-stopped meistens sinnvoll, weil Dienste nach einem Server-Neustart automatisch wieder starten.
Ports¶
Ports verbinden den Server mit dem Container.
Allgemeines Schema:
<host-ip>:<host-port>:<container-port>
Beispiel:
ports:
- "127.0.0.1:8200:80"
Bedeutung:
| Teil | Bedeutung |
|---|---|
127.0.0.1 |
nur lokal auf dem Server erreichbar |
8200 |
Port auf dem Server |
80 |
Port im Container |
Für Dienste hinter Nginx wird empfohlen:
ports:
- "127.0.0.1:<lokaler-port>:<container-port>"
Nicht empfohlen:
ports:
- "80:80"
Warum?
- Docker würde Port
80öffentlich belegen. - Nginx könnte Port
80nicht verwenden. - Mehrere Apps auf einem Server wären schwerer zu betreiben.
Volumes¶
Volumes verbinden Dateien oder Ordner vom Server mit dem Container.
Beispiel:
volumes:
- ./frontend:/usr/share/nginx/html:ro
Bedeutung:
| Teil | Bedeutung |
|---|---|
./frontend |
Ordner im Projekt |
/usr/share/nginx/html |
Zielordner im Container |
:ro |
read-only, also nur lesend |
Volumes sind wichtig für:
- statische Webseiten
- Dokumentation
- Konfigurationsdateien
- Datenbanken
- persistente Daten
Read-only Volumes¶
Wenn ein Container Dateien nur lesen muss, sollte :ro verwendet werden.
Beispiel:
volumes:
- ./frontend:/usr/share/nginx/html:ro
Vorteil:
- Container kann die Dateien nicht verändern.
- Risiko unbeabsichtigter Änderungen sinkt.
Commands¶
Mit command kann der Startbefehl eines Containers überschrieben oder ergänzt werden.
Beispiel für MkDocs:
command: serve --dev-addr=0.0.0.0:8000 --strict
Bedeutung:
| Teil | Bedeutung |
|---|---|
serve |
MkDocs-Entwicklungsserver starten |
--dev-addr=0.0.0.0:8000 |
im Container auf allen Interfaces Port 8000 nutzen |
--strict |
bei Warnungen oder Fehlern strenger prüfen |
Environment¶
Umgebungsvariablen können direkt oder über eine .env-Datei gesetzt werden.
Beispiel:
environment:
- APP_ENV=production
Oder:
env_file:
- .env
Wichtig:
.env-Dateien mit Secrets dürfen nicht committed werden.
Sie gehören in .gitignore.
Netzwerke¶
Docker Compose legt standardmäßig ein eigenes Netzwerk für das Projekt an.
Services können sich innerhalb dieses Netzwerks über ihre Service-Namen erreichen.
Beispiel:
backend kann postgres über den Namen postgres erreichen
Für einfache App- und Doku-Setups muss meistens kein eigenes Netzwerk definiert werden.
Grundbefehle¶
| Befehl | Zweck |
|---|---|
docker compose up -d |
Dienste im Hintergrund starten |
docker compose ps |
Dienste anzeigen |
docker compose logs |
Logs anzeigen |
docker compose logs <service> |
Logs eines Dienstes anzeigen |
docker compose restart |
Dienste neu starten |
docker compose stop |
Dienste stoppen |
docker compose down |
Dienste stoppen und entfernen |
docker compose config |
Compose-Datei prüfen und auflösen |
docker compose pull |
neue Images herunterladen |
Compose-Datei prüfen¶
Vor dem Start sollte die Compose-Datei geprüft werden:
docker compose config
Dieser Befehl zeigt die aufgelöste Konfiguration.
Wenn YAML-Fehler enthalten sind, werden sie hier sichtbar.
Dienste starten¶
docker compose up -d
Bedeutung:
| Teil | Bedeutung |
|---|---|
up |
Dienste erstellen und starten |
-d |
detached, also im Hintergrund |
Dienste anzeigen¶
docker compose ps
Allgemeine Containerübersicht:
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
Logs anzeigen¶
Alle Logs:
docker compose logs
Logs eines Dienstes:
docker compose logs docs
Letzte 100 Zeilen:
docker compose logs docs --tail=100
Live verfolgen:
docker compose logs docs -f
Dienste neu starten¶
Alle Dienste:
docker compose restart
Einzelner Dienst:
docker compose restart docs
Dienste stoppen¶
docker compose stop
Dienste entfernen¶
docker compose down
Wichtig:
down entfernt Container und Netzwerke, aber normalerweise keine benannten Volumes, solange nicht zusätzliche Optionen verwendet werden.
Vorsicht bei produktiven Datenbanken.
Praxisbeispiel Developer Playbook¶
Datei:
/home/fober/workspace/developer-playbook/docker-compose.yml
Konfiguration:
services:
docs:
image: squidfunk/mkdocs-material:latest
container_name: developer-playbook-docs
restart: unless-stopped
ports:
- "127.0.0.1:8100:8000"
volumes:
- ./:/docs
command: serve --dev-addr=0.0.0.0:8000 --strict
Bedeutung:
| Punkt | Wert |
|---|---|
| Service | docs |
| Image | squidfunk/mkdocs-material:latest |
| Container | developer-playbook-docs |
| Lokaler Port | 127.0.0.1:8100 |
| Container-Port | 8000 |
| Volume | aktuelles Repo nach /docs |
| Command | MkDocs strict serve |
Prüfen:
cd /home/fober/workspace/developer-playbook
docker compose config
docker compose ps
curl -I http://127.0.0.1:8100
Praxisbeispiel Immohai¶
Datei:
/home/fober/projects/immohai/docker-compose.yml
Konfiguration:
services:
web:
image: nginx:latest
container_name: immohai-web
restart: always
ports:
- "127.0.0.1:8200:80"
volumes:
- ./frontend:/usr/share/nginx/html:ro
docs:
image: squidfunk/mkdocs-material:latest
container_name: immohai-docs
restart: always
ports:
- "127.0.0.1:8201:8000"
volumes:
- ./:/docs
command: serve -a 0.0.0.0:8000
Bedeutung:
| Service | Container | Lokaler Port | Container-Port | Zweck |
|---|---|---|---|---|
web |
immohai-web |
127.0.0.1:8200 |
80 |
Immohai App |
docs |
immohai-docs |
127.0.0.1:8201 |
8000 |
Immohai Dokumentation |
Prüfen:
cd /home/fober/projects/immohai
docker compose config
docker compose ps
curl -I http://127.0.0.1:8200
curl -I http://127.0.0.1:8201
Compose im Gesamtsetup¶
Docker Compose startet die Dienste.
Nginx macht sie öffentlich erreichbar.
Certbot sorgt für HTTPS.
docker-compose.yml
↓
lokaler Docker-Port
↓
Nginx Reverse Proxy
↓
HTTPS mit Certbot
↓
öffentliche Domain
Sicherheit¶
.env-Dateien mit Secrets nicht committen.- Keine Tokens oder Passwörter in
docker-compose.ymlschreiben. - Container nur auf notwendige Ports binden.
- Für Dienste hinter Nginx
127.0.0.1verwenden. - Volumes bewusst einsetzen.
- Datenbankdaten sichern.
- Images regelmäßig aktualisieren.
- Compose-Dateien versionieren, aber Secrets getrennt halten.
Typische Fehler¶
| Fehler | Ursache | Lösung |
|---|---|---|
docker compose funktioniert nicht |
Compose Plugin fehlt | Docker Compose Plugin installieren |
| YAML-Fehler | falsche Einrückung | docker compose config ausführen |
| Port ist belegt | anderer Container nutzt Port | docker ps prüfen |
| Dienst ist nicht erreichbar | Container läuft nicht | docker compose ps und Logs prüfen |
| Änderung wird nicht sichtbar | Container wurde nicht neu gestartet | docker compose restart |
.env versehentlich committed |
Secrets nicht geschützt | Datei aus Git entfernen und Secret rotieren |
| Container öffentlich erreichbar | Port nicht auf 127.0.0.1 begrenzt |
Port-Mapping korrigieren |
Best Practices¶
- Pro Projekt eine
docker-compose.ymlverwenden. - Services klar und einfach benennen.
- Container-Namen sprechend wählen.
- Lokale Ports sauber dokumentieren.
- Für Nginx-Reverse-Proxy-Betrieb nur
127.0.0.1binden. docker compose configvor dem Start ausführen.- Logs zuerst mit
docker compose logsprüfen. .envin.gitignoreaufnehmen.- Produktive Daten nicht unbewusst mit
down -vlöschen. - Änderungen an Compose-Dateien committen.
Checkliste¶
- [ ] Zweck von Docker Compose verstanden
- [ ]
docker-compose.ymlvorhanden - [ ] Services klar benannt
- [ ] Images bewusst gewählt
- [ ] Container-Namen gesetzt
- [ ] Restart Policy gesetzt
- [ ] Ports lokal auf
127.0.0.1gebunden - [ ] Volumes bewusst definiert
- [ ] keine Secrets in Compose-Datei
- [ ]
.envgeschützt, falls verwendet - [ ]
docker compose configerfolgreich - [ ] Dienste gestartet
- [ ]
docker compose psgeprüft - [ ] Logs geprüft
- [ ] lokale Ports getestet
- [ ] Änderungen committed