Die Docker Engine ist die Laufzeitumgebung, die Container erstellt und ausführt. Sie besteht aus mehreren Prozessen mit klar getrennten Aufgaben. Wer versteht, welche Komponente was tut, kann Fehler deutlich schneller einordnen – vom „Cannot connect to the Docker daemon“ bis zum Container, der startet und sofort wieder endet.

Die Komponenten

  • Client (docker): das Kommandozeilenprogramm. Es spricht mit dem Daemon über eine lokale Socket-Datei (/var/run/docker.sock) oder über TCP/SSH. Der Client enthält keine Containerlogik – er formuliert nur Anfragen an die Docker-API.
  • Daemon (dockerd): der eigentliche Dienst. Er nimmt Anfragen entgegen, baut Images, verwaltet Container, Netzwerke und Volumes. Läuft er nicht, funktioniert kein Befehl mit dieser Fehlermeldung.
  • containerd: der Container-Manager, den der Daemon nutzt. Er verwaltet Lebenszyklus, Images und Snapshots und ist selbst ein eigenständiges Projekt der Cloud Native Computing Foundation – auch Kubernetes verwendet es direkt, ohne dockerd.
  • runc: die Low-Level-Laufzeit. Sie ist ein sehr kleines Programm, das einen Container nach der OCI-Runtime-Spezifikation tatsächlich erzeugt: Namespaces setzen, cgroups konfigurieren, Root-Dateisystem einhängen und den Prozess starten. Nach dem Start beendet sich runc – der Containerprozess läuft dann unter containerd.
# Prozessübersicht der Engine
systemctl status docker
ps -ef | grep -E 'dockerd|containerd'

# Ist der Daemon erreichbar?
docker info | head -20
docker version

# Wo liegt der Socket und wer darf ihn nutzen?
ls -la /var/run/docker.sock
groups                       # Mitgliedschaft in der Gruppe "docker" prüfen

Wichtige Verzeichnisse

  • /var/lib/docker/ – Images, Container-Schreibschichten, Volumes, Netzwerkzustand. Das ist das Verzeichnis, das bei Platzmangel auffällt.
  • /etc/docker/daemon.json – Konfiguration des Daemons: Logging-Treiber, Datenverzeichnis, Registry-Spiegel, Adressen.
  • /var/run/docker.sock – die Kontrollschnittstelle. Wer Zugriff auf diesen Socket hat, hat faktisch Root-Rechte auf dem Host, weil sich darüber ein Container mit eingehängtem / starten lässt.

Der Container-Lebenszyklus

docker create    # Container anlegen, nicht starten
docker start     # anlegen und starten
docker run       # create + start
docker pause     # Prozesse im Container anhalten (SIGSTOP)
docker unpause
docker stop      # SIGTERM, nach 10s SIGKILL
docker kill      # sofort SIGKILL
docker rm        # Container entfernen
docker run --rm  # nach Beenden automatisch entfernen

Der Unterschied zwischen stop und kill ist praktisch bedeutsam: stop gibt der Anwendung Zeit, ihre Arbeit sauber abzuschließen – offene Datenbanktransaktionen, Puffer, temporäre Dateien. kill tut das nicht. Bei datenhaltenden Diensten ist stop der richtige Befehl.

Logging und Datenspeicherung

Der Daemon fängt die Standardausgabe jedes Containers ab und schreibt sie in eine Datei. Standardmäßig ist das der json-file-Treiber ohne Begrenzung – ein bekannter Grund für volle Platten, weil eine geschwätzige Anwendung über Wochen Gigabyte ansammelt.

# daemon.json: Loggröße begrenzen (gilt für neue Container)
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "5" },
  "storage-driver": "overlay2"
}

# Aufräumen
docker system df
docker system prune -a --volumes      # Vorsicht: entfernt ungenutzte Volumes!

Entscheidungen in der Praxis

  • Den Daemon nicht per TCP anbieten. Ein ungeschützter Docker-Port 2375 ist ein offener Root-Zugang. Wenn TCP benötigt wird, nur mit TLS und Client-Zertifikaten.
  • Gruppenmitgliedschaft in docker bedenken. Sie ist bequem, entspricht aber einer Root-Berechtigung. In Mehrbenutzersystemen ist Podman mit benutzerlosem Betrieb die sicherere Wahl.
  • Ein Container, ein Prozess. Die Engine ist auf einen Hauptprozess pro Container ausgelegt. Mehrere Dienste in einem Container (etwa über einen Init-Prozess) brechen Logging, Signalweitergabe und Neustartlogik.
  • Neustartverhalten explizit setzen. Ohne --restart bleibt ein Container nach dem Host-Neustart aus. unless-stopped ist meist die richtige Wahl; always startet auch nach einem absichtlichen Stopp erneut.

Fehlerbilder

  • „Cannot connect to the Docker daemon“ – der Dienst läuft nicht oder die Zugriffsrechte fehlen: systemctl status docker, Gruppenzugehörigkeit prüfen.
  • Container endet sofort mit Code 0 – der Hauptprozess hat sich beendet. Ein Container lebt nur, solange sein PID 1 läuft.
  • Volle Platte – meist unbegrenzte Logs oder verwaiste Volumes: docker system df zeigt die Verteilung.
  • Plötzliche Netzwerkprobleme – häufig nach einer Änderung an Firewallregeln, weil Docker eigene Ketten in iptables verwaltet.

Verwandte Grundlagen: Docker-Grundlagen, Docker, docker-Befehle, OCI-Standard.