Docker: Team-Entwicklungsumgebungen mit globalen Daemon-Einstellungen vereinheitlichen

Ob lokal oder auf dem Server: Wer Docker nutzt, wird feststellen, dass immer wieder dieselben Einstellungen in der docker-compose.yml pro Projekt kopiert und eingefügt werden müssen.

  • Ständig DNS auf 1.1.1.1, 8.8.8.8 festlegen
  • Den Log-Treiber auf json-file + max-size=10m fixieren
  • Proxy, unsichere Registrierung, Standard-Netzwerkbereiche und mehr…

Solche Dinge lassen sich viel einfacher verwalten, wenn man sie nicht als individuelle Containereinstellungen, sondern als „Standardwerte für den gesamten Host“ definiert. Genau diese Rolle übernimmt die globale Docker-Daemon-Konfiguration (daemon.json).

Im Folgenden werde ich erläutern:

  • Welche Datei
  • Wo sie erstellt werden sollte
  • Wie sie zu konfigurieren ist
  • Und für welche Entwickler/Teams sie unter welchen Umständen nützlich ist.


1. Zwei Methoden zur Konfiguration des Docker-Daemons

Der Docker-Daemon (dockerd) kann grundsätzlich auf zwei Arten konfiguriert werden:

  1. Verwendung einer JSON-Konfigurationsdatei (daemon.json)Empfohlen
  2. Übergabe von Optionen als CLI-Flags beim Start von dockerd

Beide Methoden können kombiniert werden, aber wenn dieselbe Option in beiden Konfigurationen angegeben wird, startet der Daemon überhaupt nicht. Wenn Sie beispielsweise den Log-Treiber sowohl über das --log-driver-Flag als auch in der daemon.json festlegen, wird Docker beim Start mit einem Fehler beendet.

Zur Vereinheitlichung von Team-/Serverumgebungen wird in der Regel empfohlen:

„So viel wie möglich in die daemon.json packen und Flags auf ein Minimum beschränken.“

2. Speicherort der daemon.json

Der Dateipfad ist /etc/docker/daemon.json. Dies gilt natürlich für Linux.

Es mag Nutzer geben, die Docker in anderen Umgebungen als Linux verwenden. Da ich es jedoch ausschließlich unter Linux nutze, bin ich mit anderen Betriebssystemen weniger vertraut. Die Standardpfade pro Betriebssystem sind jedoch übersichtlich in der folgenden Tabelle zusammengefasst:

Umgebung Standardpfad Anmerkung
Linux (Standardinstallation) /etc/docker/daemon.json Der häufigste Fall
Linux (per Snap installiertes Docker) /var/snap/docker/current/config/daemon.json Ubuntu Snap-Paket
Windows Server / Docker Engine C:\ProgramData\Docker\config\daemon.json
Docker Desktop (Mac / Windows) ~/.docker/daemon.json
  • Diese Datei existiert standardmäßig möglicherweise nicht. Falls sie fehlt, können Sie sie einfach selbst erstellen.

3. Grundlegendes Nutzungsmuster: „Datei erstellen → Daemon neu starten“

