Docker Container sind keine schlanken VMs: vier Fragen, eine Antwort

15.11.2026

Thema: alle Beiträge zu Docker

Ein Docker Container ist ein Linux-Prozess, keine kleine VM. Vier Fragen zu Docker und Kubernetes, die sich daraus herleiten lassen, jede nachgemessen.

Inhaltsverzeichnis

Ein Docker Container ist ein Prozess

„Docker Container sind doch nur schlanke VMs.” Der Satz klingt plausibel und ist technisch falsch. Eine virtuelle Maschine emuliert einen kompletten Rechner, mit Hypervisor und eigenem Gast-Kernel. Ein Docker Container hat nichts davon. Er ist ein ganz normaler Linux-Prozess, dem der Kernel weniger zeigt (Namespaces), weniger gibt (cgroups) und ein eigenes Wurzeldateisystem unterschiebt (das Image).

Wie diese drei Bausteine funktionieren und welche Kette hinter dem Kommando docker run arbeitet, steht in Docker Architektur: ein Container ist nur ein Prozess. Hier geht es um den Nutzen dieses einen Satzes. Wer ihn ernst nimmt, muss vier Dinge nicht mehr auswendig lernen, die sonst wie Docker-Folklore wirken: Er kann sie sich herleiten, und jede Herleitung lässt sich in einer Minute am eigenen Rechner nachmessen.

Gemessen habe ich mit der Docker Engine 29.7.2 unter Windows, direkt in WSL 2, ohne Docker Desktop. Deine Zahlen und PIDs werden andere sein, die Aussagen dahinter nicht.

Warum ein Docker Container in Millisekunden startet

Die Herleitung: Wenn ein Docker Container ein Prozess ist, bootet beim Start nichts. Keine Firmware, kein Kernel, kein Init-System. Der Kernel läuft schon, er startet nur einen weiteren Prozess.

Die Messung: ein Container, der nichts tut, außer sich sofort wieder zu beenden.

time docker run --rm alpine true

Fünf Läufe lagen zwischen 455 und 533 Millisekunden. Das ist die gesamte Strecke: REST-Aufruf an den Daemon, Namespaces und cgroup anlegen, Dateisystem einhängen, Netzwerk verdrahten, Prozess starten, auf sein Ende warten, alles wieder abbauen. Wie viel davon Verwaltung ist, zeigt derselbe Lauf ohne Netzwerk:

time docker run --rm --network none alpine true

Jetzt sind es 324 bis 360 Millisekunden. Rund ein Drittel der Zeit ging also allein dafür drauf, dem Container ein virtuelles Netzwerk-Interface zu bauen und es wieder abzureißen. Auch der Rest ist Buchhaltung und kein Bootvorgang, denn es gibt nichts, das hochfahren müsste.

Warum Docker unter Windows und macOS eine Linux-VM braucht

Die Herleitung: Ein Linux-Prozess braucht einen Linux-Kernel. Ein Image bringt Dateien mit, aber keinen Kernel. Also muss unter Windows und macOS irgendwo ein Linux laufen.

Die Messung: dieselbe Frage an den Host und an zwei Container mit verschiedenen Distributionen.

uname -r
docker run --rm alpine uname -r
docker run --rm debian:13-slim uname -r
6.18.58.1-microsoft-standard-WSL2
6.18.58.1-microsoft-standard-WSL2
6.18.58.1-microsoft-standard-WSL2

Dreimal derselbe Kernel. Alpine und Debian unterscheiden sich nur in den Dateien, die ihr Image mitbringt:

docker run --rm alpine grep PRETTY_NAME /etc/os-release
docker run --rm debian:13-slim grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Alpine Linux v3.24"
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

Der Name des Kernels verrät den Rest: microsoft-standard-WSL2. Auf meinem Windows-Rechner kommt der Linux-Kernel aus WSL 2, und WSL 2 ist selbst eine schlanke virtuelle Maschine. Docker Desktop macht unter Windows und macOS dasselbe: Es startet im Hintergrund eine kleine Linux-VM, und in der laufen die Container. Die VM ist also nicht der Container. Sie ist der Ort, an dem der Kernel wohnt, den sich alle Container teilen.

Warum ein Docker Container schwächer isoliert als eine VM

Die Herleitung: Alle Container teilen sich den Kernel des Hosts, das hat die letzte Messung gezeigt. Zwischen zwei VMs steht ein Hypervisor. Zwischen zwei Containern steht nur die Sichtblende, die ein und derselbe Kernel aufstellt.

Die Messung: ein Container, der fünf Minuten schläft, und dann der Blick vom Host.

docker run -d --name herleitung --memory 64m alpine sleep 300
docker inspect -f '{{.State.Pid}}' herleitung
15964

Das ist die PID des Containers auf dem Host. Mit ihr lässt sich der Prozess ganz normal anschauen:

