Docker Compose: Multi-Container-Orchestrierung
Docker Compose ist ein Tool, das es ermöglicht, Multi-Container-Anwendungen zu definieren und zu verwalten. Während Docker einzelne Container verwaltet, ermöglicht Docker Compose, mehrere Container als eine zusammenhängende Anwendung zu orchestrieren. Dies ist essentiell für moderne Anwendungen, die typischerweise aus mehreren Komponenten bestehen: Web-Server, Datenbank, Cache, Message Queue, etc.
Eine typische Web-Anwendung besteht aus einem Web-Server (z.B. Nginx), einer Anwendungs-Server (z.B. PHP-FPM oder Node.js), einer Datenbank (z.B. MySQL), und möglicherweise einem Cache (z.B. Redis). Ohne Docker Compose müssten Sie jeden Container manuell starten, Netzwerke konfigurieren, Volumes verbinden, und Abhängigkeiten verwalten. Docker Compose vereinfacht dies erheblich durch eine einzige Konfigurationsdatei.
Docker Compose verwendet eine YAML-Datei (docker-compose.yml), die alle Services, Netzwerke, Volumes, und Konfigurationen definiert. Mit einem einzigen Befehl (docker-compose up) können Sie die gesamte Anwendung starten, und mit docker-compose down können Sie alles stoppen. Dies macht Entwicklung, Testing, und Deployment erheblich einfacher.
Docker Compose Grundlagen
Services:
Services sind Container-Definitionen in Docker Compose. Jeder Service definiert einen Container: welches Image verwendet wird, welche Ports exponiert werden, welche Umgebungsvariablen gesetzt werden, welche Volumes gemountet werden, etc.
Networks:
Docker Compose erstellt automatisch ein Netzwerk für alle Services, sodass sie miteinander kommunizieren können. Services können sich über Service-Namen erreichen (z.B. db für einen Datenbank-Service).
Volumes:
Volumes ermöglichen persistente Datenspeicherung. Datenbank-Daten, Upload-Dateien, oder Konfigurationsdateien können in Volumes gespeichert werden, die über Container-Lebensdauer hinaus bestehen.
Dependencies:
Services können Abhängigkeiten definieren - ein Web-Server-Service kann abhängig von einem Datenbank-Service sein, sodass die Datenbank zuerst gestartet wird.
Typische Docker Compose Setup
Ein typisches Docker Compose Setup für eine PHP-Anwendung könnte so aussehen:
yaml
version: "3.8"
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./src:/var/www/html
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- php
- db
php:
image: php:8.1-fpm
volumes:
- ./src:/var/www/html
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Dieses Setup definiert drei Services: einen Nginx Web-Server, einen PHP-FPM Application-Server, und eine MySQL-Datenbank. Der Web-Server exponiert Port 80, alle Services teilen sich ein Netzwerk, und die Datenbank verwendet ein Volume für persistente Datenspeicherung.
Service-Konfiguration
Image vs. Build:
Services können entweder ein vorgefertigtes Image verwenden (image: nginx:alpine) oder ein Image aus einem Dockerfile bauen (build: ./path/to/dockerfile). Für Production sind vorgefertigte Images oft besser, für Development kann Build nützlich sein.
Ports:
Ports können exponiert werden mit ports: - "host:container". Port 80 auf dem Host wird zu Port 80 im Container gemappt. Für interne Kommunikation zwischen Containern sind Ports nicht nötig - Services können sich über Service-Namen erreichen.
Environment Variables:
Umgebungsvariablen können mit environment: gesetzt werden. Dies ist wichtig für Konfiguration wie Datenbank-Passwörter, API-Keys, etc. Für sensible Daten sollten env_file: oder Secrets verwendet werden.
Volumes:
Volumes können für persistente Datenspeicherung oder für Code-Mounting verwendet werden. Named Volumes (wie db_data) sind für persistente Daten, Bind Mounts (wie ./src:/var/www/html) sind für Development.
Networking in Docker Compose
Docker Compose erstellt automatisch ein Netzwerk für alle Services. Services können sich über Service-Namen erreichen - db für einen Datenbank-Service, web für einen Web-Server-Service. DNS-Auflösung funktioniert automatisch.
Für externe Netzwerke können Services mit external: true definiert werden. Dies ermöglicht es, Services mit Containern außerhalb von Docker Compose zu verbinden.
Volumes und persistente Daten
Named Volumes:
Named Volumes (wie db_data) werden von Docker verwaltet und sind ideal für persistente Daten wie Datenbank-Dateien. Volumes überleben Container-Neustarts.
Bind Mounts:
Bind Mounts (wie ./src:/var/www/html) mounten Host-Verzeichnisse in Container. Dies ist ideal für Development, wo Code-Änderungen sofort sichtbar sein sollen.
Volume-Definitionen:
Volumes können in der volumes: Sektion definiert werden. Dies ermöglicht es, Volumes zu benennen und wiederzuverwenden.
Abhängigkeiten und Start-Reihenfolge
Services können Abhängigkeiten mit depends_on: definieren. Ein Service, der von einem anderen abhängt, wird erst gestartet, nachdem der abhängige Service gestartet ist. Aber depends_on wartet nur auf Container-Start, nicht auf Service-Bereitschaft.
Für echte Health-Checks sollten healthcheck: Konfigurationen verwendet werden. Ein Service mit Health-Check wird erst als bereit markiert, wenn der Health-Check erfolgreich ist.
Environment-spezifische Konfigurationen
Docker Compose unterstützt mehrere Compose-Dateien. Eine docker-compose.yml für Basis-Konfiguration, eine docker-compose.prod.yml für Production-Überschreibungen. Mit docker-compose -f docker-compose.yml -f docker-compose.prod.yml up können beide Dateien kombiniert werden.
Umgebungsvariablen können in .env Dateien definiert werden. Docker Compose lädt automatisch .env Dateien, sodass Konfigurationen zwischen Umgebungen variieren können.
Best Practices
Versionierung:
Verwenden Sie eine spezifische Docker Compose Version. version: "3.8" ist aktuell, aber Versionen können variieren.
Service-Namen:
Verwenden Sie aussagekräftige Service-Namen. db statt database, web statt webserver - kürzere Namen sind einfacher zu verwenden.
Secrets Management:
Für sensible Daten sollten Docker Secrets verwendet werden, nicht plain-text Environment Variables.
Health Checks:
Verwenden Sie Health Checks für Services, die Zeit zum Starten benötigen (wie Datenbanken). Dies stellt sicher, dass Services bereit sind, bevor abhängige Services starten.
Resource Limits:
Setzen Sie Resource Limits für Production. deploy.resources.limits kann CPU und Memory begrenzen.
Kommentare