gvx: Ausführung von Linux-Containern, Docker und Kubernetes in einem einzigen unprivilegierten Prozess

Einführung: Sicherheitsgehärtete Container ohne Root oder Host-Daemons
Das Ausführen von Linux-Containern, docker build oder Kubernetes innerhalb eines Entwicklungsrechners, eines CI-Runners oder eines Multi-Tenant-Cloud-Knotens erzwingt üblicherweise einen unangenehmen Sicherheitskompromiss:
- Unter Linux erfordern Standard-OCI-Runtimes (
runc,crun,runsc) entwederroot-Rechte, die Exposition des Host-Sockets/var/run/docker.sock,--privileged(CAP_SYS_ADMIN) oder User Namespaces (unshare(CLONE_NEWUSER)), die die Angriffsfläche des Host-Kernels vergrößern. - Unter Windows und macOS starten Container-Engines (
Docker Desktop,Podman Machine,Lima,OrbStack) einen vollständigen Linux-Virtual-Machine-Kernel innerhalb von WSL2, Hyper-V oderVirtualization.frameworkund betreiben in dieser VM einen persistenten Hintergrunddaemon.
gvx (rungv CLI und das z.gfire.dev/gvx/pkg/gvx Go SDK) bietet eine sichere Alternative ohne Privilegien. Als upstream-nachverfolgbarer Fork des User-Space-Linux-Kernels Sentry von Googles gVisor und des User-Space-Netzwerkstacks netstack konzipiert, führt gvx unveränderte linux/amd64- und linux/arm64-ELF64-Binärdateien sowie OCI-Container direkt innerhalb eines einzigen unprivilegierten, selbst gesperrten Host-Prozesses unter Windows, macOS und Linux aus.
Sicherheitsgarantie (Drei-Ring-Defense-in-Depth):
gvxschwächt niemals die Sicherheitsgrenzen des Host-Betriebssystems, installiert niemals Kernel-Treiber und erfordert niemalsroot,sudo,--privilegedauf dem Host oderCLONE_NEWUSER. Bevor auch nur eine einzige Gast-Instruktion ausgeführt wird, sperrtgvxseinen eigenen Host-Prozess mithilfe von Windows Restricted Tokens und Job Objects, macOS Seatbelt (deny default) oder LinuxPR_SET_NO_NEW_PRIVS+ BPF-seccomp. Alle Gast-Systemaufrufe, virtuellenUID 0-Privilegien, Mounts (VFS2) und Netzwerktabellen (netstack) sind strikt innerhalb des speichersicheren Go-Sentry-Kernels eingeschlossen.
| Runtime | Host-Betriebssystem | Kaltstart | Speicherbedarf | Administrator- oder sudo-Rechte nötig | Hintergrund-VM-Daemon | Direkte Ausführung von OCI-Images |
|---|---|---|---|---|---|---|
gvx (whpx / hvf) | Windows (amd64, arm64) & macOS (arm64) | ~20 ms | ~30 MiB | Nein | Nein | Ja |
gvx (systrap) | Windows (amd64, arm64) & Linux (amd64, arm64) | ~25 bis 65 ms | ~31 MiB | Nein | Nein | Ja |
| WSL2 / Docker Desktop | Windows & macOS | 800 bis 2500 ms | > 512 MiB | Ja (Ersteinrichtung) | Ja | Erfordert Daemon |
| QEMU (Full System) | Windows & macOS | 1500 bis 4000 ms | > 256 MiB | Nein | Nein | Erfordert Disk Image |
Auf Windows oder macOS wird kein Linux-VM-Kernel gestartet. Auf dem Host läuft kein Hintergrunddaemon. Für das Host-Betriebssystem sind keine root-, sudo-, User-Namespace- (CLONE_NEWUSER), mount(2)-, TUN/TAP-Treiber- oder CAP_NET_ADMIN-Privilegien erforderlich. Innerhalb dieses unprivilegierten Prozesses führt gvx Docker-in-Docker (docker:dind), docker build, docker compose sowie hochverfügbares Multi-Node-Kubernetes (k3s mit eingebettetem etcd und Calico CNI) aus.
Container-Lebenszyklus und Drei-Ring-Host-Sperrung
Jede gvx-Sandbox läuft innerhalb eines unprivilegierten Host-Prozesses und durchläuft einen dreiphasigen Lebenszyklus: Vorab-Öffnung aller erforderlichen Host-File-Deskriptoren und Sockets, Sperrung des Host-Betriebssystemprozesses über pkg/hostlockdown und Eintritt in die prozessinterne Sentry-Ausführungsschleife.