ps -o user,pid,ppid,comm -p 15964
USER         PID    PPID COMMAND
root       15964   15939 sleep

Der Prozess steht in der Prozessliste des Hosts, und er läuft dort als root. Von innen sieht derselbe Prozess anders aus:

docker exec herleitung ps
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 300
    8 root      0:00 ps

Außen PID 15964, innen PID 1: derselbe Prozess, zwei Sichten. Auch der Ressourcen-Deckel ist nichts weiter als eine Zahl in einer Datei des Kernels:

docker exec herleitung cat /sys/fs/cgroup/memory.max
67108864

Das sind genau die 64 MiB aus dem Startkommando.

Root im Container ist in der Standardkonfiguration derselbe Benutzer wie root auf dem Host. Was ihn zurückhält, sind Namespaces, ein reduzierter Satz an Capabilities und ein Seccomp-Filter, aber kein zweiter Kernel. Deshalb ist eine Kernel-Lücke im Container eine Kernel-Lücke auf dem Host. Und deshalb sind die Option --privileged oder ein hineingereichter Docker-Socket so gefährlich: Sie nehmen genau diese Sichtblende wieder weg. Wie schnell daraus in Kubernetes eine Root-Shell auf dem Node wird, zeigt Ein Pod, und der Server gehört ihm.

Warum Kubernetes ohne dockerd auskommt

Die Herleitung: Wenn am Ende der Kette nur ein Prozess steht, den runc startet und containerd verwaltet, dann wird dockerd für den laufenden Container gar nicht gebraucht.

Die Messung: der Elternprozess des Containers von eben, die PPID 15939 aus der Ausgabe oben.

ps -o user,pid,ppid,comm -p 15939
USER         PID    PPID COMMAND
root       15939       1 containerd-shim

Der Elternprozess heißt containerd-shim-runc-v2, ps kürzt den Namen. Dessen Elternprozess ist die PID 1, also systemd. dockerd taucht in dieser Ahnenreihe nicht auf. Er läuft daneben als eigener Dienst, genau wie containerd selbst.

dockerd ist für den Container also Auftraggeber, nicht Elternteil, und einen Auftraggeber kann man austauschen. Genau das tut Kubernetes: Der Kubelet spricht über die CRI-Schnittstelle direkt mit containerd oder einer anderen Runtime wie CRI-O. Den eingebauten Docker-Adapter dockershim gibt es seit Kubernetes 1.24 nicht mehr. Deine Images laufen trotzdem weiter, weil Image-Format und Runtime als OCI-Standards offen spezifiziert sind. Welche Runtime dein Cluster benutzt, steht in der Spalte CONTAINER-RUNTIME von kubectl get nodes -o wide.

Zum Schluss aufräumen:

docker rm -f herleitung

Fazit

  1. Ein Docker Container ist ein Linux-Prozess, dem der Kernel weniger zeigt und weniger gibt. Vier Dinge folgen daraus von selbst.
  2. Er startet schnell, weil nichts bootet: rund eine halbe Sekunde für Anlegen, Starten und Aufräumen, davon etwa ein Drittel für das Netzwerk.
  3. Er braucht einen Linux-Kernel und bringt keinen mit. Unter Windows und macOS wohnt dieser Kernel in einer VM.
  4. Er isoliert schwächer als eine VM, weil sich alle Container einen Kernel teilen. Root im Container ist root auf dem Host, nur mit Sichtblende.
  5. Er hängt nicht an dockerd. Sein Elternprozess ist der containerd-shim, und deshalb kommt Kubernetes ohne Docker aus.

Das ist die erste Säule einer Plattform, die dir gehört: verstehen, was da läuft, statt Kommandos auswendig zu lernen. Die zweite steckt in denselben Messungen. Namespaces und cgroups gehören zum Linux-Kernel, runc und containerd sind offene Projekte unter dem Dach von Linux Foundation und CNCF, Image-Format und Runtime sind OCI-Standards. Docker Desktop ist ein Produkt mit eigener Lizenz. Der Container darunter gehört keinem Hersteller.

Mit genau diesem Gedanken beginnt meine Docker- und Kubernetes-Schulung, noch bevor Docker überhaupt installiert ist.

© 2026 Trutz Software Consulting GmbH. CC BY 4.0: Dieser Text darf mit Namensnennung weiterverwendet und bearbeitet werden, auch kommerziell. Code-Beispiele darin stehen unter Apache 2.0. Ausgenommen sind Marke und Logo sowie gekennzeichnete Zitate Dritter. Was das genau heißt.

Newsletter

Erhalte praxisnahe Tutorials, Best Practices und echte Lösungen für die häufigsten DevOps-Probleme direkt in Dein Postfach.

Datenschutz: Deine E-Mail-Adresse wird DSGVO-konform in Deutschland gespeichert. Keine Spam, nur relevante Inhalte. Eine E-Mail alle 1 bis 2 Wochen.