Zum Inhalt

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 80 nicht 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.yml schreiben.
  • Container nur auf notwendige Ports binden.
  • Für Dienste hinter Nginx 127.0.0.1 verwenden.
  • 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.yml verwenden.
  • Services klar und einfach benennen.
  • Container-Namen sprechend wählen.
  • Lokale Ports sauber dokumentieren.
  • Für Nginx-Reverse-Proxy-Betrieb nur 127.0.0.1 binden.
  • docker compose config vor dem Start ausführen.
  • Logs zuerst mit docker compose logs prüfen.
  • .env in .gitignore aufnehmen.
  • Produktive Daten nicht unbewusst mit down -v löschen.
  • Änderungen an Compose-Dateien committen.

Checkliste

  • [ ] Zweck von Docker Compose verstanden
  • [ ] docker-compose.yml vorhanden
  • [ ] Services klar benannt
  • [ ] Images bewusst gewählt
  • [ ] Container-Namen gesetzt
  • [ ] Restart Policy gesetzt
  • [ ] Ports lokal auf 127.0.0.1 gebunden
  • [ ] Volumes bewusst definiert
  • [ ] keine Secrets in Compose-Datei
  • [ ] .env geschützt, falls verwendet
  • [ ] docker compose config erfolgreich
  • [ ] Dienste gestartet
  • [ ] docker compose ps geprüft
  • [ ] Logs geprüft
  • [ ] lokale Ports getestet
  • [ ] Änderungen committed