---
id: e62d78ef5850c982dbddc9d3ff9134ae
author: Lemon Mint
title: 'gvx: Kørsel af Linux-containere, Docker og Kubernetes i én uprivilegeret proces'
description: Teknisk oversigt over gvx, en sikkerhedshærdet, krydsplatformskompatibel containerruntime og Go SDK bygget på gVisor-brugerrumskernen, der sikkert kører Linux-containere, Docker-in-Docker og multi-node HA Kubernetes i en enkelt uprivilegeret proces på tværs af Windows, macOS og Linux.
language: da
date: 2026-11-06T12:02:56.008516536Z
path: /blog/posts/gvx-cross-platform-linux-containers-z48916d01
go_package: z.gfire.dev/gvx
go_repourl: https://github.com/gfire-sigs/gvx.git
category: lowlevel
---

## Introduktion: Sikkerhedshærdede containere uden root eller værtsdaemoner

At køre Linux-containere, `docker build` eller Kubernetes inde i en udviklingsmaskine, CI-runner eller multi-tenant cloud-node tvinger som regel en ubehagelig sikkerhedsafvejning:

- På **Linux** kræver standard OCI-runtimes (`runc`, `crun`, `runsc`) enten `root`-rettigheder, eksponering af host-`/var/run/docker.sock`, `--privileged` (`CAP_SYS_ADMIN`) eller user namespaces (`unshare(CLONE_NEWUSER)`), som udvider angrebsfladen i værtskernen.
- På **Windows** og **macOS** starter containermotorer (`Docker Desktop`, `Podman Machine`, `Lima`, `OrbStack`) en fuld Linux-kerne i en virtuel maskine inde i WSL2, Hyper-V eller `Virtualization.framework` og kører en vedvarende baggrundsdaemon inde i denne VM.

