Begriff
Compose Override
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Du hast eine docker-compose.yml für dein Team.
Darin steht: "Starte Webserver auf Port 80."
Aber auf deinem lokalen Laptop ist Port 80 schon belegt. Du willst Port 8080 nutzen.
Du willst die Datei nicht ändern (weil Git dann meckert).
Lösung: Compose Override.
Du erstellst eine zweite Datei: docker-compose.override.yml.
Darin schreibst du nur die Änderung: "Für Webserver: Nutze Port 8080".
Docker liest automatisch beide Dateien und verschmilzt sie (Merge).
Die Override-Datei wird oft in .gitignore gepackt, damit jeder Entwickler seine eigenen lokalen Anpassungen haben kann.
Merksatz: Ein Mechanismus in Docker Compose, um Konfigurationen aus einer Basisdatei (docker-compose.yml) durch eine zweite Datei (docker-compose.override.yml) zu ergänzen oder zu überschreiben, ohne die Originaldatei zu verändern.
Basis docker-compose.yml:
services:
web:
image: my-app:production
ports:
- "80:80"
Override docker-compose.override.yml (lokal):
services:
web:
build: . # Baue lokal statt Image zu ziehen
ports:
- "8080:80" # Ändere Port
volumes:
- ./src:/app/src # Aktiviere Hot Reload
Befehl: Einfach docker compose up. Docker erkennt die Override-Datei automatisch.
Wenn du explizit eine andere Datei willst: docker compose -f docker-compose.yml -f prod.yml up.
1. Merge Rules (Array vs. Object)
Wie wird gemerged?
- Objekte (Environment): Werden zusammengeführt. Key A aus Basis + Key B aus Override = A & B. Bei Konflikt gewinnt Override.
- Arrays (Ports, Volumes, Command): Werden meistens addiert (Concatenation).
Basis:
- "80:80". Override:- "8080:80". Ergebnis: Beide Ports sind offen! Das führt oft zu Fehlern ("Port already allocated"). Trick: In neueren Compose-Versionen kann man Listen zurücksetzen.
2. Multi-File Chaining
Du kannst beliebig viele Overrides ketten.
docker compose -f base.yml -f dev.yml -f debug.yml up.
Die Reihenfolge ist wichtig: Die letzte Datei gewinnt (Last Write Wins).
Das nutzt man für komplexe CI/CD-Pipelines ("Test Environment" vs "Staging Environment").
3. Profiles (Alternative)
Seit Compose v1.28 gibt es Profiles.
profiles: ["debug"] im Service.
docker compose --profile debug up.
Das ist oft sauberer als viele Override-Files, wenn man nur Dienste an/abschalten will (z. B. "Starte phpMyAdmin nur im Debug Mode").
Extension Fields & Yaml Anchors (DRY Compose)
Anstatt Overrides zu nutzen, um Wiederholungen aufzulösen, nutzt man in komplexen Setups oft YAML Anchors (&) und Extension Fields (x-...).
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
services:
web:
image: nginx
logging: *default-logging
Dies erlaubt es, Base-Konfigurationen (wie Logging, Netzwerke, Restart-Policies) einmal zu definieren und im selben File in dutzenden Containern per *anchor zu injecten. Compose Overrides verschwinden dadurch oft, da das Base-File schlank genug wird, um Umgebungsvariablen (.env) für Dev/Prod Switches zu nutzen.
Das include Statement (Compose V2.20+)
Lange Zeit war das ketten von -f base.yml -f add.yml -f ... in Scripts der einzige Weg für Modularisierung.
Seit Compose V2.20 unterstützt Compose das include Statement nativ.
include:
- ./db/docker-compose.yml
- ./redis/docker-compose.yml
services:
api:
image: my-api
depends_on: [ db, redis ]
Das ist mächtiger als Overrides, da es Teams erlaubt, isolierte Repositories und Stack-Teile als modulare, in sich geschlossene Blöcke (DB, UI, API) zu pflegen, die vom Haupt-Compose gebündelt werden, ohne komplizierte Merge-Konflikte der Override-Mechanik auszulösen.
Override Merge Strategies (The Array Pitfall)
Das Zusammenführen von Arrays in Overrides ist oft unintuitiv.
Bei der Direktive ports fügt Compose standardmäßig die Ports des Overrides an die Basis an (Concatenate).
Seit neueren Spezifikationen kannst du jedoch explizite Ersetzungen oder Deduplizierungen triggern. Noch komplizierter wird es bei command:
Wenn Basis sagt command: ["node", "app.js"] und Override sagt command: ["node", "debug.js"], ersetzt der Override das gesamte Array (Replacement).
Fehler (wie laufende Production Commands überschreiben oder versehentlich offen gelassene Debug-Ports) passieren hier extrem schnell. Ein docker compose config (zeigt den final gerenderten YAML-Baum) ist daher vor jedem Prod-Deployment absolute Pflicht.
Quick-Check
Muss ich die Override-Datei angeben?
Nein. Wenn siedocker-compose.override.ymlheißt, lädt Docker sie automatisch. Das ist Standard-Verhalten. Wenn sie anders heißt, musst du-fnutzen.Kann ich Services löschen?
Nein. Overrides sind additiv. Du kannst keine Services "weg-konfigurieren". Du kannst sie nur stoppen (replicas: 0oder Profiles nutzen).Warum .gitignore?
Weil in der Override oft lokale Pfade (/Users/rixx/projekt), Secrets oder Debug-Ports stehen, die auf dem Produktionsserver nichts zu suchen haben.