Alle Updates
1. Juli 2026Architektur

Vom geteilten Docker Daemon zur Sandbox pro Run

Knecht kann aus einem Container heraus echte DDEV-Projekte booten. Was der Test gezeigt hat und warum jeder Run künftig seine eigene Sandbox bekommt.

Dieser Post ist ein Blick unter die Haube. Die Container-Architektur ist der Unterbau, damit parallele Previews mit DDEV-Projekten funktionieren, nicht das Produkt selbst. Was Knecht macht und für wen er gedacht ist, steht auf der Startseite und in Was macht der Knecht.Update, Juli 2026: Wir haben die Sysbox-Sandbox gebaut, und sie lief. Trotzdem haben wir sie wieder ausgebaut. Warum, steht in der Fortsetzung Zurück zum geteilten Daemon. Der Weg zur Entscheidung unten bleibt trotzdem lesenswert, die Fortsetzung baut darauf auf.

Knecht läuft selbst als Docker Container, muss aber DDEV-Projekte hochfahren, die wieder aus Containern bestehen. Ob das überhaupt funktioniert, war die riskanteste Annahme der ganzen Architektur. Deshalb haben wir sie zuerst getestet, noch bevor der eigentliche Code entsteht.

Der Ansatz

Kurz zum Hintergrund: Docker besteht aus zwei Teilen. Der Docker Daemon ist der Dienst, der Container tatsächlich erstellt und verwaltet. Die Docker CLI ist nur ein Client, der über einen Unix-Socket (/var/run/docker.sock) mit dem Daemon spricht. Wer den Socket hat, steuert den Daemon.

Genau das nutzt Knecht: Der Container startet keinen eigenen Daemon, sondern mountet den Socket des Hosts und steuert damit den Host-Daemon. Das Muster heißt Docker-out-of-Docker (DooD). Die DDEV-Container laufen dann als Geschwister neben dem Knecht-Container auf dem Host, nicht verschachtelt in ihm. Coolify und viele CI-Runner arbeiten genauso.

Der Test

Host-Daemon erreichbar

docker ps im Container zeigt die Host-Container. Der Socket-Mount funktioniert.

DDEV-Projekt bootet

Ein minimales PHP-Projekt am festen Pfad, dann ddev start. DDEV startet Webserver und Datenbank auf dem Host.

Container sind Host-Geschwister

Auf dem Host tauchen die Projekt-Container als normale Nachbarn des Knecht-Containers auf.

App erreichbar

Das gebootete Projekt antwortet. Wichtig dabei: *.ddev.site löst per DNS immer auf 127.0.0.1 auf, also auf den Container selbst. Der Preview-Proxy muss den Web-Container deshalb direkt über das Docker-Netzwerk ansprechen.

Damit ist die Basis bewiesen: Ein Prozess im Knecht-Container kann echte DDEV-Stacks booten, mit korrekt gemountetem Source Code.

Zwei Probleme sind geblieben

Der Test hat aber auch die Grenzen des Ansatzes gezeigt.

Keine Isolation zwischen Runs

Alles läuft auf einem gemeinsamen Daemon. Knecht soll aber mehrere Previews parallel fahren, ohne dass sich Runs gegenseitig stören. Wir mussten sogar den DDEV-Router weglassen. Das ist der Reverse Proxy, den DDEV vor alle Projekte stellt und der die Ports 80 und 443 auf dem Host bindet. Feste Host-Ports gibt es nur einmal, bei vielen parallelen Projekten kollidiert das. Ohne Router muss Knecht in die .ddev/config.yaml eingreifen und zum Beispiel dir Urls überschreiben.

Fremder Code am Host-Socket

Der Agent führt Code aus, und wir kontrollieren nicht vollständig, was er tut. Ein Agent lässt sich über Prompt Injection kapern, etwa durch manipulierte Inhalte im Repo oder in einer Datenquelle, und macht dann nicht mehr das, was wir wollten. Wer an dieser Stelle an den Host-Socket kommt, steuert den Daemon, und wer den Daemon steuert, kann jeden Container mit jedem Mount starten. Das ist faktisch Root auf dem Server.

Die Lösung: eine Sandbox pro Run

Beide Probleme haben dieselbe Antwort: Jeder Run bekommt seinen eigenen Docker Daemon in einer eigenen Sandbox. Damit verschwindet auch der Grund, den Router wegzulassen. Port 80 in Sandbox A kann nicht mit Sandbox B kollidieren, weil jede Sandbox ihren eigenen Netzwerk-Namespace hat. Projekte laufen also wieder mit allen ihren URLs und Settings.

Bleibt die Frage, was die Sandbox ist. Wir haben uns die üblichen Kandidaten angesehen.

Privileged Docker-in-Docker

Ein zweiter Daemon in einem Container mit --privileged. Die Flag schaltet praktisch alle Schutzmechanismen ab und gibt dem Container Zugriff auf die Host-Geräte. Eine bösartige Dependency kommt damit ohne Exploit auf den Host. Fällt raus.

Kata Containers

Kata startet jeden Container in einer leichtgewichtigen VM mit eigenem Kernel. Das ist die stärkste Grenze und der Ansatz hinter Firecracker, auf dem etwa AWS Lambda läuft. Kata braucht aber /dev/kvm, und normale Cloud-VPS bieten keine Nested Virtualization. Das würde Bare-Metal erzwingen und kollidiert mit dem Ziel, Knecht auf einem normalen VPS zu installieren. Fällt raus.

gVisor

gVisor fängt Syscalls in einem Userspace-Kernel ab und braucht kein KVM. Es isoliert Anwendungsprozesse gut, tut sich aber schwer damit, selbst ein Docker-Host zu sein: iptables wird nur teilweise unterstützt und Overlayfs bricht mit Docker v29. Genau ein Docker-Host ist aber, was DDEV braucht. Fällt raus.

Unsere Wahl: Sysbox

Sysbox ist eine Container-Runtime, die Docker-in-Docker ohne --privileged erlaubt. Sie nutzt dafür User Namespaces, Root im Container wird auf einen unprivilegierten User auf dem Host gemappt. Sysbox ist genau für diesen Fall gebaut, braucht kein KVM und läuft damit auf jedem normalen Linux-Server.

Das Threat Model entscheidet

Den Ausschlag gibt am Ende nicht die Runtime, sondern das Threat Model, also die Frage, wer hier eigentlich angreift und was er erreicht. Knecht ist Single-Tenant: eine Agentur, ihre Projekte, ihr Server. Die VM-Grenze von Kata schützt vor allem davor, dass ein Kunde aus seiner Umgebung in die eines anderen ausbricht. Diesen Fall gibt es hier nicht.

Wie es weitergeht

Als Nächstes bauen wir die Sysbox-Sandbox pro Run (eigener Daemon, DDEV inklusive Router) und einen zentralen Ingress mit Auth-Gate, der Preview-URLs in die richtige Sandbox routet. Der nächste Meilenstein: DDEV mit Router in einer Sysbox-Sandbox auf einem echten Linux-Host, erreichbar vom Ingress.

Vielleicht gibt es auch schon den ersten Showcase vom Prototypen.

Mitmachen

Bau Knecht mit von Anfang an.

Knecht ist noch in Entwicklung. Werde Beta-Tester und gib direkt Feedback, oder bleib einfach per Update auf dem Laufenden.

Wie möchtest du dabei sein?

nur Fortschritt · jederzeit abbestellbar