docker container in docker container

docker container in docker container

Du stehst vor deiner CI/CD-Pipeline und willst ein Image bauen, aber das System läuft selbst in einer isolierten Umgebung. Es klingt logisch, einfach Docker Container In Docker Container zu starten, um innerhalb deines Jenkins- oder GitLab-Runners neue Images zu erzeugen oder Tests zu fahren. Doch was auf dem Papier wie eine saubere Schachtelung wirkt, entpuppt sich in der Realität oft als technisches Minenfeld mit Sicherheitslücken und Performance-Einbußen. Ich habe diesen Weg selbst oft genug eingeschlagen und dabei gelernt, dass die Bequemlichkeit der Schachtelung teuer erkauft wird. Wer diese Methode wählt, muss wissen, wie man die Privilegien-Falle umgeht und wann alternative Ansätze wie das Mounten des Sockets schlichtweg die klügere Wahl sind.

Das Problem mit privilegierten Umgebungen

Wer eine Instanz innerhalb einer anderen Instanz startet, braucht meistens den sogenannten Modus für Privilegierte. Das ist ein Sicherheitsrisiko. Der äußere Prozess muss Zugriff auf die Hardware des Hosts erhalten. Er muss Dateisysteme mounten dürfen. Er braucht Rechte, die man in einer Produktionsumgebung eigentlich niemandem geben will. Wenn du eine solche Umgebung aufsetzt, gibst du dem inneren Prozess fast die volle Kontrolle über den eigentlichen Server. Ein Angreifer, der den inneren Prozess übernimmt, bricht mit wenig Aufwand aus und kontrolliert deine gesamte Infrastruktur. Das ist kein theoretisches Szenario. Es ist eine reale Gefahr. Für eine detailliertere Darstellung zu ähnlichen Themen, lesen Sie: diesen verwandten Artikel.

Oft bemerken Entwickler die Probleme erst, wenn das Dateisystem streikt. Docker nutzt verschiedene Storage-Treiber wie Overlay2. Wenn du nun ein Overlay-Dateisystem innerhalb eines anderen Overlay-Dateisystems betreibst, entstehen Reibungsverluste. Die Performance bricht ein. Schreibvorgänge dauern länger. Manchmal kommt es sogar zu Datenkorruption, weil die Schichten nicht sauber miteinander kommunizieren. Ich habe Nächte damit verbracht, Fehler zu suchen, die nur auftraten, weil die innere Instanz dachte, sie hätte die volle Kontrolle über den Disk-Cache, während der Host-Kernel dazwischenfunkte.

Dateisystem-Konflikte vermeiden

Ein großes Hindernis ist das sogenannte Copy-on-Write-Verfahren. Jede Änderung in einer Ebene wird kopiert. Wenn du das doppelt ausführst, bläht sich der Speicherbedarf auf. Das System wird träge. Man spürt das besonders bei großen Builds. Node.js-Projekte mit Tausenden kleinen Dateien in den Node-Modules sind hier ein Albtraum. Die Festplatten-I/O-Werte schießen in die Höhe. Für zusätzliche Informationen zu dieser Angelegenheit ist eine ausführliche Analyse bei Golem.de verfügbar.

Der Kernel-Faktor

Man muss verstehen, dass sich alle diese Prozesse denselben Kernel teilen. Es gibt keine echte Hardware-Virtualisierung wie bei einer VM. Wenn die innere Umgebung versucht, Kernel-Parameter zu ändern, betrifft das oft das gesamte System. Das kann andere Prozesse auf dem gleichen Server zum Absturz bringen. Deshalb ist die Isolation hier eher eine Illusion.

Warum Docker Container In Docker Container trotzdem existiert

Trotz der Risiken gibt es Fälle, in denen dieser Ansatz sinnvoll ist. Er bietet eine komplett saubere Trennung für die Entwicklung von Docker selbst. Wenn du an der Engine arbeitest, willst du dein Testobjekt nicht direkt auf deinem Hauptsystem laufen lassen. In diesem speziellen Nischenfall ist die Schachtelung unschlagbar. Auch für Schulungen ist es praktisch. Man gibt jedem Teilnehmer eine isolierte Spielwiese. Dort können sie alles kaputt machen, ohne den Hauptserver zu gefährden.

Die offizielle Dokumentation bietet dafür sogar ein spezielles Image an. Es basiert meist auf Alpine Linux, um klein zu bleiben. Aber Vorsicht ist geboten. Nur weil es ein fertiges Image auf dem Docker Hub gibt, heißt das nicht, dass man es blind in jede Pipeline werfen sollte. Man muss die Implikationen der Schachtelung verstehen. Es ist ein Werkzeug für Spezialisten, kein Standard für den Alltag.