**[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`-CLI'en og `z.gfire.dev/gvx/pkg/gvx` Go SDK'en) udgør et **sikkert alternativ uden privilegier**. Bygget som en fork af Googles **gVisor** brugerrums-Linux-kerne (`Sentry`) og brugerrums-netværksstak (`netstack`), som kan spores opstrøms, eksekverer `gvx` uændrede `linux/amd64`- og `linux/arm64`-ELF64-binærfiler og OCI-containere direkte inde i **en enkelt proces på værten uden privilegier og med selvlåsning** på Windows, macOS og Linux.

> **Sikkerhedsgaranti (Tre-ring forsvar i dybden)**: `gvx` svækker aldrig sikkerhedsgrænserne i værtens OS, installerer aldrig kerne-drivere og kræver aldrig `root`, `sudo`, `--privileged` på værten eller `CLONE_NEWUSER`. Før en enkelt gæsteinstruktion eksekveres, låser `gvx` sin egen værtsproces ned ved hjælp af Windows Restricted Tokens og Job Objects, macOS Seatbelt (`deny default`) eller Linux `PR_SET_NO_NEW_PRIVS` + BPF `seccomp`. Alle gæstesystemkald, virtuelle `UID 0`-privilegier, monteringer (`VFS2`) og netværkstabeller (`netstack`) er strengt afgrænset inde i den hukommelsessikre Go `Sentry`-kerne.

| Runtime                    | Værts-OS                                              |          Cold Start | Memory Footprint | Admin eller `sudo` påkrævet | Baggrunds-VM-daemon | Direkte OCI-billedkørsel |
| :------------------------- | :---------------------------------------------------- | ------------------: | ---------------: | :-------------------------- | :------------------ | :----------------------- |
| **`gvx` (`whpx` / `hvf`)** | Windows (`amd64`, `arm64`) & macOS (`arm64`)          |           `~20 ms` |        `~30 MiB` | Nej                         | Nej                 | Ja                       |
| **`gvx` (`systrap`)**      | Windows (`amd64`, `arm64`) & Linux (`amd64`, `arm64`) |     `~25 to 65 ms` |        `~31 MiB` | Nej                         | Nej                 | Ja                       |
| **WSL2 / Docker Desktop**  | Windows & macOS                                       |   `800 to 2500 ms` |      `> 512 MiB` | Ja (initial opsætning)      | Ja                  | Kræver daemon            |
| **QEMU (Full System)**     | Windows & macOS                                       | `1500 to 4000 ms` |      `> 256 MiB` | Nej                         | Nej                 | Kræver diskbillede       |

Der startes ingen Linux-VM-kerne på Windows eller macOS. Der kører ingen baggrundsdaemon på værten. Der kræves ingen `root`, `sudo`, user namespaces (`CLONE_NEWUSER`), `mount(2)`, `TUN`/`TAP`-drivere eller `CAP_NET_ADMIN`-privilegier på værts-OS'et. Inde i denne proces uden privilegier kører `gvx` **Docker-in-Docker (`docker:dind`)**, `docker build`, `docker compose` og **multi-node højtilgængelig Kubernetes (`k3s` med indlejret `etcd` og `Calico` CNI)**.

---

## Containerens livscyklus og tre-ring-låsning af værten

Hver `gvx`-sandkasse kører inde i en enkelt proces på værten uden privilegier og håndhæver en livscyklus i tre faser: præ-åbning af alle nødvendige fildeskriptorer og sockets på værten, låsning af værts-OS-processen via `pkg/hostlockdown` og indtræden i den in-process `Sentry`-eksekveringsløkke.

![gvx-containerens livscyklus og selvlåsning af værten](/assets/images/gvx/gvx-lifecycle-lockdown.png)

Før kontrollen overdrages til den første gæsteinstruktion, præ-åbner `gvx` sine cachede `.erofs`-billedlagdeskriptorer, `.ext4`-volumen-fildeskriptorer, `/workspace`-`*os.Root`-håndtaget og værtens netværkssockets og kalder derefter `hostlockdown.Apply()`:

1. **Windows NT (`lockdown_windows.go`)**: Kalder `AdjustTokenPrivileges` med `SE_PRIVILEGE_REMOVED` for at fjerne privilegier på stedet, binder et `DISABLE_MAX_PRIVILEGE`-begrænset impersonation-token med Low-integritet (`S-1-16-4096`), tildeler processen til et anonymt Job Object med `JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1` (blokerer oprettelse af child-processer) og aktiverer `DisallowWin32kSystemCalls = 1` via `SetProcessMitigationPolicy`.
2. **macOS XNU (`lockdown_darwin.go`)**: Sætter `RLIMIT_NPROC = 0` og anvender en Seatbelt-profil (`sandbox_init_with_parameters`), der starter fra `(version 1)(deny default)` og blokerer `process-fork`, `process-exec*` og alle nye filåbninger på værten.
3. **Linux (`lockdown_linux.go` + `pkg/gvx/syscallfilter_linux.go`)**: Sætter `PR_SET_NO_NEW_PRIVS` og installerer Sentry BPF `seccomp`-tilladelsesliste på tværs af alle tråde (`SECCOMP_FILTER_FLAG_TSYNC`) med eksplicitte `EPERM`-regler for `execve`, `execveat`, `clone`, `openat` og `socket`.

---

## Krydsplatforms-interception af systemkald og 4 KB-paging (`pkg/sentry/platform`)

Linux ELF64-binærfiler antager en hukommelsessidegranularitet på 4 KB (`0x1000`) for `mmap(MAP_FIXED)`-segmentafbildninger. Windows `VirtualAlloc` og `MapViewOfFile3` håndhæver dog 64 KB (`0x10000`)-justering, og Apple Silicon macOS (`darwin/arm64`) bruger 16 KB (`0x4000`)-sider på værten. Desuden kræver hvert OS en forskellig mekanisme for at opsnappe Linux-instruktionerne `SYSCALL` (`amd64`) og `SVC #0` (`arm64`) uden at starte en Linux-VM.

`gvx` løser begge problemer på tværs af fire eksekveringsbackends, der implementerer `pkg/sentry/platform.Context`:

![gvx-platformens interception af systemkald og 4KB-paging](/assets/images/gvx/gvx-platform-syscalls.png)

### 1. Windows-hardwaremotor: `platform/whpx` (`WinHvPlatform.dll`)

På `windows/amd64` og `windows/arm64` opretter `platform/whpx` en letvægts-hypervisor-partition via `WHvCreatePartition` uden at starte en gæste-OS-kerne:

- **64 KB-til-4 KB Paging Decoupler**: `whpx` registrerer hver 64 MiB-arena af `pgalloc.MemoryFile` hos partitionen én gang via `WHvMapGpaRange`. Efterfølgende kald af `MapFile` og `Unmap` ændrer kun gæstens sidetabeller inde i partitionen og håndhæver præcise 4 KB `R/W/X`-rettigheder på trods af Windows' 64 KB-allokeringsgranularitet.
- **Register-udveksling uden API via `CommPage`**:
  - På `amd64` går gæstens Ring-3 `SYSCALL` ind i en in-partition Ring-0 `MSR_LSTAR`-stub (`stubgen_x86.go`), som skriver fast-path-systemkaldets GPR'er (`RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP`) ud i en delt 4 KB `CommPage` og udfører `HLT` for at afslutte `WHvRunVirtualProcessor`.
  - På `arm64` går gæstens EL0 `SVC #0` ind i EL1-vektorer (`stubgen_a64.go`), skriver `X0..X8, SP_EL0, ELR_EL1, PSTATE` til `CommPage` og læser fra ubacket GPA nul for at udløse en hukommelsesafslutning tilbage til Sentry.

### 2. macOS-hardwaremotor: `platform/hvf` (`Hypervisor.framework`)

På Apple Silicon (`darwin/arm64`) kører `platform/hvf` containertråde inde i `Hypervisor.framework`-vCPU'er (`hv_vm_create`, `hv_vcpu_run`):

- **To-trins 4 KB over 16 KB MMU-oversættelse**: Stage-2 (`hv_vm_map`) afbilder 1 GiB hukommelsesfil-bidder ind i Intermediate Physical Address (IPA)-rummet én gang med 16 KB sidegranularitet på værten med `HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC`. Inde i vCPU'en konfigurerer EL1-stubben `bluepill` (`bluepill_arm64.go`) `TCR_EL1.TG0 = 0b00` (4 KB-granule) i `TTBR0_EL1` og udfylder 4 KB Stage-1-sidetabelindgange med præcise `R-X`- eller `RW-` (`UXN=1`)-rettigheder. Fordi ARM64 MMU'en håndhæver skæringspunktet af Stage-1- og Stage-2-rettigheder, fanger hardwaren rettighedsfejl præcist på 4 KB-grænser.
- **Systemkaldsfælde**: Gæstens EL0 `SVC #0` fanges af EL1 `VBAR_EL1`, skriver registre til den delte 4 KB `CommPage` og udfører `HVC #0` for at vende tilbage fra `hv_vcpu_run` til Go Sentry-tråden.

### 3. Windows-fallback i brugertilstand: `platform/systrap` (`winsystrap`)

Når hardwarevirtualisering ikke er tilgængelig (f.eks. inde i indlejrede cloud-VM'er), kører `winsystrap` gæstekode i brugertilstand på `windows/amd64` og `windows/arm64`:

- **Hardware-isolation via `CR3` / `TTBR0_EL1`**: Gæstetråde kører inde i isolerede stub-underprocesser, startet fra en genereret 1 KB-eksekverbar fil (`stubimage_xplat.go`), afgrænset af et Low-Integrity-token og et Job Object.
- **Patching på stedet i binærfiler & `winSysmsg` IPC**: På `amd64` erstatter patcheren (`patcher_amd64_xplat.go`) 2-byte `syscall`-instruktioner (`0f 05`) med 5-byte `jmp rel32`-hop (eller `CC 90`-breakpoint-fælder, når et 5-byte-vindue ikke er tilgængeligt) ind i en fast-path-ø. På `arm64` patches `svc #0` med en `B`-forgrening til en øplads. Øen skriver registre til den delte `winSysmsg`-side og synkroniseres med Sentry via `WaitOnAddress` og `WakeByAddressSingle`, mens upatchede fælder og sidefejl standser på et Windows Debug Object (`WaitForDebugEventEx`).

### 4. Linux-motor i brugertilstand: `platform/systrap`

På `linux/amd64` og `linux/arm64` kører `systrap` gæstetråde (`sysmsg`), der fanger gæstesystemkald via `SECCOMP_RET_TRAP` (`SIGSYS`) og binært patcher `syscall`-steder ind i en delt-hukommelses-trampolin (`sysmsg`), synkroniseret via `SYS_FUTEX`, mens en stub-`syscallThread` (`syscall_thread.go`) udfører adresserumsoperationer (`mmap`, `munmap`, `clone`) via `SECCOMP_RET_USER_NOTIF` (`_RUN_SECCOMP_LOOP`). Når `gvx` kører inde i en ydre `gVisor` (`runsc`)-sandkasse, hvor den enkelte `SECCOMP_FILTER_FLAG_NEW_LISTENER`-plads returnerer `EBUSY`, skifter `gvx` automatisk `syscallThread` til en futex-løkke i delt hukommelse (`_RUN_SYSCALL_LOOP`), som beskrevet i detaljer i [Del 3 af denne serie](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03).

---

## Hvordan `gvx` afbilder gæste-Linux-systemkald til virtuelle delsystemer og værtshåndtag

Når en platformmotor har fanget en gæstes `SYSCALL` (`amd64`) eller `SVC #0` (`arm64`)-instruktion og skrevet gæsteregistrene til den delte 4 KB-side (`CommPage`, `sysmsg` eller `winSysmsg`), vender kontrollen tilbage til Go `Sentry`-opgavegoroutinen (`pkg/sentry/kernel/task_syscall.go`). I stedet for at videresende Linux-systemkald til den underliggende værts-OS-kerne, gemmer `Task.doSyscall()` den oprindelige registertilstand (`SyscallSaveOrig()`), evaluerer eventuelle BPF `seccomp`-filtre og `ptrace`-stop i gæsten og sender systemkaldsnummeret gennem `linux.AMD64` eller `linux.ARM64` (`pkg/sentry/syscalls/linux/linux64.go`, der dækker ~370 Linux-systemkald) ind i fire interne domæner:

![Hvordan gvx afbilder gæste-Linux-systemkald til delsystemer og værts-OS](/assets/images/gvx/gvx-syscall-mapping.png)

| Systemkaldsdomæne | Repræsentative gæste-Linux-systemkald | Internt `gvx`-delsystem (`pkg/sentry`) | Interaktion med værts-OS-grænsen (efter `hostlockdown`) |
| :--- | :--- | :--- | :--- |
| **A. Proces, namespace, montering & synkronisering** | `clone`, `execve`, `unshare`, `setns`, `mount`, `umount2`, `pivot_root`, `setuid`, `capset`, `futex`, `epoll_wait`, `pipe2` | `kernel.Task`, virtuelle legitimationsoplysninger, futex-tabel og in-memory `VFS2` (`procfs`, `sysfs`, `cgroupfs` v2, `tmpfs`, `overlayfs`) | **Nul værtssystemkald** (100% in-memory Go-tilstand; fuldstændigt usynlig for værts-OS'et) |
| **B. Virtuel hukommelse (`MM`)** | `mmap`, `munmap`, `mremap`, `mprotect`, `brk`, `madvise`, `memfd_create` | `mm.MemoryManager` (4 KB VMA-træ) & `pgalloc.MemoryFile` | Tovejsopdateringer af 4 KB-sidetabeller via `WHvMapGpaRange`, `hv_vm_map` + `TTBR0_EL1` eller stub-`mmap`/`mprotect` |
| **C. Fil og lager (`VFS2`)** | `openat`, `pread64`, `pwrite64`, `getdents64`, `statx`, `renameat2`, `setxattr`, `mknod`, `inotify_add_watch` | `vfs.VirtualFilesystem`-monteringstabelrouter (`fsimpl/erofs`, `fsimpl/ext4lite`, `fsimpl/hostfs` v2) | Tovejs `pread`/`pwrite` på 1 fastgjort `.erofs`-FD eller 1 `.ext4`-FD, eller afgrænsede relative gennemgange af `*os.Root` |
| **D. Netværk & Netfilter** | `socket`, `bind`, `listen`, `connect`, `sendmsg`, `recvmsg`, `netlink`, `setsockopt(IPT_SO_SET_REPLACE)` | `pkg/tcpip` i brugertilstand (`lo`, `eth0`, `docker0`, `veth`, `vxlan`, `wireguard`, `ipset`, `iptables-legacy`) | Trafik internt i sandkassen bruger **nul værtssystemkald**; ekstern trafik afbildes til `net.Dial`/`net.Listen` (`-net=nat`) eller 1 UDP-socket (`-net=wg`) |

Når handleren returnerer `(rval, ctrl, err)`, konverterer `Task.doSyscallInvoke()` enhver fejl til en negativ Linux-`errno` (`-ExtractErrno(err, sysno)`), skriver returværdien tilbage til den delte registerside (`RAX` på `amd64`, `X0` på `arm64`) og genoptager gæsteeksekveringen.

---

## Lager (`VFS2`) og netværk i brugertilstand med to spor (`netstack`)

Alle gæstens fil- og netværksoperationer betjenes inde i Go `Sentry` gennem tre `VFS2`-filsystemer og to `pkg/netbackend`-spor:

![gvx VFS2-lagermotorer og netstack med to spor](/assets/images/gvx/gvx-storage-netstack.png)

| Lagermotor | Monteringsrolle i `gvx` | Bagvedliggende værtsressource | Værtens `openat`- / `NtCreateFile`-kald under kørsel | Windows Defender (`WdFilter.sys`) scanninger pr. fil |
| :--------------------- | :----------------------------------------------- | :------------------------------------- | -----------------------------------------------: | -----------------------------------------------: |
| **`fsimpl/erofs`**     | Skrivebeskyttede nedre OCI-billedlag             | Enkelt `<sha256>.erofs`-fil pr. lag    |                                              `0` |                                              `0` |
| **`fsimpl/ext4lite`**  | Navngivne volumener (`-v name:/path`)            | Enkelt `<name>.ext4`-fil pr. volumen   |                                              `0` |                                              `0` |
| **`fsimpl/hostfs` v2** | Arbejdsområde på værten (`-workspace`, `-v /host:/guest`) | Fastgjort `*os.Root`-værtsmappe | `O(depth)` pr. ukached åbning                    | `1` pr. lukning af værtsfil                      |

### Hvorfor `ext4lite` betyder noget for Docker, databaser og pakkehåndteringer

Udpakning eller skrivning af titusindvis af containerfiler direkte til Windows NTFS eller macOS APFS udløser scanninger af antivirus-minifiltre (`WdFilter.sys`), kollisioner pga. versalfølsomhed og manglende POSIX-udvidede attributter.

`pkg/sentry/fsimpl/ext4lite` implementerer et rent Go-`ext4`-filsystem inde i en enkelt præ-åbnet værtsfil (`%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4` på Windows, `~/Library/Caches/gvx/volumes/<name>.ext4` på macOS eller `~/.cache/gvx/volumes/<name>.ext4` på Linux) med:

- **4 KiB-blokke og 16 MiB dynamiske blokgrupper (`meta_bg`)**: Vokser dynamisk uden stop i forbindelse med allokering af sparse-filer (`fallocate` på Linux, `fcntl(F_PREALLOCATE)` på macOS, `FileAllocationInfo` på Windows) og komprimerer ubrugte efterfølgende grupper ved ren afmontering.
- **JBD2-journal i ordered-tilstand (inode 8)**: Atomare transaktionsbekræftelser med CRC-32-checksummer og revoke-blokke samt `fsckLite`-gendannelse.
- **Understøttelse af øvre lag i `overlayfs`**: Implementerer `trusted.overlay.*`- og `security.capability`-udvidede attributter, whiteouts for tegnenheder (`0:0`), `d_type`-rapportering af mappeindgange og `RENAME_EXCHANGE`.

---

## Praktiske arbejdsbelastninger: Docker Engine, Kubernetes (`k3s` + `Calico`) og Go SDK

### Installation af `rungv`: SLSA-attesterede færdigbyggede udgivelser eller `go install`

Du kan downloade et færdigbygget `rungv`-arkiv til `linux/amd64`, `linux/arm64`, `darwin/arm64`, `windows/amd64` eller `windows/arm64` fra [GitHub Releases](https://github.com/gfire-sigs/gvx/releases) (hvert bygget af SLSA-udgivelsespipelinen med en Sigstore-provenansbundle og `SHA256SUMS`), eller installere direkte fra kildekoden med `go install`:

```sh
# Mulighed A: Download en færdigbygget udgivelse og verificér SLSA-build-provenans
gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
  --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
  --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
shasum -a 256 -c SHA256SUMS --ignore-missing
tar -xzf rungv-v0.2.0-linux-amd64.tar.gz

# Mulighed B: Installér direkte via Go (Linux / Windows)
CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
```

> På macOS (`darwin/arm64`) er det færdigbyggede udgivelsesarkiv allerede signeret med rettigheden `com.apple.security.hypervisor` (`xattr -d com.apple.quarantine rungv` fjerner browserens karantæne). Hvis du bygger lokalt med `go install` eller `go build` på macOS, signerer du binærfilen med `codesign --sign - --entitlements entitlements.plist --force $(which rungv)`.

### 1. Kørsel af en Docker Engine uden privilegier (`docker:dind`)

Ved at følge [`docs/docker-engine.md`](https://github.com/gfire-sigs/gvx/blob/main/docs/docker-engine.md) kan du køre en uændret `docker:dind`-container inde i `rungv` på Windows, macOS eller Linux og styre den med din værts `docker`-CLI:

```sh
# 1. Opret værtsmappen til den videresendte Unix-socket
mkdir -p ~/.gvx

# 2. Start docker:dind inde i en gvx-sandkasse med et ext4lite-volumen
rungv run \
  -p unix:~/.gvx/docker.sock:2375 \
  -p 127.0.0.1:9000-9019:9000-9019 \
  -v gvx-docker:/var/lib/docker \
  -e DOCKER_TLS_CERTDIR= \
  docker:dind --tls=false
```

I en anden terminal peger du din værts `docker`-CLI mod sandkassens socket:

```sh
docker context create gvx --docker host=unix://$HOME/.gvx/docker.sock
docker context use gvx

docker info --format '{{.Driver}} {{.OperatingSystem}}'
# Resultat: overlayfs Alpine Linux ... (containerized)

docker build -t myapp ./app
docker compose up -d
```

### 2. Kørsel af Kubernetes (`k3s` + `Calico`) i sandkasser uden privilegier

Da `gvx` implementerer `/dev/kmsg`, `cgroup` v2 (`memory.max` OOM-killer og `cpu.max` båndbreddebegrænsning), `/proc/diskstats`, `wireguard`- og `vxlan`-netlink-enheder, `ipset` og `iptables-legacy` (`addrtype`, `conntrack`, `statistic`, `recent`), når et uændret `rancher/k3s`-image status `Ready` inde i en enkelt `rungv`-proces:

```sh
mkdir -p ~/.gvx/k3s

rungv run \
  -e IPTABLES_MODE=legacy \
  -p 127.0.0.1:6443:6443 \
  -p 127.0.0.1:30000-30019:30000-30019 \
  -v k3s:/var/lib/rancher \
  --mount type=bind,src=$HOME/.gvx/k3s,dst=/output \
  rancher/k3s:v1.31.4-k3s1 server \
  --disable=traefik,servicelb \
  --write-kubeconfig=/output/kubeconfig.yaml \
  --write-kubeconfig-mode=644
```

Du kan også forbinde flere `gvx`-noder over WireGuard (`flannel-backend=wireguard-native` eller et `wg0`-mesh) med indlejret `etcd`-højtilgængelighed, eller køre **Calico** (`calico-vxlan.yaml` med `FELIX_IPTABLESBACKEND=Legacy`) for at håndhæve Kubernetes `NetworkPolicy` fuldstændigt inde i brugerrummet.

### 3. Indlejring af Linux-containere i Go via `z.gfire.dev/gvx/pkg/gvx`

Go-applikationer kan indlejre Linux-containere direkte uden en ekstern containerdaemon:

```go
package main

import (
	"context"
	"fmt"
	"os"

	"z.gfire.dev/gvx/pkg/gvx"
)

func main() {
	ctx := context.Background()
	sb, err := gvx.New(ctx, gvx.Config{
		Platform:      gvx.PlatformAuto,
		NetworkMode:   gvx.NetModeNAT,
		OCIImage:      "alpine:3.20",
		WorkspacePath: "./repo",
		Argv:          []string{"/usr/bin/git", "status"},
		Stdout:        os.Stdout,
		Stderr:        os.Stderr,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "init sandbox: %v\n", err)
		os.Exit(1)
	}
	defer sb.Close()

	exitCode, err := sb.Run(ctx)
	if err != nil {
		fmt.Fprintf(os.Stderr, "run sandbox: %v\n", err)
		os.Exit(1)
	}
	os.Exit(exitCode)
}
```

---

## Yderligere læsning i denne serie

1. **[gvx: Kørsel af Linux-containere, Docker og Kubernetes i én proces uden privilegier](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)** (dette indlæg)
2. **[Kørsel af Docker, docker build og docker compose uden root eller user namespaces](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)**: Sådan bootstrapper du `docker:dind` i låste sandkasser, hvor `sudo`, `unshare(CLONE_NEWUSER)`, `mount(2)` og `/dev/fuse` er blokeret.
3. **[Kørsel af Docker-in-Docker inde i gVisor og indlejrede sandkasser med gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Hvorfor `apt-get install docker.io` og indlejret `runsc` fejler inde i `gVisor` på tværs af fem kernebarrierer, og hvordan `gvx` kører indlejret `docker:dind` ved hjælp af en futex-løkke i delt hukommelse.
4. **[Hurtige isolerede Docker-miljøer til AI-agent RL-rollouts med gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Skalering af `SWE-bench` og rollouts med forstærkningslæring for agenter med hundredvis af parallelle `docker:dind`-instanser uden privilegier og 100 millisekunders copy-on-write-nulstillinger af `.ext4`-volumener.