Unter Linux ist der typische Workflow wie folgt:

  1. daemon.json erstellen/bearbeiten
{
  "dns": ["1.1.1.1", "8.8.8.8"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
  1. Vorabvalidierung der Konfigurationsdatei
sudo dockerd --validate --config-file=/etc/docker/daemon.json
# Wenn "configuration OK" erscheint, ist alles in Ordnung
  1. Docker-Daemon neustarten
sudo systemctl restart docker

Von nun an erben alle neu gestarteten Container diese globalen Einstellungen als Standardwerte, sofern keine individuellen Einstellungen vorgenommen werden.

4. Haupteinstellung: DNS-Server global festlegen

4.1 Warum DNS global konfigurieren?

Wenn Container häufig Probleme haben, „externe APIs nicht zu finden“ oder „interne Domains nicht aufzulösen“, liegt das meist daran, dass sie von den DNS-Einstellungen/der Umgebung des Hosts abhängig sind.

Zum Beispiel:

  • Das gesamte Team möchte Cloudflare DNS (1.1.1.1) nutzen.
  • Es gibt Endpunkte, die nur über den internen DNS-Server des Unternehmens erreichbar sind.

In solchen Fällen ist es viel bequemer, die DNS-Einstellungen auf der Docker-Daemon-Ebene zu vereinheitlichen, anstatt in jedem Projekt dns: in die docker-compose.yml einzufügen.

4.2 Konfigurationsbeispiel (daemon.json)

{
  "dns": ["1.1.1.1", "8.8.8.8"]
}

Wenn bereits eine daemon.json existiert, fügen Sie einfach den Eintrag "dns": [...] innerhalb des Wurzel-Objekts { ... } hinzu.

⚠️ Achtung: DNS-Einstellungen werden in der /etc/resolv.conf im Container übernommen. Sie werden nicht sofort auf bereits laufende Container angewendet, sondern erst auf neu gestartete Container.

5. Haupteinstellung 2 – Globaler Log-Treiber & Optionen

Container-Logs werden standardmäßig über den json-file-Treiber unter /var/lib/docker/containers/... gespeichert. Wenn dies global geändert wird, können Sie:

  • das Log-Format
  • den Speicherort der Logs
  • und die Log-Rotationsrichtlinie

für alle Container einheitlich anwenden.

5.1 Standard json-file Treiber + Rotation

Das häufigste Muster ist: „Einfach json-file verwenden, aber mit Rotations-Einstellungen, damit die Festplatte nicht überläuft.“

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Damit wird erreicht:

  • Die Log-Dateigröße pro Container beträgt maximal 10 MB.
  • Es werden maximal 5 Dateien vorgehalten.
  • Überschüssige Dateien werden automatisch gelöscht.

5.2 Treiber für die zentrale Log-Erfassung (Fluentd, Journald etc.)

Plattform- oder Infrastrukturteams möchten oft die Logs aller Container an ein zentrales Log-System senden.

Wenn Sie beispielsweise Fluentd verwenden:

{
  "log-driver": "fluentd",
  "log-opts": {
    "fluentd-address": "localhost:24224",
    "tag": "{{.Name}}"
  }
}

Auf diese Weise werden die Logs aller Container automatisch an Fluentd gesendet, ohne dass ein separates docker run --log-driver=... erforderlich ist.

Persönlich mag ich auch den journald-Treiber sehr. In systemd-basierten Linux-Umgebungen können alle Anwendungs- und Docker-Container-Logs an einer zentralen Stelle (journald) gesammelt werden, wodurch die Abfrage, Filterung und Aufbewahrungsrichtlinien allein mit journalctl vereinheitlicht werden können.

Wenn Sie journald als globalen Log-Treiber verwenden möchten, können Sie es beispielsweise so konfigurieren:

{
  "log-driver": "journald",
  "log-opts": {
    "tag": "{{.Name}}"
  }
}

Da tag hier als Container-Name verwendet wird, können Sie:

  • Echtzeit-Logs schnell überblicken im Format journalctl -f | grep {container_name}
  • Optionen wie --since "10m ago" kombinieren, um nur Logs ab einem bestimmten Zeitpunkt anzuzeigen
  • und mit der Option -t (basierend auf Tag/Identifier) wie journalctl -f -t {container_name} gezielt Logs eines bestimmten Containers anzeigen.

Selbstverständlich ist es auch möglich, Logs einheitenbasiert mit journalctl -u docker.service anzuzeigen. Das Filtern nach Container-Namen ist jedoch intuitiver und erfordert weniger Tipparbeit, weshalb es in der Praxis viel häufiger eingesetzt wird.

5.3 Beziehung zu Compose / docker run

  • Der globale log-driver + log-opts dient als „Standardwert“
  • Wenn für einzelne Container logging: (Compose) oder --log-driver, --log-opt (CLI) angegeben wird, überschreibt dies die globalen Einstellungen nur für diesen Container.

Strategisch wird empfohlen:

  • Gemeinsame Werte in der daemon.json zu definieren
  • und nur spezielle Dienste individuell zu überschreiben.

6. Haupteinstellung 3 – Globale Netzwerkeinstellungen wie Proxy, Insecure Registry

Es gibt weitere Optionen, die häufig in den globalen Einstellungen verwendet werden.

6.1 Proxy-Einstellungen

Wenn der Zugriff nach außen nur über einen internen Unternehmensproxy möglich ist, können Sie den Proxy auf Daemon-Ebene konfigurieren, anstatt jedes Mal Umgebungsvariablen hinzuzufügen.

{
  "proxies": {
    "http-proxy": "http://proxy.example.com:3128",
    "https-proxy": "http://proxy.example.com:3128",
    "no-proxy": "localhost,127.0.0.1,.corp.example.com"
  }
}

Auf diese Weise folgt der Docker-Daemon diesen Proxy-Einstellungen, wenn er Images abruft oder das Netzwerk während des Builds verwendet.

6.2 Insecure Registry

Wenn Sie unbedingt eine Registry ohne TLS verwenden müssen (z. B. für die interne Entwicklung):

{
  "insecure-registries": ["my-registry.local:5000"]
}

Dies kann ein Sicherheitsrisiko darstellen, daher sollte es nur in internen Testumgebungen verwendet werden.


7. Haupteinstellung 4 – Standard-Netzwerkbereiche, Storage-Treiber etc.

7.1 Anpassen des Standard-Bridge-Netzwerkbereichs

Wenn Sie Überschneidungen von IP-Adressen mit VPNs oder internen Unternehmensnetzwerken vermeiden möchten:

{
  "default-address-pools": [
    {
      "base": "10.20.0.0/16",
      "size": 24
    }
  ]
}

Dadurch verwendet Docker beim Erstellen neuer Bridge-Netzwerke den Bereich 10.20.x.0/24.

7.2 Erzwingen eines Storage-Treibers

Der Standard-Storage-Treiber kann je nach Linux-Distribution variieren. Wenn Ihr Team beschlossen hat, nur overlay2 zu verwenden:

{
  "storage-driver": "overlay2"
}

Die tatsächlich unterstützten Storage-Treiber variieren je nach Betriebssystem und Kernel. Überprüfen Sie daher unbedingt die dockerd-Dokumentation und die Distributionsanleitung.


8. Wenn Sie diese „Déjà-vus“ erleben, sollten Sie jetzt handeln

Sie müssen keine komplexen Infrastrukturdetails kennen. Wenn Sie kürzlich die folgenden Erfahrungen gemacht haben, ist es höchste Zeit, sich um die daemon.json zu kümmern.

  • Bei jedem neuen Projekt durchsuchen Sie die docker-compose.yml und kopieren/einfügen Log-Einstellungen: Wenn Sie Einstellungen wie max-size oder max-file aus dem Code von gestern heraussuchen und erneut einfügen, verschwenden Sie bereits wertvolle Zeit. Einmal global definiert, starten alle Container automatisch im „Diät-Modus“.
  • Container, die im Büro einwandfrei funktionieren, haben in einer Café- oder VPN-Umgebung keinen Internetzugang: Das ist der klassische Fall von „Auf meinem lokalen System hat es funktioniert!“. Wenn Sie möchten, dass Ihre Container unabhängig von den DNS-Einstellungen des Hosts in jeder Netzwerkumgebung konsistent mit der Außenwelt kommunizieren, ist die globale DNS-Fixierung die richtige Lösung.
  • Sie sind völlig überfordert, weil Sie die Einstellungen zahlreicher Server-Knoten einzeln anpassen müssen: Kämpfen Sie mit „Geister-Bugs“, die durch subtil unterschiedliche Docker-Einstellungen auf jedem Server entstehen? Wenn Sie nur eine daemon.json-Datei bereitstellen, werden alle Server nach denselben Regeln betrieben.

Wenn Sie wiederkehrende Einstellungen leid sind oder die ständigen Probleme durch Umgebungsänderungen satt haben, ist dies der perfekte Zeitpunkt, diese Konfiguration einzuführen.

Zusammenfassung

  • Die globalen Standardwerte von Docker werden in der daemon.json verwaltet.
  • Der Speicherort ist normalerweise /etc/docker/daemon.json.
  • Beispiele für typische globale Einstellungen:
    • DNS: "dns": ["1.1.1.1", "8.8.8.8"]
    • Log-Treiber: "log-driver": "json-file", "log-opts": {...}
    • Proxy, unsichere Registrierung, Standard-Netzwerkbereiche, Storage-Treiber…
  • Globale Einstellungen sind nützlich für wiederkehrende Konfigurationen und beim Einsatz vieler Knoten in verschiedenen Umgebungen.

Wenn Sie ständig dieselben Optionen in Ihrer docker-compose.yml oder bei docker run verwenden, könnte es an der Zeit sein, diese einmal in die daemon.json zu verschieben.

Abbildung der Docker-Daemon-JSON-Einstellungen