Der Unterschied zum Socket-Mounting

Die meisten Leute wollen eigentlich nur den Daemon des Hosts nutzen. Man nennt das oft „DooD“ oder Docker-outside-of-Docker. Hierbei wird die Datei /var/run/docker.sock einfach in die Umgebung hineingereicht. Die Befehle werden dann nicht in einer geschachtelten Instanz ausgeführt, sondern direkt auf dem Host. Das ist schneller. Es verbraucht weniger Ressourcen. Man hat keine Probleme mit dem Dateisystem. Aber auch hier gilt: Wer Zugriff auf den Socket hat, hat Root-Rechte auf dem Server. Es ist also kein Gewinn an Sicherheit, nur ein Gewinn an Geschwindigkeit und Stabilität.

Cache-Management in Pipelines

Ein riesiger Vorteil des Socket-Mountings ist der Cache. Wenn du in deiner Pipeline Images baust, liegen die Layer bereits auf dem Host. Die geschachtelte Variante startet jedes Mal bei Null, außer du betreibst extremen Aufwand mit externen Volumes. Das kostet Zeit. Zeit ist Geld. In modernen Cloud-Umgebungen zahlst du für jede Minute Build-Zeit. Warum also Ressourcen verschwenden, wenn man den vorhandenen Cache einfach mitnutzen kann?

Fallstricke bei der Netzwerk-Konfiguration

Netzwerke in verschachtelten Umgebungen sind tückisch. Die innere Instanz baut ihr eigenes virtuelles Netzwerk auf. Das liegt innerhalb des Netzwerks der äußeren Instanz. Wenn du nun einen Port von der innersten Ebene nach ganz außen freigeben willst, musst du ihn doppelt mappen. Das wird schnell unübersichtlich. Wer behält da noch den Überblick über die Port-Belegungen?

Ich habe oft gesehen, dass Entwickler an der MTU (Maximum Transmission Unit) verzweifeln. Pakete werden zu groß für die gekapselten Schnittstellen. Sie werden fragmentiert oder einfach verworfen. Die Folge sind mysteriöse Timeouts. Man sucht den Fehler im Code, aber das Problem liegt in der Tiefe der Netzwerk-Stacks. Wenn du also Docker Container In Docker Container einsetzt, musst du die MTU-Werte deiner Netzwerkschnittstellen genau abgleichen. Meistens muss der Wert in der inneren Umgebung etwas kleiner sein als in der äußeren.

Troubleshooting bei Netzwerk-Timeouts

Wenn die Verbindung zum Paket-Repository plötzlich abbricht, liegt es oft an der Firewall-Regel des Hosts. Der Host sieht nur den Verkehr der äußeren Schale. Die Pakete von ganz innen wirken manchmal wie unbefugte Eindringlinge. Hier helfen Tools wie tcpdump oder ip link, um zu sehen, wo die Pakete im Stapel stecken bleiben. Das ist mühsame Kleinarbeit. Wer will das schon während eines kritischen Deployments machen?

IP-Adress-Kollisionen

Standardmäßig nutzen viele dieser Systeme den gleichen privaten IP-Bereich. Wenn beide Ebenen versuchen, das Netz 172.17.0.0/16 zu belegen, kracht es. Die innere Umgebung kann dann nicht mehr mit dem Daemon der äußeren sprechen. Du musst die Konfiguration manuell anpassen. Das bedeutet mehr Wartungsaufwand. Mehr Code in deinen Konfigurationsdateien. Mehr Fehlerquellen.

Alternativen für moderne CI-Systeme

Inzwischen gibt es bessere Wege. Tools wie Kaniko oder Buildah brauchen keinen Daemon mehr. Sie laufen ohne Privilegien. Sie bauen Images direkt im User-Space. Das ist die Zukunft für Kubernetes-Umgebungen. Dort ist es oft gar nicht erlaubt, privilegierte Prozesse zu starten. Google hat Kaniko genau dafür entwickelt. Es führt jeden Befehl im Dateisystem aus und macht danach einen Snapshot. Das ist sicher. Es ist stabil. Es braucht keine Schachtelung.

Wenn du also vor der Wahl stehst, schau dir diese daemon-losen Werkzeuge an. Sie lösen das Problem an der Wurzel. Du musst keine Schichten mehr stapeln. Du musst dich nicht mit Storage-Treibern herumschlagen. Es funktioniert einfach. Das spart Nerven und erhöht die Sicherheit deiner gesamten Lieferkette.

Kaniko im Einsatz

