← Blog

Der Container, den es nie gab

Ein Freund von uns hat eine 12-GB-Karte und ein gesundes Misstrauen gegenüber Software. Als wir ihn baten, das Hosten auszuprobieren, fragte er nicht, was er verdienen würde. Er fragte: „Und welche Docker-Images wollt ihr auf meinem PC laufen lassen?"

Es ist genau die richtige Frage, und die ehrliche Antwort überraschte ihn: keine. Nicht „ein kleines", nicht „ein sandboxed". Es gibt kein Image, keinen Daemon, kein Root. Zu dieser Antwort brauchte es ein paar Monate Design, und sie ist es wert, aufgeschrieben zu werden — denn die Überlegung gilt für jeden, der entscheidet, was der Computer eines Fremden ausführen soll.

Das offensichtliche Design, und warum wir es nicht ausgeliefert haben

Jeder Serving-Stack des Jahres 2026 wird als Container ausgeliefert. vLLM veröffentlicht CUDA- und ROCm-Images; jedes Inferenz-Framework, das den Namen verdient, ebenso. Die offensichtliche Architektur schreibt sich von selbst: Die Steuerungsebene sagt einem Host, welches Image er ziehen soll, der Host führt es aus, Feierabend.

Wir bauten den Plan, rechneten ihn für eine Heim-Maschine durch und blieben an der ersten Zeile der Schätzung hängen. Ein vLLM-Image hat 10 bis 30 GB. Obendrauf braucht der Host eine Container-Runtime, ein GPU-Container-Toolkit, dazu passende Treiberverkabelung und — auf den meisten Distributionen — einen privilegierten Installationsschritt. Das ist eine erhebliche Zumutung, bevor ein einziges Token bedient wurde, und es ist eine Menge Angriffsfläche auf einer Maschine, auf der auch jemandes Fotos liegen.

Dabei lag die Alternative direkt vor uns. llama.cpp ist ein ~5-MB-Binary. Ein einziger Build davon — der Vulkan-Build — bedient AMD-, NVIDIA- und Intel-GPUs aus derselben Datei. Er startet in Sekunden, läuft als unprivilegierter Nutzer und bindet sich nur an localhost.

Für die Maschinen, die wir wirklich im Pool haben wollen — Gaming-PCs, Workstations, die RX 6900 XT unter einem Schreibtisch — ist das 5-MB-Binary nicht der Kompromiss. Es ist die bessere Ingenieursarbeit.

Was wir am Ende installieren

Zwei Dateien, und von beiden können Sie den Quelltext lesen.

mahout ist unser Agent: ein Rust-Binary, das die Hardware sondiert, die Maschine mit einem Einmal-Code anmeldet, Modellgewichte herunterlädt und verifiziert, die Engine beaufsichtigt, Arbeit abholt und für jeden Job eine Quittung signiert. Rund 5 MB, Open Source, kein Root.

Die Engine ist ein gepinntes llama.cpp-Release, einmal heruntergeladen und gegen eine SHA-256-Prüfsumme geprüft, die in das mahout-Binary selbst einkompiliert ist. Ist die ankommende Datei nicht die gepinnte, wird sie verworfen, und nichts läuft.

Das ist der gesamte Fußabdruck. Auf einer Host-Maschine landen ein Agent, eine Engine und einige Modellgewichte in einem Cache-Verzeichnis — alles benannt, mit Prüfsummen versehen und mit einem Befehl entfernbar.

Der Teil, in dem Container ihr Geld wert sind

Nichts davon heißt, dass Container falsch sind. Es heißt, dass sie hier falsch sind, vorerst.

Wenn eine einzelne Karte viele gleichzeitige Anfragen bedient, ziehen vLLMs Continuous Batching und Paged Attention entschieden davon. Das ist eine Workstation- und Datacenter-Geschichte — die Stufe, auf der eine Maschine zum Bedienen gekauft wird, statt zwischen Gaming-Sessions ausgeliehen. Wir werden sie wollen, und die Architektur hat die Naht bereits: In unserem Katalog gehört die Engine zum Build, nicht zum Host. vLLM hinzuzufügen heißt, einen Eintrag hinzuzufügen, nicht den Agenten neu zu schreiben.

