Zum Hauptinhalt springen
Self-Hosting & Privatsphäre

Docker Compose: env_file oder environment?

Sie ändern .env, starten den Container neu – und der alte Wert bleibt, ohne Fehlermeldung. Die exakte Rangfolge zwischen env_file, environment und Ihrer Shell, nachgestellt an einem echten Stack, plus der Fix, wenn Compose die Änderung nicht übernimmt.

Milan Buha8. November 20266 Min. LesezeitRead in English
TeilenXin
Docker Compose: env_file oder environment?

Docker Compose: env_file vs. environment

Sie ändern einen Wert in .env, führen docker compose up -d aus, gehen per Exec in den Container, um ihn zu prüfen – und es ist immer noch der alte Wert. Keine Fehlermeldung, keine Warnung, nichts in den Logs. Die Datei ist definitiv gespeichert. Compose ist definitiv gelaufen. Warum hat die Änderung nicht gegriffen?

TL;DR
  • Compose kennt drei unterschiedliche Dinge, die alle als "Umgebungsvariablen" bezeichnet werden: die Top-Level-.env-Datei (füllt ${VAR}-Platzhalter in compose.yaml selbst), env_file: (lädt den Inhalt einer Datei in den Container) und environment: (setzt Container-Variablen direkt).
  • Existiert derselbe Key in beiden, gewinnt environment: immer gegen env_file: – laut Dockers eigener Präzedenz-Dokumentation.
  • Eine bereits in der Shell exportierte Variable schlägt alles aus einer Datei – das ist der häufigste Grund, warum ein geänderter .env-Wert "nicht wirkt".
  • docker compose up -d erstellt einen Container nur neu, wenn eine Konfigurationsänderung erkannt wird – allein den Inhalt einer env_file:-Datei zu ändern, reicht manchmal nicht aus, um das auszulösen; --force-recreate ist der zuverlässige Fix.
  • ${VAR:-default} und ${VAR:?error} gelten nur für die Interpolation (.env / Shell), niemals für den Inhalt, der über env_file: geladen wird.

Die drei Dinge, die alle "Umgebungsvariablen" nennen

"In Compose setzen" kann drei unabhängige Mechanismen bedeuten, und sie zu vermischen ist genau das, was die stille Überschreibung verursacht:

Mechanismus Was er tatsächlich tut Wann Compose ihn liest
Top-Level-.env-Datei Füllt ${VAR}-Platzhalter, die direkt in compose.yaml stehen Beim Parsen, bevor der Container überhaupt existiert
env_file: Lädt die key=value-Zeilen einer separaten Datei in die Laufzeitumgebung des Containers Bei der Container-Erstellung
environment: Setzt Variablen direkt in der Laufzeitumgebung des Containers, in compose.yaml selbst Bei der Container-Erstellung

Die Top-Level-.env-Datei ist diejenige, über die die meisten stolpern: für sich allein landet daraus nichts im Container. Sie löst nur ${VAR}-Tokens auf, die wörtlich in compose.yaml stehen – Image-Namen, Portnummern, alles, was Sie parametrisiert haben. Dockers Interpolations-Dokumentation macht explizit klar, dass dies ein separater Schritt ist von dem, was am Ende im laufenden Container landet.

Die Rangfolge (höchste Priorität zuerst)

Ist derselbe Variablenname an mehr als einer Stelle definiert, löst Docker Compose ihn in dieser Reihenfolge auf:

Rang Quelle Gewinnt gegen
1 docker compose run -e VAR=value auf der Kommandozeile Alles darunter
2 Shell-exportierte Variable, interpoliert in environment: oder env_file: environment: / env_file: als Literalwerte
3 environment: in compose.yaml env_file:
4 env_file: in compose.yaml Das ENV im Image
5 ENV im Dockerfile des Images Nichts – niedrigste Priorität

Die Regel, die man sich merken sollte: environment: schlägt env_file: bei gleichem Key, jedes Mal. Wenn Sie einen Wert debuggen, der sich nicht ändern will, prüfen Sie zuerst environment: – fast immer ist das die Stelle, die still gewinnt.

Warning

Eine bereits in Ihrer Shell exportierte Variable (export DB_PASSWORD=old, ein Überbleibsel aus einer früheren Sitzung) übertrumpft alles, was in .env oder env_file: steht. Das ist die häufigste Ursache für "ich habe die Datei geändert und nichts ist passiert" – die Shell, nicht die Datei, ist die aktive Quelle.

Die stille Überschreibung nachgestellt

Ich habe genau dieses Setup auf einem meiner Homelab-Stacks laufen lassen, um die Reihenfolge zu bestätigen, nicht nur zu zitieren. Minimale compose.yaml:

services:
  app:
    image: alpine
    command: sleep infinity
    env_file: .env
    environment:
      - DB_PASSWORD=from_environment_block

Mit folgendem Inhalt in .env:

DB_PASSWORD=from_env_file

Gestartet und die tatsächliche Container-Umgebung geprüft:

docker compose up -d
docker compose exec app env | grep DB_PASSWORD

Ausgabe: DB_PASSWORD=from_environment_block.

environment: gewinnt, exakt wie die Rangfolge-Tabelle es sagt – der Wert aus env_file: landet für diesen Key überhaupt nicht im Container. Entfernt man den environment:-Block vollständig, erscheint stattdessen DB_PASSWORD=from_env_file.

Warum ".env-Änderungen manchmal nicht wirken"