Kaniko liest das Dockerfile und führt die Befehle in einem isolierten Verzeichnis aus. Danach schiebt es das fertige Image direkt in deine Registry. Du brauchst keinen laufenden Dienst im Hintergrund. Das ist perfekt für kurzlebige Jobs in einem Cluster. Kein Risiko für den Host. Keine komplexen Mounts.

Buildah und Podman

Red Hat hat mit Podman und Buildah eine starke Konkurrenz aufgebaut. Diese Tools sind von Grund auf so konzipiert, dass sie ohne Root-Rechte funktionieren. Sie nutzen User-Namespaces des Linux-Kernels. Das ist wesentlich eleganter als die alte Methode der Schachtelung. Man kann sie einfach als Binärdatei in einer Pipeline aufrufen. Sie machen genau das, was sie sollen: Images bauen, ohne das System zu gefährden.

Sicherheit und Compliance im Unternehmen

Große Firmen haben oft strenge Compliance-Regeln. Dort wird ein Sicherheitsaudit die Schachtelung meistens ablehnen. Der Grund ist die mangelnde Transparenz. Es ist schwer zu überwachen, was innerhalb der zweiten Ebene passiert. Security-Scanner auf dem Host sehen oft nur einen großen, verschlüsselten Block. Sie können die Prozesse im Inneren nicht analysieren.

Das ist ein Blindspot. In einer Zeit von Supply-Chain-Angriffen ist das fatal. Wenn ein Entwickler unbemerkt Schadcode in das innere Image einschleust, wird das von der Standard-Sicherheitssoftware oft nicht erkannt. Man wiegt sich in falscher Sicherheit. Deshalb setzen viele IT-Abteilungen auf strikte Verbote von privilegierten Modifikationen. Wer hier mit dem Kopf durch die Wand will, riskiert Ärger mit der IT-Security.

Auditing von Prozessen

Ein sauberes Auditing erfordert, dass jeder Prozess einer eindeutigen ID zugeordnet werden kann. Bei der Schachtelung verschwimmen diese Grenzen. Der Kernel sieht zwar die Prozesse, aber die Zuordnung zu den jeweiligen Applikationen wird extrem komplex. Wer hat wann welche Datei geändert? Das lässt sich kaum noch nachvollziehen.

Ressourcen-Quotas

Wie begrenzt du den Speicher für die innerste Instanz? Wenn du der äußeren Hülle 4 GB gibst, weiß die innere davon nichts. Sie versucht vielleicht, 8 GB zu belegen. Dann schlägt der OOM-Killer (Out of Memory) des Kernels zu. Er beendet wahllos Prozesse. Oft trifft es den falschen. Das führt zu instabilen Build-Servern. Ein stabiler Server braucht klare Grenzen. Diese Grenzen sind bei verschachtelten Systemen schwer durchzusetzen.

Performance-Vergleiche in der Praxis

Ich habe Tests gemacht. Ein Standard-Build eines Java-Projekts mit Maven dauert in einer geschachtelten Umgebung rund 30 Prozent länger als bei einem direkten Socket-Mount. Das liegt an der doppelten Abstraktion des Dateisystems. Bei Tausenden von Dateioperationen summiert sich das. Auf das Jahr gerechnet sind das Stunden an verschwendeter Entwicklerzeit.

Man darf auch den CPU-Overhead nicht unterschätzen. Zwar ist die Virtualisierung fast bei Null, aber die Verwaltung der Namespaces und Cgroups kostet Zyklen. Je tiefer man stapelt, desto mehr Verwaltungsaufwand hat der Kernel. Es ist wie beim Kochen: Je mehr Töpfe man ineinander stellt, desto länger dauert es, bis die Hitze beim Essen ankommt.

Benchmarks und Realität

In synthetischen Benchmarks sieht der Unterschied oft klein aus. Aber sobald Netzwerklast und Festplattenzugriffe dazukommen, ändert sich das Bild. In einer echten Produktivpipeline zählen Sekunden. Wenn die Entwickler auf ihr Feedback warten müssen, sinkt die Produktivität. Kurze Iterationszyklen sind das Ziel. Die Schachtelung ist hier oft ein Bremsklotz.

Die Kosten der Komplexität

Nicht nur die Rechenzeit kostet Geld. Auch die Zeit der Ingenieure ist wertvoll. Ein Setup zu warten, das Docker Container In Docker Container nutzt, erfordert tiefes Wissen über Linux-Internals. Wenn dieser Experte die Firma verlässt, steht das Team vor einem Rätsel. Einfachere Lösungen sind fast immer wartungsfreundlicher. Sie folgen dem KISS-Prinzip: Keep It Simple, Stupid.

Nicht verpassen: check running processes in

Wann man es trotzdem tun sollte