Bevor die Kontrolle an die erste Gast-Instruktion übergeben wird, öffnet gvx vorab seine zwischengespeicherten .erofs-Image-Layer-Deskriptoren, .ext4-Volume-Deskriptoren, das /workspace-*os.Root-Handle und Host-Netzwerk-Sockets und ruft anschließend hostlockdown.Apply() auf:
- Windows NT (
lockdown_windows.go): RuftAdjustTokenPrivilegesmitSE_PRIVILEGE_REMOVEDauf, um Privilegien direkt zu entfernen, bindet einDISABLE_MAX_PRIVILEGE-eingeschränktes Impersonierungstoken mit Low-Integrität (S-1-16-4096), weist den Prozess einem anonymen Job Object mitJOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1zu (wodurch die Erstellung jedes Kindprozesses blockiert wird) und aktiviertDisallowWin32kSystemCalls = 1überSetProcessMitigationPolicy. - macOS XNU (
lockdown_darwin.go): SetztRLIMIT_NPROC = 0und wendet ein Seatbelt-Profil (sandbox_init_with_parameters) an, das mit(version 1)(deny default)beginnt undprocess-fork,process-exec*sowie alle neuen Host-Dateiöffnungen blockiert. - Linux (
lockdown_linux.go+pkg/gvx/syscallfilter_linux.go): SetztPR_SET_NO_NEW_PRIVSund installiert die Sentry-BPF-seccomp-Allowlist über alle Threads (SECCOMP_FILTER_FLAG_TSYNC) mit explizitenEPERM-Regeln fürexecve,execveat,clone,openatundsocket.
Plattformübergreifendes Abfangen von Systemaufrufen und 4-KB-Paging (pkg/sentry/platform)
Linux-ELF64-Binärdateien setzen für mmap(MAP_FIXED)-Segmentzuordnungen eine Speicherseitengranularität von 4 KB (0x1000) voraus. Windows VirtualAlloc und MapViewOfFile3 erzwingen jedoch eine Ausrichtung auf 64 KB (0x10000), und Apple-Silicon-macOS (darwin/arm64) verwendet 16-KB-Host-Seiten (0x4000). Darüber hinaus benötigt jedes Betriebssystem einen anderen Mechanismus, um Linux-SYSCALL- (amd64) und SVC #0-Instruktionen (arm64) abzufangen, ohne eine Linux-VM zu starten.
gvx löst beide Probleme über vier Ausführungs-Backends, die pkg/sentry/platform.Context implementieren:

