containerd containerd

Von Docker zu containerd: Eine kurze Geschichte der Kubernetes-Runtimes

Warum Kubernetes aufgehört hat, direkt mit Docker zu sprechen, und was containerd im Verhältnis dazu eigentlich ist.

9 min Anfänger

Ältere Kubernetes-Tutorials gehen davon aus, dass Docker die Container-Runtime ist. Aktuelle gehen von containerd aus. Keines ist falsch: Sie beschreiben unterschiedliche Zeitpunkte in der Geschichte von Kubernetes. Zu verstehen, was sich geändert hat, klärt den Großteil der Verwirrung um ctr, crictl und die Frage, warum docker ps auf einem Cluster-Knoten nichts Nützliches mehr anzeigt.

Docker kam zuerst, und Kubernetes wurde darum herum gebaut

Docker machte Container nutzbar: eine CLI, ein Image-Format, ein Daemon, der alles ausführte. Das frühe Kubernetes wurde speziell dafür gebaut, Docker-Container zu orchestrieren, und beide waren eng gekoppelt. Als Kubernetes wuchs, wollten auch andere Runtimes (unter anderem rkt) integriert werden. Dafür brauchte Kubernetes einen Weg, mit mehr als einer Runtime zu arbeiten, statt fest an die API von Docker gebunden zu sein.

CRI und OCI: die Schnittstelle standardisieren

Kubernetes’ Antwort war das Container Runtime Interface (CRI), eine gRPC-API, über die der kubelet mit der jeweils installierten Runtime spricht, ohne für jede runtime-spezifischen Code zu brauchen. Jede Runtime, die CRI implementiert, kann sich in Kubernetes einklinken.

CRI selbst stützt sich auf Standards der Open Container Initiative (OCI), einer Spezifikation, die Docker mit etabliert hat, damit das Ökosystem nicht von der Implementierung eines einzelnen Anbieters abhängt:

  • Die Image-Spec definiert, wie ein Container-Image aufgebaut und adressiert wird, damit ein mit einem Werkzeug gebautes Image von einem anderen ausgeführt werden kann.
  • Die Runtime-Spec definiert, wie ein Container auf einem Host tatsächlich erstellt und ausgeführt werden soll, bis hinunter zu Namespaces, Mounts und Prozesskonfiguration.
  • Die Distribution-Spec (später hinzugekommen) definiert, wie Images in eine Registry gepusht und aus ihr gepullt werden.

Zusammen bedeuten CRI und OCI, dass Runtime und Orchestrator nicht mehr dasselbe Produkt sein müssen, nicht einmal vom selben Anbieter.

Docker ist älter als CRI, also musste Kubernetes eine Brücke bauen

Docker wurde nicht gebaut, um CRI zu sprechen, da CRI noch nicht existierte, als Docker entstand, und Docker blieb trotzdem die dominierende Runtime. Kubernetes’ Behelf war dockershim: eine Kompatibilitätsschicht, die CRI-Aufrufe in Dockers eigene API übersetzte, sodass der kubelet weiter mit Docker arbeiten konnte, ohne dass sich Docker selbst ändern musste.

containerd steckte schon in Docker

Docker war nie nur eine Runtime. Es bündelte eine CLI, ein Build-System, Volume- und Netzwerkverwaltung, Authentifizierung und, darunter, die Komponente, die Container tatsächlich ausführte: einen Daemon namens containerd, der auf der Low-Level-Runtime runc aufsetzt. containerd wurde als eigenes Projekt herausgelöst und an die CNCF gespendet, wo es 2019 graduierte, und anders als Dockers nutzerseitige Werkzeuge spricht es CRI nativ. Das ist die ganze Beziehung in einem Satz: containerd ist die Runtime-Komponente, die schon immer in Docker steckte und nun eigenständig und CRI-kompatibel verfügbar ist.

Das Ende von dockershim

Eine Übersetzungsschicht für eine einzige Runtime zu pflegen, während jede andere Runtime direkt CRI sprach, war laufender Aufwand bei schwindendem Nutzen. Kubernetes hat dockershim mit dem Release 1.24 (2022) entfernt, und damit auch die direkte Unterstützung, Docker als Container-Runtime eines Clusters zu betreiben.

Das hat bestehende Images nicht kaputt gemacht. Docker baute Images nach der OCI-Image-Spec, sodass alles, was bereits in einer Registry liegt, auf containerd genauso läuft wie zuvor. Was nicht mehr funktionierte, war, die Docker Engine selbst als das zu verwenden, was auf einem Knoten tatsächlich Container ausführt. Cluster mussten auf eine CRI-native Runtime wie containerd oder CRI-O umsteigen.

Was das heute auf einem Knoten bedeutet

docker ps existiert auf einem modernen Knoten entweder nicht oder zeigt nichts Relevantes, weil Docker nicht das ist, was deine Container ausführt. Die Werkzeuge dafür sind crictl, ctr und nerdctl, und die nächste Anleitung dieser Reihe behandelt, wann du welches nimmst. Die Container-Images selbst, die eigentlichen Anwendungsschichten, sind von dieser ganzen Geschichte unberührt. Geändert hat sich ausschließlich die Technik darunter.

Beliebte Anleitungen