Das ist der Teil, der tatsächlich verwirrt, weil es so aussieht, als würde Compose die Datei komplett ignorieren. Zwei getrennte Ursachen kommen dafür in Frage:

  1. Eine Shell-Variable desselben Namens existiert bereits – siehe die Warnung oben.
  2. Compose hat den Container nicht neu erstellt. docker compose up -d erstellt einen Container nur neu, wenn eine Änderung in der aufgelösten Konfiguration erkannt wird – und in manchen Compose-Versionen wird das Ändern des Inhalts einer über env_file: referenzierten Datei nicht immer als Konfigurationsunterschied erkannt, weil Compose den Inhalt der referenzierten Datei nicht auf die gleiche Weise hasht wie die Service-Definition selbst.

Note

Im Zweifel nicht blind debuggen – mit docker compose up -d --force-recreate erzwingen. Das baut den Container aus der aktuellen Konfiguration und den aktuellen Dateien neu, unabhängig davon, ob Compose glaubt, dass sich etwas geändert hat, und schließt damit einen veralteten Zustand als Ursache aus.

Mehrere env_file-Einträge und ihre Reihenfolge

env_file: akzeptiert auch eine Liste, und taucht derselbe Key in mehr als einer Datei auf, gewinnt die letzte Datei in der Liste:

services:
  app:
    env_file:
      - .env.defaults
      - .env.local

Setzen beide Dateien LOG_LEVEL, ist der Wert aus .env.local derjenige, den der Container erhält.

Interpolations-Defaults: ${VAR:-default} und ${VAR:?error}

Die Interpolationssyntax gilt nur für Werte, die aus der Shell oder der Top-Level-.env-Datei nach compose.yaml aufgelöst werden – niemals für den Inhalt, der über env_file: geladen wird:

services:
  app:
    image: "myapp:${TAG:-latest}"
    environment:
      - API_KEY=${API_KEY:?API_KEY must be set}

${TAG:-latest} fällt auf latest zurück, wenn TAG nicht gesetzt ist. ${API_KEY:?...} macht das Gegenteil – es verweigert den Start und gibt die Meldung aus, wenn API_KEY komplett fehlt, was eine günstige Absicherung gegen einen Container ist, der still ohne jedes Credential hochfährt.

Eine kurze Debugging-Checkliste

  1. docker compose config – druckt die vollständig aufgelöste compose.yaml mit angewendeter Interpolation, damit Sie sehen, was Compose tatsächlich geparst hat.
  2. docker compose exec <service> env – die Wahrheit: was tatsächlich im laufenden Container steckt, unabhängig davon, was irgendeine Datei sagt.
  3. echo $VARNAME in Ihrer Shell – schließt einen vergessenen Export aus einer früheren Sitzung als Ursache aus.
  4. docker compose up -d --force-recreate – wenn sich ein Wert nach den vorherigen Schritten immer noch nicht aktualisiert, erzwingt das den Neuaufbau des Containers aus der aktuellen Konfiguration.

Tip

Wenn es eigentlich um Secrets-Management statt reine Konfigurationswerte geht, deckt unser Leitfaden zu Docker Compose Secrets vs. .env die sicherheitsrelevante Seite ab, die dieser Artikel nicht behandelt.

FAQ

Was ist der Unterschied zwischen env_file und environment in Docker Compose?

env_file: lädt key=value-Paare aus einer separaten Datei in die Umgebung des Containers. environment: setzt Variablen direkt in compose.yaml. Definieren beide denselben Key, gewinnt environment:.

Hat environment oder env_file Vorrang in Docker Compose?

environment: hat Vorrang vor env_file: für denselben Variablennamen, laut Dockers eigener Präzedenz-Dokumentation. Eine Shell-exportierte Variable übertrumpft beide.

Warum wirkt sich meine .env-Änderung nicht auf den Container aus?

Meist liegt es an einer von zwei Ursachen: Eine Variable desselben Namens ist bereits in der Shell exportiert und gewinnt still, oder Compose hat keine Konfigurationsänderung erkannt und den Container nie neu erstellt. Führen Sie docker compose up -d --force-recreate aus, um die zweite Ursache auszuschließen.

Kann ich mehrere env_file-Einträge in Docker Compose verwenden?

Ja – env_file: akzeptiert eine Liste von Dateien. Taucht derselbe Key in mehr als einer auf, gewinnt der Wert aus der letzten Datei in der Liste.

Fazit

5unterschiedliche Prioritätsstufen, die Compose prüft, bevor die Umgebung eines Containers endgültig feststeht – selbst getestet in diesem Artikel auf meinem Homelab-Stack

Drei Mechanismen werden in Compose "Umgebungsvariablen" genannt, und nur eine Regel zählt wirklich, wenn sie kollidieren: environment: schlägt env_file:, und alles, was bereits in Ihrer Shell exportiert ist, schlägt beide. Wenn sich ein Wert nicht ändern will, verrät Ihnen docker compose exec <service> env die Wahrheit schneller, als Ihr YAML erneut zu lesen es je könnte. Taucht ein Portkonflikt auf, nachdem Ihre Umgebung geklärt ist, deckt unser Leitfaden zu Docker Compose Ports das als Nächstes ab; läuft der Befehl selbst gar nicht, ist dieser Fix für "docker-compose: command not found" das vorgelagerte Problem.

Ähnliche Artikel

Mehr aus Self-Hosting & Privatsphäre

Bleiben Sie auf dem Laufenden

Erhalten Sie die neuesten Artikel direkt in Ihr Postfach. Kein Spam, jederzeit abbestellbar.

Als Nächstes lesen

Discord-Alternativen selbst hosten

Stoat, Spacebar und Matrix/Element im Vergleich für eine selbst gehostete Discord-Alternative: RAM-Bedarf, Sprach-/Video-Reife, Discord-Bot-Kompatibilität und die echte Migrationsreibung für eine bestehende Community.

Weiterlesen