Wie (und warum) wird Docker in Docker ausgeführt

0
12

Wenn Sie Docker in Docker ausführen, können Sie Images erstellen und Container in einem bereits containerisierten . starten Umgebung. Es gibt zwei mögliche Ansätze, um dies zu erreichen, je nachdem, ob Sie untergeordnete oder gleichgeordnete Container starten möchten.

Der Zugriff auf Docker aus einem Docker-Container ist am häufigsten im Kontext von CI- und CD-Systemen wünschenswert. Es ist üblich, die Agenten, die Ihre Pipeline ausführen, in einem Docker-Container zu hosten. Am Ende verwenden Sie eine Docker-in-Docker-Strategie, wenn eine Ihrer Pipeline-Stufen dann ein Image erstellt oder mit Containern interagiert.

Das Docker-in-Docker-Image

Docker wird als eigenständiges Image über das docker:dind-Tag auf Docker Hub bereitgestellt. Wenn Sie dieses Image starten, erhalten Sie eine funktionierende Docker-Daemon-Installation in Ihrem neuen Container. Es funktioniert unabhängig vom Daemon Ihres Hosts, der den Dind-Container ausführt, sodass docker ps innerhalb des Containers andere Ergebnisse liefert als docker ps auf Ihrem Host.

docker run -d –privileged –name docker -e DOCKER_TLS_CERTDIR=/certs -v docker-certs-ca:/certs/ca -v docker-certs-client:/certs/client docker:dind

Verwendung von Docker- in-Docker hat auf diese Weise eine große Einschränkung: Sie müssen den privilegierten Modus verwenden. Diese Einschränkung gilt auch dann, wenn Sie Rootless-Container verwenden. Der privilegierte Modus wird durch das Flag –privileged im oben gezeigten Befehl aktiviert.

Die Verwendung des privilegierten Modus gibt dem Container vollständigen Zugriff auf Ihr Hostsystem. Dies ist in einem Docker-in-Docker-Szenario erforderlich, damit Ihr innerer Docker neue Container erstellen kann. In manchen Umgebungen kann dies jedoch ein inakzeptables Sicherheitsrisiko darstellen.

Werbung

Es gibt auch andere Probleme mit Dind. Bei bestimmten Systemen können Konflikte mit Linux-Sicherheitsmodulen (LSM) wie AppArmor und SELinux auftreten. Dies tritt auf, wenn der innere Docker LSM-Richtlinien anwendet, die der äußere Daemon nicht vorhersehen kann.

Eine weitere Herausforderung betrifft Container-Dateisysteme. Der äußere Daemon wird auf dem regulären Dateisystem Ihres Hosts wie ext4 ausgeführt. Alle seine Container, einschließlich des inneren Docker-Daemons, werden jedoch auf einem Copy-on-Write-Dateisystem (CoW) sitzen. Dies kann zu Inkompatibilitäten führen, wenn der innere Daemon so konfiguriert ist, dass er einen Speichertreiber verwendet, der nicht auf einem vorhandenen CoW-Dateisystem verwendet werden kann.

Mounten Sie stattdessen den Docker-Socket Ihres Hosts

Die mit dind verbundenen Herausforderungen lassen sich am besten angehen, indem man ganz auf die Verwendung verzichtet. In vielen Szenarien können Sie den gewünschten Effekt erzielen, indem Sie den Docker-Socket Ihres Hosts in einen normalen Docker-Container einbinden:

docker run -d –name docker -v /var/run/docker.sock:/var/run/docker.sock docker:latest

Die Docker-CLI im Docker-Image interagiert mit dem Docker-Daemon-Socket, das sie unter /var/run/docker.sock findet. Das Einhängen des Sockets Ihres Hosts in diesen Pfad bedeutet, dass im Container ausgeführte Docker-Befehle gegen Ihren vorhandenen Docker-Daemon ausgeführt werden.

Dies bedeutet, dass sich Container, die vom inneren Docker erstellt wurden, auf Ihrem Host-System befinden, neben dem Docker-Container selbst. Alle Container werden als Geschwister existieren, auch wenn es sich anfühlt, als ob der verschachtelte Docker ein untergeordnetes Element des übergeordneten Elements ist. Das Ausführen von docker ps führt zu denselben Ergebnissen, unabhängig davon, ob es auf dem Host oder in Ihrem Container ausgeführt wird.

Diese Technik mildert die Implementierungsherausforderungen von dind. Es macht auch die Verwendung des privilegierten Modus überflüssig, obwohl das Mounten des Docker-Sockets selbst ein potenzielles Sicherheitsproblem darstellt. Alles, was Zugriff auf den Socket hat, kann Anweisungen an den Docker-Daemon senden und bietet die Möglichkeit, Container auf Ihrem Host zu starten, Images abzurufen oder Daten zu löschen.

Wann sollte jeder Ansatz verwendet werden

Docker-in-Docker über dind ist in der Vergangenheit in CI-Umgebungen weit verbreitet. Es bedeutet das “innere” Container haben eine Isolationsschicht vom Host. Ein einzelner CI-Runner-Container unterstützt jeden Pipeline-Container, ohne den Docker-Daemon des Hosts zu verschmutzen.

Werbung

Obwohl es oft funktioniert, ist dies mit Nebenwirkungen behaftet und nicht der beabsichtigte Anwendungsfall für Dind . Es wurde hinzugefügt, um die Entwicklung von Docker selbst zu erleichtern, nicht um Endbenutzer-Support für verschachtelte Docker-Installationen zu bieten.

Laut Jérôme Petazzoni, dem Schöpfer der dind-Implementierung, sollte der Socket-basierte Ansatz Ihre bevorzugte Lösung sein. Das Binden des Daemon-Sockets Ihres Hosts ist sicherer, flexibler und genauso umfassend wie das Starten eines Dind-Containers.

Wenn Ihr Anwendungsfall bedeutet, dass Sie dind unbedingt benötigen, gibt es einen sichereren Weg, es bereitzustellen. Das moderne Sysbox-Projekt ist eine dedizierte Container-Laufzeit, die andere Laufzeiten verschachteln kann, ohne den privilegierten Modus zu verwenden. Sysbox-Container werden VM-ähnlich, sodass sie Software unterstützen können, die normalerweise Bare-Metal auf einer physischen oder virtuellen Maschine ausgeführt wird. Dazu gehören Docker und Kubernetes ohne spezielle Konfiguration.

Schlussfolgerung

Das Ausführen von Docker innerhalb von Docker ist eine relativ häufige Anforderung. Sie werden es höchstwahrscheinlich beim Einrichten von CI-Servern sehen, die Container-Image-Builds aus von Benutzern erstellten Pipelines unterstützen müssen.

Mit docker:dind erhalten Sie einen unabhängigen Docker-Daemon, der in seinem eigenen ausgeführt wird Container. Es erstellt effektiv untergeordnete Container, die vom Host aus nicht direkt sichtbar sind. Während es eine starke Isolation zu bieten scheint, birgt Dind tatsächlich viele Randfallprobleme und Sicherheitsbedenken. Diese sind auf die Betriebssysteminteraktionen von Docker zurückzuführen.

Werbung

Das Einbinden des Docker-Sockets Ihres Hosts in einen Container, der die Docker-Binärdatei enthält, ist eine einfachere und vorhersehbarere Alternative. Dadurch kann der verschachtelte Docker-Prozess Container starten, die zu seinen eigenen Geschwistern werden. Bei Verwendung des Socket-basierten Ansatzes sind keine weiteren Einstellungen erforderlich.