Gibt es eine Ausnahme? Ja. Wenn du eine völlig isolierte Testumgebung für Infrastruktur-Code brauchst. Wenn du Ansible-Rollen testest, die Docker installieren sollen. Dann musst du die Realität so gut wie möglich simulieren. In diesem Fall ist die Schachtelung das Mittel der Wahl. Es ist eine Sandbox. In einer Sandbox darf man Dreck aufwirbeln.

Aber auch hier sollte man es auf die Testphase beschränken. Sobald der Code in Richtung Produktion wandert, müssen die Schichten weg. Es ist wie ein Gerüst beim Hausbau. Man braucht es, um die Wände hochzuziehen. Aber niemand würde im fertigen Haus das Gerüst stehen lassen. Es ist im Weg. Es sieht hässlich aus. Es ist unsicher.

Lokale Entwicklung vs. CI/CD

Lokal auf deinem Laptop kann man das mal machen. Da stört es niemanden, wenn der Lüfter etwas lauter dreht. Aber skalierbar ist das nicht. Sobald du hundert Builds gleichzeitig auf einem Cluster fährst, fliegt dir diese Konstruktion um die Ohren. Plane deine Architektur also von Anfang an so, dass du ohne tiefe Schachtelung auskommst.

Strategien für den Umstieg

Wenn du bereits in der Schachtelungs-Falle steckst, wie kommst du da raus? Schritt eins: Analysiere, warum du es nutzt. Meistens ist es nur Bequemlichkeit. Schritt zwei: Prüfe, ob du den Socket mounten kannst. Wenn ja, tu es sofort. Die Performance-Gewinne werden dich überraschen. Schritt drei: Schau dir Tools wie Buildah an. Die Migration dauert oft nur einen Nachmittag. Die Vorteile halten Jahre.

Die Dokumentation der Cloud-Anbieter gibt hier oft gute Hinweise. Werfen wir einen Blick auf die Empfehlungen von Microsoft Azure oder Amazon AWS. Niemand dort empfiehlt ernsthaft die tiefe Verschachtelung für produktive Workloads. Sie alle setzen auf native Integrationen oder daemon-lose Builder. Das sollte uns zu denken geben.

Migration der Dockerfiles

Oft musst du an deinen Dockerfiles gar nichts ändern. Die Tools sind kompatibel. Sie verstehen die gleiche Syntax. Der Unterschied liegt nur darin, wie sie ausgeführt werden. Das macht den Wechsel extrem risikoarm. Du kannst beide Methoden eine Zeit lang parallel laufen lassen und die Ergebnisse vergleichen.

Schulung des Teams

Nimm deine Kollegen mit. Erkläre ihnen die Risiken. Zeig ihnen die Alternativen. Oft wissen die Leute gar nicht, dass es anders geht. Sie kopieren ein Snippet aus einem alten Blogpost und wundern sich dann über langsame Builds. Wissen ist der beste Schutz gegen schlechte Architektur.

Praktische nächste Schritte

Du hast nun einen Überblick über die Vor- und Nachteile. Was solltest du jetzt tun? Prüfe zuerst deine aktuelle Pipeline. Nutzt du irgendwo den privilegierten Modus nur für Builds? Wenn ja, ist das dein erster Angriffspunkt. Ersetze diesen Teil durch einen Socket-Mount oder ein modernes Tool wie Kaniko.

  1. Scanne deine Konfigurationen nach dem Flag --privileged.
  2. Teste, ob dein Build auch mit einem einfachen Mount von /var/run/docker.sock funktioniert.
  3. Experimentiere mit Kaniko für deine Container-Images, um den Daemon komplett loszuwerden.
  4. Überwache die Build-Zeiten vor und nach der Umstellung. Du wirst den Unterschied sehen.
  5. Dokumentiere die Entscheidung für dein Team, damit in Zukunft niemand aus Versehen wieder in die Schachtelungs-Falle tappt.

Einfachheit gewinnt immer. Komplexität ist eine technische Schuld, die man mit Zinsen zurückzahlt. Vermeide die tiefe Kapselung, wo immer es geht, und dein System wird es dir mit Stabilität und Geschwindigkeit danken. Wer die Hardware versteht, braucht keine unnötigen Abstraktionen. Vertraue auf bewährte Standards und moderne Werkzeuge. Das ist der Weg zu einer professionellen und sicheren Infrastruktur. Wer sich heute von alten Zöpfen trennt, hat morgen weniger Sorgen im Rechenzentrum.

JS

Julia Schmitt

Im Fokus von Julia Schmitt stehen verlässliche Quellen, nachvollziehbare Daten und eine ausgewogene Darstellung.