Wenn das kommt, gelten drei Regeln — dieselben, die schon für Modellgewichte gelten:

  • Gepinnt per Digest, nie per Tag. vllm/vllm-openai@sha256:… ist eine bestimmte Menge Bytes. :latest ist ein Versprechen, das jemand anderes stillschweigend ändern kann.
  • Allow-Liste im Client. Die Liste der Images, die ein Host ausführen darf, ist in das mahout-Release einkompiliert. Die Steuerungsebene kann eines davon anfordern; sie kann kein neues einführen. Selbst wenn wir je kompromittiert würden, könnten wir Ihrer Maschine nichts Beliebiges zum Ausführen geben — wir müssten ein neues signiertes Binary ausliefern, öffentlich, für alle sichtbar.
  • Kein Netzausgang, Gewichte nur lesbar. Der Container spricht mit mahout auf localhost und mit sonst nichts.

„Und wo liegen die Images?"

Die Anschlussfrage unseres Freundes, natürlich. Hier haben wir uns selbst überrascht.

Der Instinkt jedes Infrastruktur-Ingenieurs ist zu spiegeln: eine eigene Registry betreiben, alles darüber ziehen, die Lieferkette kontrollieren. Fast hätten wir es getan. Dann fragten wir, was das Spiegeln eines Upstream-Images tatsächlich einbringt, wenn wir es ohnehin per Digest referenzieren — und die Antwort war: nichts. Einen Digest verifiziert die Container-Runtime beim Hereinholen. Stimmen die Bytes mit dem Digest überein, sind es die Bytes, die wir getestet haben — ob sie von Docker Hub kommen oder von einem Server in unserem eigenen Rack. Selbst zu hosten würde Dutzende Gigabyte Speicher, eine Backup-Geschichte und eine Monitoring-Geschichte hinzufügen, im Tausch gegen null zusätzliche Garantie.

Also spiegeln wir nicht. Wir pinnen.

Es gibt genau einen Fall, in dem wir eine eigene Registry betreiben werden, und es geht dabei nicht um Kontrolle über die Lieferkette — sondern darum, dass das Image unseres sein wird. Zu verifizieren, dass ein Host wirklich das Modell ausgeführt hat, das er behauptet, verlangt einen Engine-Build, der beim Dekodieren ein kryptografisches Commitment auf seine eigenen Aktivierungen ausgibt. Das ist eine gepatchte Engine, also ein Image, das wir selbst bauen, also ein Ort, es zu veröffentlichen: eine EU-Registry, signiert, per Digest gepinnt, genau wie alles andere. Diese Infrastruktur an dem Tag zu bauen, an dem wir sie brauchen, statt an dem Tag, an dem wir uns einbilden, sie zu brauchen — das war das stille Leitmotiv des ganzen Projekts.

Wie das von außen aussieht

Unser Freund hatte es in etwa vier Minuten installiert:

curl -fsSL https://elephantpool.ai/install-mahout.sh | sh

# Windows (PowerShell)
irm https://elephantpool.ai/install-mahout.ps1 | iex
mahout models
mahout up --code HIS-CODE
mahout bench --model gpt-oss-20b

mahout models sagte ihm, was seine 12-GB-Karte bedienen kann, bevor er sich zu einem einzigen Download verpflichtete. Der Benchmark maß, was sie wirklich leistet, statt was eine Tabelle vorhersagte — und diese Messung, nicht unsere Schätzung, zeigt sein Dashboard jetzt als Verdienst pro bedienter Stunde.

Er hat nie Docker installiert. Er hat nie sudo getippt. Und wenn er es loswerden will, zeigt mahout uninstall einen Löschplan mit Größenangaben, bevor irgendetwas angefasst wird.

Das ist am Ende das ganze Argument. Software, die unbeaufsichtigt auf fremder Hardware läuft, sollte klein genug sein, um sie zu lesen, straff genug gepinnt, um sie zu verifizieren, und leicht genug zu entfernen, dass der Abschied nie ein Kampf ist.

Die vollständige Architektur lesen · Was auf Ihrer Maschine läuft · Die Modelle ansehen · mahout installieren

Read next

a GPU died mid-sentence. the sentence finished.

Consumer hardware disappears without notice — someone sits down at their PC, a breaker trips, Wi-Fi drops. Our streams now survive that: another machine picks the answer up mid-word, and the dead segment is billed to nobody.

one model, every card: how a 27b runs on 8 gb

Qwen3.8 27B ships in five builds, from Q5_K_M on a 24 GB card down to IQ2_XXS on 8 GB. Why we split models from builds, what quantization actually costs, and how a quantized KV cache doubled our context overnight.

Model catalogue · Knowledge base · Run a GPU