1. Windows-Hardware-Engine: platform/whpx (WinHvPlatform.dll)
Auf windows/amd64 und windows/arm64 erstellt platform/whpx über WHvCreatePartition eine leichtgewichtige Hypervisor-Partition, ohne einen Gast-Betriebssystemkernel zu booten:
- 64-KB-zu-4-KB-Paging-Entkoppler:
whpxregistriert jede 64-MiB-Arena vonpgalloc.MemoryFileeinmalig überWHvMapGpaRangebei der Partition. NachfolgendeMapFile- undUnmap-Aufrufe ändern lediglich die Gastseitentabellen innerhalb der Partition und erzwingen exakte 4-KB-R/W/X-Berechtigungen trotz der 64-KB-Allokationsgranularität von Windows. - Registeraustausch über
CommPageohne API-Aufrufe:- Auf
amd64gelangt einSYSCALLaus Ring 3 des Gastes in einen innerhalb der Partition liegenden Ring-0-MSR_LSTAR-Stub (stubgen_x86.go), der die GPRs für den Fast-Path-Systemaufruf (RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP) in eine gemeinsame 4-KB-CommPageschreibt undHLTausführt, umWHvRunVirtualProcessorzu verlassen. - Auf
arm64gelangt einSVC #0aus EL0 des Gastes in die EL1-Vektoren (stubgen_a64.go), schreibtX0..X8, SP_EL0, ELR_EL1, PSTATEin dieCommPageund lädt von einer nicht hinterlegten GPA-Null, um einen Speicherexit zurück zum Sentry auszulösen.
- Auf
2. macOS-Hardware-Engine: platform/hvf (Hypervisor.framework)
Auf Apple Silicon (darwin/arm64) führt platform/hvf Container-Threads innerhalb von Hypervisor.framework-vCPUs aus (hv_vm_create, hv_vcpu_run):
- Zweistufige 4-KB-über-16-KB-MMU-Übersetzung: Stage-2 (
hv_vm_map) bildet 1-GiB-Chunks der Memory-File einmalig mit 16-KB-Host-Seitengranularität in den Intermediate-Physical-Address-(IPA)-Raum ab, mitHV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC. Innerhalb der vCPU konfiguriert der EL1-bluepill-Stub (bluepill_arm64.go)TCR_EL1.TG0 = 0b00(4-KB-Granule) inTTBR0_EL1und befüllt 4-KB-Stage-1-Seitentabelleneinträge mit exaktenR-X- oderRW-(UXN=1)-Berechtigungen. Da die ARM64-MMU die Schnittmenge der Stage-1- und Stage-2-Berechtigungen durchsetzt, fängt die Hardware Berechtigungsfehler exakt an 4-KB-Grenzen ab. - Systemaufruf-Trap: Ein
SVC #0aus EL0 des Gastes trifft auf EL1VBAR_EL1, schreibt Register in die gemeinsame 4-KB-CommPageund führtHVC #0aus, um aushv_vcpu_runin den Go-Sentry-Thread zurückzukehren.
3. Windows-User-Mode-Fallback: platform/systrap (winsystrap)
Wenn Hardwarevirtualisierung nicht verfügbar ist (etwa innerhalb verschachtelter Cloud-VMs), führt winsystrap Gastcode im User Mode auf windows/amd64 und windows/arm64 aus:
- Hardware-
CR3- /TTBR0_EL1-Isolation: Gast-Threads laufen innerhalb isolierter Stub-Subprozesse, die aus einer generierten 1-KB-ausführbaren Datei (stubimage_xplat.go) gestartet werden und durch ein Low-Integrity-Token und ein Job Object eingeschränkt sind. - Binärpatching an Ort und Stelle &
winSysmsg-IPC: Aufamd64ersetzt der Patcher (patcher_amd64_xplat.go) 2-Byte-syscall-Instruktionen (0f 05) durch 5-Byte-jmp rel32-Sprünge (oder durchCC 90-Breakpoint-Traps, wenn kein 5-Byte-Fenster verfügbar ist) in eine Fast-Path-Insel. Aufarm64wirdsvc #0durch einenB-Branch zu einem Inselslot ersetzt. Die Insel schreibt Register in die gemeinsamewinSysmsg-Seite und synchronisiert sich mit dem Sentry überWaitOnAddressundWakeByAddressSingle, während nicht gepatchte Traps und Seitenfehler an einem Windows-Debug-Object (WaitForDebugEventEx) anhalten.
4. Linux-User-Mode-Engine: platform/systrap
Auf linux/amd64 und linux/arm64 führt systrap Gast-Threads (sysmsg) aus, die Gastsystemaufrufe über SECCOMP_RET_TRAP (SIGSYS) abfangen und syscall-Stellen binär in einen gemeinsam genutzten Speicher-Trampolin (sysmsg) patchen, der über SYS_FUTEX synchronisiert wird. Gleichzeitig führt ein Stub-syscallThread (syscall_thread.go) Adressraumoperationen (mmap, munmap, clone) über SECCOMP_RET_USER_NOTIF (_RUN_SECCOMP_LOOP) aus. Wenn gvx innerhalb einer äußeren gVisor-(runsc)-Sandbox läuft, in der der einzelne SECCOMP_FILTER_FLAG_NEW_LISTENER-Slot EBUSY zurückgibt, schaltet gvx syscallThread automatisch auf eine Futex-Schleife mit gemeinsamem Speicher (_RUN_SYSCALL_LOOP) um, wie in Teil 3 dieser Serie beschrieben.
Wie gvx Linux-Systemaufrufe des Gastes auf virtuelle Subsysteme und Host-Handles abbildet
Sobald eine Plattform-Engine eine SYSCALL- (amd64) oder SVC #0-Instruktion (arm64) des Gastes abfängt und die Gastregister in die 4-KB-gemeinsame Seite (CommPage, sysmsg oder winSysmsg) schreibt, kehrt die Kontrolle zur Go-Sentry-Task-Goroutine zurück (pkg/sentry/kernel/task_syscall.go). Statt Linux-Systemaufrufe an den zugrunde liegenden Host-Betriebssystemkernel weiterzuleiten, speichert Task.doSyscall() den ursprünglichen Registerzustand (SyscallSaveOrig()), wertet alle im Gast eingebetteten BPF-seccomp-Filter und ptrace-Stopps aus und leitet die Systemaufrufnummer über linux.AMD64 oder linux.ARM64 (pkg/sentry/syscalls/linux/linux64.go, das etwa 370 Linux-Systemaufrufe abdeckt) in vier interne Domänen weiter:

| Systemaufruf-Domäne | Repräsentative Linux-Systemaufrufe des Gastes | Interne gvx-Subsystem (pkg/sentry) | Interaktion mit der Host-OS-Grenze (nach hostlockdown) |
|---|---|---|---|
| A. Prozess, Namespace, Mount & Synchronisation | clone, execve, unshare, setns, mount, umount2, pivot_root, setuid, capset, futex, epoll_wait, pipe2 | kernel.Task, virtuelle Credentials, Futex-Tabelle und im Speicher liegendes VFS2 (procfs, sysfs, cgroupfs v2, tmpfs, overlayfs) | Null Host-Systemaufrufe (100 % im Go-Zustand im Speicher; für das Host-Betriebssystem vollständig unsichtbar) |
B. Virtueller Speicher (MM) | mmap, munmap, mremap, mprotect, brk, madvise, memfd_create | mm.MemoryManager (4-KB-VMA-Baum) & pgalloc.MemoryFile | Bidirektionale 4-KB-Seitentabellenaktualisierungen über WHvMapGpaRange, hv_vm_map + TTBR0_EL1 oder Stub-mmap/mprotect |
C. Dateien & Speicher (VFS2) | openat, pread64, pwrite64, getdents64, statx, renameat2, setxattr, mknod, inotify_add_watch | Mount-Tabellen-Router vfs.VirtualFilesystem (fsimpl/erofs, fsimpl/ext4lite, fsimpl/hostfs v2) | Bidirektionales pread/pwrite auf 1 fixierten .erofs-FD oder 1 .ext4-FD oder eingeschränkte relative Pfadauflösungen auf *os.Root |
| D. Netzwerk & Netfilter | socket, bind, listen, connect, sendmsg, recvmsg, netlink, setsockopt(IPT_SO_SET_REPLACE) | Benutzerraum-pkg/tcpip (lo, eth0, docker0, veth, vxlan, wireguard, ipset, iptables-legacy) | Datenverkehr innerhalb der Sandbox verwendet null Host-Systemaufrufe; externer Datenverkehr wird auf net.Dial/net.Listen (-net=nat) oder 1 UDP-Socket (-net=wg) abgebildet |
Wenn der Handler (rval, ctrl, err) zurückgibt, wandelt Task.doSyscallInvoke() jeden Fehler in einen negativen Linux-errno um (-ExtractErrno(err, sysno)), schreibt den Rückgabewert zurück auf die gemeinsame Registerseite (RAX auf amd64, X0 auf arm64) und setzt die Ausführung des Gastes fort.
Speicher (VFS2) und zweigleisiger User-Space-Netzwerkbetrieb (netstack)
Alle Datei- und Netzwerkoperationen des Gastes werden innerhalb des Go-Sentry über drei VFS2-Dateisysteme und zwei pkg/netbackend-Stränge bedient:

| Speicher-Engine | Einhängerolle in gvx | Zugrunde liegende Host-Ressource | Host-openat- / NtCreateFile-Aufrufe zur Laufzeit | Windows-Defender-(WdFilter.sys)-Scans pro Datei |
|---|---|---|---|---|
fsimpl/erofs | Schreibgeschützte untere OCI-Image-Layer | Eine einzelne <sha256>.erofs-Datei pro Layer | 0 | 0 |
fsimpl/ext4lite | Benannte Volumes (-v name:/path) | Eine einzelne <name>.ext4-Datei pro Volume | 0 | 0 |
fsimpl/hostfs v2 | Host-Workspace (-workspace, -v /host:/guest) | Fixiertes *os.Root-Host-Verzeichnis | O(depth) pro uncachierter Öffnung | 1 pro Schließen einer Host-Datei |
Warum ext4lite für Docker, Datenbanken und Paketmanager wichtig ist
Das Entpacken oder Schreiben von Zehntausenden Container-Dateien direkt auf Windows NTFS oder macOS APFS löst Antivirus-Minifilter-Scans (WdFilter.sys), Kollisionen bei der Groß-/Kleinschreibung und fehlende erweiterte POSIX-Attribute aus.
pkg/sentry/fsimpl/ext4lite implementiert ein rein in Go geschriebenes ext4-Dateisystem innerhalb einer einzelnen vorab geöffneten Host-Datei (%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4 unter Windows, ~/Library/Caches/gvx/volumes/<name>.ext4 unter macOS oder ~/.cache/gvx/volumes/<name>.ext4 unter Linux) mit:
- 4-KiB-Blöcke und dynamische 16-MiB-Blockgruppen (
meta_bg): Wächst dynamisch, ohne Stalls durch Sparse-File-Allokation (fallocateunter Linux,fcntl(F_PREALLOCATE)unter macOS,FileAllocationInfounter Windows), und verdichtet nicht genutzte nachlaufende Gruppen beim sauberen Aushängen. - JBD2-Journal im Ordered-Modus (Inode 8): Atomare Transaktionsbestätigungen mit CRC-32-Prüfsummen und Revoke-Blöcken, zusammen mit einer
fsckLite-Wiederherstellung. - Unterstützung der
overlayfs-Upper-Layer: Implementiert die erweiterten Attributetrusted.overlay.*undsecurity.capability, Character-Device-Whiteouts (0:0),d_type-Meldung für Verzeichniseinträge undRENAME_EXCHANGE.
Praktische Workloads: Docker Engine, Kubernetes (k3s + Calico) und Go SDK
Installation von rungv: SLSA-attestierte vorgefertigte Releases oder go install
Sie können ein vorgefertigtes rungv-Archiv für linux/amd64, linux/arm64, darwin/arm64, windows/amd64 oder windows/arm64 von GitHub Releases herunterladen (jeweils erstellt durch die SLSA-Release-Pipeline mit einem Sigstore-Provenance-Bundle und SHA256SUMS) oder direkt aus dem Quellcode mit go install installieren:
1# Option A: Vorgefertigtes Release herunterladen und SLSA-Build-Provenance verifizieren
2gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
3 --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
4 --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
5shasum -a 256 -c SHA256SUMS --ignore-missing
6tar -xzf rungv-v0.2.0-linux-amd64.tar.gz
7
8# Option B: Direkte Installation über Go (Linux / Windows)
9CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
Auf macOS (
darwin/arm64) ist das vorgefertigte Release-Archiv bereits mit dem Berechtigungsanspruchcom.apple.security.hypervisorsigniert (xattr -d com.apple.quarantine rungventfernt die Browser-Quarantäne). Wenn Sie lokal mitgo installodergo buildunter macOS bauen, signieren Sie die Binärdatei mitcodesign --sign - --entitlements entitlements.plist --force $(which rungv).
1. Ausführen einer unprivilegierten Docker Engine (docker:dind)
Gemäß docs/docker-engine.md können Sie einen unveränderten docker:dind-Container innerhalb von rungv unter Windows, macOS oder Linux ausführen und mit Ihrer Host-docker-CLI steuern:
1# 1. Host-Verzeichnis für den weitergeleiteten Unix-Socket erstellen
2mkdir -p ~/.gvx
3
4# 2. docker:dind innerhalb einer gvx-Sandbox mit einem ext4lite-Volume starten
5rungv run \
6 -p unix:~/.gvx/docker.sock:2375 \
7 -p 127.0.0.1:9000-9019:9000-9019 \
8 -v gvx-docker:/var/lib/docker \
9 -e DOCKER_TLS_CERTDIR= \
10 docker:dind --tls=false
In einem zweiten Terminal richten Sie Ihre Host-docker-CLI auf den Sandbox-Socket:
1docker context create gvx --docker host=unix://$HOME/.gvx/docker.sock
2docker context use gvx
3
4docker info --format '{{.Driver}} {{.OperatingSystem}}'
5# Ausgabe: overlayfs Alpine Linux ... (containerized)
6
7docker build -t myapp ./app
8docker compose up -d
2. Ausführen von Kubernetes (k3s + Calico) in unprivilegierten Sandboxes
Da gvx /dev/kmsg, cgroup v2 (memory.max-OOM-Killer und cpu.max-Bandbreitendrosselung), /proc/diskstats, wireguard- und vxlan-Netlink-Geräte, ipset sowie iptables-legacy (addrtype, conntrack, statistic, recent) implementiert, erreicht ein unverändertes rancher/k3s-Image innerhalb eines einzigen rungv-Prozesses den Status Ready:
1mkdir -p ~/.gvx/k3s
2
3rungv run \
4 -e IPTABLES_MODE=legacy \
5 -p 127.0.0.1:6443:6443 \
6 -p 127.0.0.1:30000-30019:30000-30019 \
7 -v k3s:/var/lib/rancher \
8 --mount type=bind,src=$HOME/.gvx/k3s,dst=/output \
9 rancher/k3s:v1.31.4-k3s1 server \
10 --disable=traefik,servicelb \
11 --write-kubeconfig=/output/kubeconfig.yaml \
12 --write-kubeconfig-mode=644
Sie können außerdem mehrere gvx-Knoten über WireGuard verbinden (flannel-backend=wireguard-native oder ein wg0-Mesh) mit eingebettetem etcd für Hochverfügbarkeit oder Calico (calico-vxlan.yaml mit FELIX_IPTABLESBACKEND=Legacy) ausführen, um Kubernetes-NetworkPolicy vollständig im Benutzerraum durchzusetzen.
3. Einbetten von Linux-Containern in Go über z.gfire.dev/gvx/pkg/gvx
Go-Anwendungen können Linux-Container direkt ohne externen Container-Daemon einbetten:
1package main
2
3import (
4 "context"
5 "fmt"
6 "os"
7
8 "z.gfire.dev/gvx/pkg/gvx"
9)
10
11func main() {
12 ctx := context.Background()
13 sb, err := gvx.New(ctx, gvx.Config{
14 Platform: gvx.PlatformAuto,
15 NetworkMode: gvx.NetModeNAT,
16 OCIImage: "alpine:3.20",
17 WorkspacePath: "./repo",
18 Argv: []string{"/usr/bin/git", "status"},
19 Stdout: os.Stdout,
20 Stderr: os.Stderr,
21 })
22 if err != nil {
23 fmt.Fprintf(os.Stderr, "init sandbox: %v\n", err)
24 os.Exit(1)
25 }
26 defer sb.Close()
27
28 exitCode, err := sb.Run(ctx)
29 if err != nil {
30 fmt.Fprintf(os.Stderr, "run sandbox: %v\n", err)
31 os.Exit(1)
32 }
33 os.Exit(exitCode)
34}
Weiterführende Literatur in dieser Serie
- gvx: Ausführen von Linux-Containern, Docker und Kubernetes in einem einzigen unprivilegierten Prozess (dieser Beitrag)
- Ausführen von Docker, docker build und docker compose ohne Root oder User Namespaces: Wie Sie
docker:dindin abgesicherten Sandboxes booten, in denensudo,unshare(CLONE_NEWUSER),mount(2)und/dev/fuseblockiert sind. - Ausführen von Docker-in-Docker innerhalb von gVisor und verschachtelten Sandboxes mit gvx: Warum
apt-get install docker.iound verschachteltesrunscinnerhalb vongVisoran fünf Kernel-Barrieren scheitern und wiegvxverschachteltesdocker:dindüber eine Futex-Schleife mit gemeinsamem Speicher ausführt. - Schnelle isolierte Docker-Umgebungen für RL-Rollouts von KI-Agenten mit gvx: Skalierung von
SWE-benchund Reinforcement-Learning-Rollouts von Agenten mit Hunderten paralleler unprivilegierterdocker:dind-Instanzen und 100-Millisekunden-Copy-on-Write-.ext4-Volume-Resets.