---
id: e62d78ef5850c982dbddc9d3ff9134ae
author: Lemon Mint
title: 'gvx: Kjøring av Linux Containers, Docker og Kubernetes i én uprivilegert prosess'
description: Teknisk oversikt over gvx, en sikkerhetsherdet, plattformuavhengig container runtime og Go SDK bygget på gVisor-brukerromkjernen, som trygt kjører Linux-containere, Docker-in-Docker og multi-node HA Kubernetes i én enkelt uprivilegert prosess på tvers av Windows, macOS og Linux.
language: "no"
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
---

## Introduksjon: Sikkerhetsherdede containere uten root eller vertsdaemoner

Å kjøre Linux-containere, `docker build` eller Kubernetes på en utviklingsmaskin, en CI-runner eller en flerleietakersky-node krever vanligvis en ubehagelig sikkerhetsavveining:

- På **Linux** krever standard OCI-runtimes (`runc`, `crun`, `runsc`) enten `root`-rettigheter, eksponering av vertens `/var/run/docker.sock`, `--privileged` (`CAP_SYS_ADMIN`) eller brukernavnerom (`unshare(CLONE_NEWUSER)`), som utvider angrepsflaten i vertens kjerne.
- På **Windows** og **macOS** starter containermotorer (`Docker Desktop`, `Podman Machine`, `Lima`, `OrbStack`) en fullstendig Linux-kjerne i en virtuell maskin innenfor WSL2, Hyper-V eller `Virtualization.framework`, og kjører en vedvarende bakgrunnsdaemon inne i den virtuelle maskinen.

**[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`-CLI-en og `z.gfire.dev/gvx/pkg/gvx` Go-SDK-en) tilbyr et **sikkert alternativ uten privilegier**. Det er bygget som en oppstrømssporbar gaffel av Googles **gVisor** brukerromsbaserte Linux-kjerne (`Sentry`) og brukerromsbasert nettverksstakk (`netstack`), og `gvx` kjører umodifiserte `linux/amd64`- og `linux/arm64`-ELF64-binærfiler og OCI-containere direkte inne i **en enkelt, uprivilegert og selvlåst vertsprosess** på Windows, macOS og Linux.

> **Sikkerhetsgaranti (tre-ringers forsvar i dybden)**: `gvx` svekker aldri sikkerhetsgrensene i vertsoperativsystemet, installerer aldri kjernedrivere og krever aldri `root`, `sudo`, `--privileged` på verten eller `CLONE_NEWUSER`. Før en eneste gjesteinstruksjon kjøres, låser `gvx` sin egen vertsprosess ved hjelp av Windows Restricted Tokens og Job Objects, macOS Seatbelt (`deny default`), eller Linux `PR_SET_NO_NEW_PRIVS` + BPF `seccomp`. Alle systemkall fra gjesten, virtuelle `UID 0`-rettigheter, monteringer (`VFS2`) og nettverkstabeller (`netstack`) er strengt begrenset innenfor den minnesikre Go-kjernen `Sentry`.

| Runtime                    | Vertsoperativsystem                                   |        Kaldstart | Minneavtrykk     | Krever administrator eller `sudo` | VM-daemon i bakgrunnen | Direkte kjøring av OCI-image |
| :------------------------- | :---------------------------------------------------- | ---------------: | ---------------: | :-------------------------------- | :--------------------- | :--------------------------- |
| **`gvx` (`whpx` / `hvf`)** | Windows (`amd64`, `arm64`) og macOS (`arm64`)         |         `~20 ms` |       `~30 MiB`  | Nei                               | Nei                    | Ja                           |
| **`gvx` (`systrap`)**      | Windows (`amd64`, `arm64`) og Linux (`amd64`, `arm64`) |   `~25 til 65 ms` |       `~31 MiB`  | Nei                               | Nei                    | Ja                           |
| **WSL2 / Docker Desktop**  | Windows og macOS                                      | `800 til 2500 ms` |     `> 512 MiB`  | Ja (førstegangsoppsett)           | Ja                     | Krever daemon                |
| **QEMU (fullt system)**    | Windows og macOS                                      | `1500 til 4000 ms` |    `> 256 MiB`  | Nei                               | Nei                    | Krever diskbilde             |

Ingen Linux-kjerne i en virtuell maskin starter på Windows eller macOS. Ingen bakgrunnsdaemon kjører på verten. Det kreves ingen `root`, `sudo`, brukernavnerom (`CLONE_NEWUSER`), `mount(2)`, `TUN`/`TAP`-drivere eller `CAP_NET_ADMIN`-rettigheter på vertsoperativsystemet. Inne i denne uprivilegerte prosessen kjører `gvx` **Docker-in-Docker (`docker:dind`)**, `docker build`, `docker compose` og **høyt tilgjengelig Kubernetes med flere noder (`k3s` med innebygd `etcd` og `Calico` CNI)**.

---

## Containerlivssyklus og tre-ringers vertslåsing

Hver `gvx`-sandkasse kjører innenfor én uprivilegert vertsprosess og følger en livssyklus i tre faser: forhåndsåpning av alle nødvendige vertens filbeskrivere og sockets, låsing av vertens operativsystemprosess via `pkg/hostlockdown`, og inngang til den interne `Sentry`-utførelsessløyfen.

![gvx containerlivssyklus og selvlåsing av verten](/assets/images/gvx/gvx-lifecycle-lockdown.png)

Før kontrollen overføres til den første gjesteinstruksjonen, forhåndsåpner `gvx` sine cachede `.erofs`-bildelagsdeskriptorer, `.ext4`-volumfilbeskrivere, `/workspace`-håndtaket `*os.Root` og vertens nettverkssockets, og kaller deretter `hostlockdown.Apply()`:

1. **Windows NT (`lockdown_windows.go`)**: Kaller `AdjustTokenPrivileges` med `SE_PRIVILEGE_REMOVED` for å fjerne privilegier på stedet, binder et `DISABLE_MAX_PRIVILEGE`-restriktivt impersonation-token med lav integritet (`S-1-16-4096`), tilordner prosessen til et anonymt Job Object med `JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1` (blokkerer opprettelse av underordnede prosesser), og aktiverer `DisallowWin32kSystemCalls = 1` via `SetProcessMitigationPolicy`.
2. **macOS XNU (`lockdown_darwin.go`)**: Setter `RLIMIT_NPROC = 0` og bruker en Seatbelt-profil (`sandbox_init_with_parameters`) som starter fra `(version 1)(deny default)` og blokkerer `process-fork`, `process-exec*` og alle nye filåpninger på verten.
3. **Linux (`lockdown_linux.go` + `pkg/gvx/syscallfilter_linux.go`)**: Setter `PR_SET_NO_NEW_PRIVS` og installerer Sentrys BPF `seccomp`-tillatelsesliste på tvers av alle tråder (`SECCOMP_FILTER_FLAG_TSYNC`), med eksplisitte `EPERM`-regler for `execve`, `execveat`, `clone`, `openat` og `socket`.

---

## Krysplattform-avskjæring av systemkall og 4 KB-paging (`pkg/sentry/platform`)

Linux ELF64-binærfiler forutsetter en minnesidekornethet på 4 KB (`0x1000`) for `mmap(MAP_FIXED)`-segmentmappinger. Windows `VirtualAlloc` og `MapViewOfFile3` håndhever imidlertid 64 KB-justering (`0x10000`), og Apple Silicon macOS (`darwin/arm64`) bruker 16 KB-sider (`0x4000`) på verten. Dessuten krever hvert operativsystem en ulik mekanisme for å avskjære Linux-instruksjonene `SYSCALL` (`amd64`) og `SVC #0` (`arm64`) uten å starte en Linux-virtuell maskin.

`gvx` løser begge problemene på tvers av fire utførelsesbackends som implementerer `pkg/sentry/platform.Context`:

![gvx-mekanismer for avskjæring av plattformsystemkall og 4KB-paging](/assets/images/gvx/gvx-platform-syscalls.png)

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

På `windows/amd64` og `windows/arm64` oppretter `platform/whpx` en lettvekts hypervisor-partisjon via `WHvCreatePartition` uten å starte en gjestekjerne for operativsystemet:

- **Frikobler for 64 KB-til-4 KB-paging**: `whpx` registrerer hver 64 MiB-arena av `pgalloc.MemoryFile` hos partisjonen én gang via `WHvMapGpaRange`. Påfølgende kall til `MapFile` og `Unmap` endrer kun gjestens sidetabeller i partisjonen, og håndhever nøyaktige 4 KB-tillatelser `R/W/X` til tross for Windows' 64 KB-allokeringskornethet.
- **Registerutveksling uten API via `CommPage`**:
  - På `amd64` går gjestens Ring-3 `SYSCALL` inn i en Ring-0 `MSR_LSTAR`-stub i partisjonen (`stubgen_x86.go`), som skriver de raske systemkall-GPR-ene (`RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP`) til en delt 4 KB `CommPage` og kjører `HLT` for å avslutte `WHvRunVirtualProcessor`.
  - På `arm64` går gjestens EL0 `SVC #0` inn i EL1-vektorer (`stubgen_a64.go`), skriver `X0..X8, SP_EL0, ELR_EL1, PSTATE` til `CommPage`, og laster fra ubakket GPA-null for å utløse et minneavbrudd tilbake til Sentry.

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

På Apple Silicon (`darwin/arm64`) kjører `platform/hvf` containertråder inne i `Hypervisor.framework`-vCPU-er (`hv_vm_create`, `hv_vcpu_run`):

- **To-trinns 4 KB over 16 KB MMU-oversettelse**: Stage-2 (`hv_vm_map`) mapper 1 GiB store minnefilbiter inn i Intermediate Physical Address (IPA)-rommet én gang, med 16 KB vertssidekornethet og `HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC`. Inne i vCPU-en konfigurerer EL1-stubben `bluepill` (`bluepill_arm64.go`) `TCR_EL1.TG0 = 0b00` (4 KB-granule) i `TTBR0_EL1` og fyller Stage-1-sidetabelloppføringer på 4 KB med nøyaktige `R-X`- eller `RW-`-tillatelser (`UXN=1`). Fordi ARM64-MMU-en håndhever snittet av Stage-1- og Stage-2-tillatelser, fanger maskinvaren tillatelsesfeil på nøyaktige 4 KB-grenser.
- **Systemkallfelle**: Gjestens EL0 `SVC #0` fanges opp til EL1 `VBAR_EL1`, skriver registrene til den delte 4 KB `CommPage` og kjører `HVC #0` for å returnere fra `hv_vcpu_run` til Go-tråden for Sentry.

### 3. Windows brukermodus-reserve: `platform/systrap` (`winsystrap`)

Når maskinvarevirtualisering ikke er tilgjengelig (for eksempel i nestede skytilfeller), kjører `winsystrap` gjestekode i brukermodus på `windows/amd64` og `windows/arm64`:

- **Maskinvarebasert isolasjon via `CR3` / `TTBR0_EL1`**: Gjestetråder kjører i isolerte stub-underprosesser startet fra en generert 1 KB kjørbar fil (`stubimage_xplat.go`), begrenset av et token med lav integritet og et Job Object.
- **Patching av binærfil på stedet og `winSysmsg` IPC**: På `amd64` erstatter patcheren (`patcher_amd64_xplat.go`) 2-byte `syscall`-instruksjoner (`0f 05`) med 5-byte `jmp rel32`-hopp (eller `CC 90`-breakpoint-feller når et 5-byte-vindu ikke er tilgjengelig) inn i en øy for hurtig bane. På `arm64` patches `svc #0` med en `B`-grenhopp til en øyplass. Øya skriver registrene til den delte `winSysmsg`-siden og synkroniseres med Sentry via `WaitOnAddress` og `WakeByAddressSingle`, mens upatchede feller og sidefeil stopper på et Windows Debug Object (`WaitForDebugEventEx`).

### 4. Linux brukermodusmotor: `platform/systrap`

På `linux/amd64` og `linux/arm64` kjører `systrap` gjestetråder (`sysmsg`) som fanger gjestens systemkall via `SECCOMP_RET_TRAP` (`SIGSYS`) og binærpatcher `syscall`-steder til en trampoline i delt minne (`sysmsg`) synkronisert via `SYS_FUTEX`. Samtidig utfører en stub-`syscallThread` (`syscall_thread.go`) operasjoner på adresserom (`mmap`, `munmap`, `clone`) via `SECCOMP_RET_USER_NOTIF` (`_RUN_SECCOMP_LOOP`). Når `gvx` kjører inne i en ytre `gVisor` (`runsc`)-sandkasse der den ene `SECCOMP_FILTER_FLAG_NEW_LISTENER`-plassen returnerer `EBUSY`, bytter `gvx` automatisk `syscallThread` til en futex-løkke i delt minne (`_RUN_SYSCALL_LOOP`), som beskrevet i [del 3 av denne serien](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03).

---

## Hvordan `gvx` kobler gjestens Linux-systemkall til virtuelle delsystemer og vertshåndtak

Når en plattformmotor har fanget en gjeste-`SYSCALL` (`amd64`) eller `SVC #0`-instruksjon (`arm64`) og skrevet gjestens registre til den delte 4 KB-siden (`CommPage`, `sysmsg` eller `winSysmsg`), returnerer kontrollen til Go-gorutinen for Sentry-oppgaven (`pkg/sentry/kernel/task_syscall.go`). I stedet for å videresende Linux-systemkall til den underliggende kjernen i vertens operativsystem, lagrer `Task.doSyscall()` den opprinnelige registertilstanden (`SyscallSaveOrig()`), evaluerer eventuelle BPF `seccomp`-filtre og `ptrace`-stopp i gjesten, og sender systemkallnummeret gjennom `linux.AMD64` eller `linux.ARM64` (`pkg/sentry/syscalls/linux/linux64.go`, som dekker ca. 370 Linux-systemkall) til fire interne domener:

![Hvordan gvx kobler gjestens Linux-systemkall til delsystemer og vertsoperativsystemet](/assets/images/gvx/gvx-syscall-mapping.png)

| Systemkalldomene | Representative Linux-systemkall i gjesten | Intern `gvx`-delkomponent (`pkg/sentry`) | Interaksjon med vertens operativsystemgrense (etter `hostlockdown`) |
| :--- | :--- | :--- | :--- |
| **A. Prosess, navnerom, montering og synkronisering** | `clone`, `execve`, `unshare`, `setns`, `mount`, `umount2`, `pivot_root`, `setuid`, `capset`, `futex`, `epoll_wait`, `pipe2` | `kernel.Task`, virtuelle legitimasjoner, futex-tabell og `VFS2` i minnet (`procfs`, `sysfs`, `cgroupfs` v2, `tmpfs`, `overlayfs`) | **Null systemkall på verten** (100 % Go-tilstand i minnet; fullstendig usynlig for vertens operativsystem) |
| **B. Virtuelt minne (`MM`)** | `mmap`, `munmap`, `mremap`, `mprotect`, `brk`, `madvise`, `memfd_create` | `mm.MemoryManager` (VMA-tre med 4 KB) og `pgalloc.MemoryFile` | Toveis oppdateringer av 4 KB-sidetabeller via `WHvMapGpaRange`, `hv_vm_map` + `TTBR0_EL1`, eller stub-`mmap`/`mprotect` |
| **C. Filer og lagring (`VFS2`)** | `openat`, `pread64`, `pwrite64`, `getdents64`, `statx`, `renameat2`, `setxattr`, `mknod`, `inotify_add_watch` | `vfs.VirtualFilesystem`-monteringstabellens ruter (`fsimpl/erofs`, `fsimpl/ext4lite`, `fsimpl/hostfs` v2) | Toveis `pread`/`pwrite` på 1 festet `.erofs`-FD eller 1 `.ext4`-FD, eller avgrensede relative gjennomgåinger av `*os.Root` |
| **D. Nettverk og Netfilter** | `socket`, `bind`, `listen`, `connect`, `sendmsg`, `recvmsg`, `netlink`, `setsockopt(IPT_SO_SET_REPLACE)` | Brukerromsbasert `pkg/tcpip` (`lo`, `eth0`, `docker0`, `veth`, `vxlan`, `wireguard`, `ipset`, `iptables-legacy`) | Trafikk internt i sandkassen bruker **null systemkall på verten**; ekstern trafikk mappes til `net.Dial`/`net.Listen` (`-net=nat`) eller 1 UDP-socket (`-net=wg`) |

Når behandleren returnerer `(rval, ctrl, err)`, konverterer `Task.doSyscallInvoke()` eventuelle feil til en negativ Linux-`errno` (`-ExtractErrno(err, sysno)`), skriver returverdien tilbake til den delte registersiden (`RAX` på `amd64`, `X0` på `arm64`) og gjenopptar kjøringen i gjesten.

---

## Lagring (`VFS2`) og tospors brukerromsnettverk (`netstack`)

All filhåndtering og nettverkstrafikk i gjesten betjenes inne i Go-`Sentry` gjennom tre `VFS2`-filsystemer og to spor i `pkg/netbackend`:

![gvx VFS2-lagringsmotorer og tospors netstack](/assets/images/gvx/gvx-storage-netstack.png)

| Lagringsmotor          | Monteringsrolle i `gvx`                          | Underliggende vertsressurs              | Kall til vertens `openat` / `NtCreateFile` ved kjøring | Windows Defender (`WdFilter.sys`) skanninger per fil |
| :--------------------- | :----------------------------------------------- | :-------------------------------------- | -----------------------------------------------------: | ---------------------------------------------------: |
| **`fsimpl/erofs`**     | Skrivebeskyttede nedre lag i OCI-image           | Én `<sha256>.erofs`-fil per lag         |                                                   `0` |                                                  `0` |
| **`fsimpl/ext4lite`**  | Navngitte volumer (`-v name:/path`)              | Én `<name>.ext4`-fil per volum          |                                                   `0` |                                                  `0` |
| **`fsimpl/hostfs` v2** | Vertens arbeidsområde (`-workspace`, `-v /host:/guest`) | Festet `*os.Root`-vertskatalog   |                                    `O(dybde)` per ukachet åpning |                                      `1` per lukking av vertsfil |

### Hvorfor `ext4lite` er viktig for Docker, databaser og pakkehåndterere

Å pakke ut eller skrive titusenvis av containerfiler direkte til Windows NTFS eller macOS APFS utløser skanninger fra antivirusfilterdrivere (`WdFilter.sys`), kollisjoner i forskjell mellom store og små bokstaver, og manglende utvidede POSIX-attributter.

`pkg/sentry/fsimpl/ext4lite` implementerer et rent Go-`ext4`-filsystem inne i én forhåndsåpnet vertsfil (`%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-blokker og 16 MiB dynamiske blokkgrupper (`meta_bg`)**: Vokser dynamisk uten stopp ved allokering av sparsomme filer (`fallocate` på Linux, `fcntl(F_PREALLOCATE)` på macOS, `FileAllocationInfo` på Windows) og komprimerer ubrukte grupper på slutten ved ren avmontering.
- **JBD2-journal i ordered-modus (inode 8)**: Atomiske transaksjonsforpliktelser med CRC-32-kontrollsummer og revoke-blokker, samt gjenoppretting med `fsckLite`.
- **Støtte for `overlayfs` øvre lag**: Implementerer utvidede attributter `trusted.overlay.*` og `security.capability`, whiteouts for tegnenheter (`0:0`), rapportering av `d_type` for katalogoppføringer og `RENAME_EXCHANGE`.

---

## Praktiske arbeidslaster: Docker-motor, Kubernetes (`k3s` + `Calico`) og Go-SDK

### Installasjon av `rungv`: SLSA-attesterte forhåndsbygde utgivelser eller `go install`

Du kan laste ned et forhåndsbygd `rungv`-arkiv for `linux/amd64`, `linux/arm64`, `darwin/arm64`, `windows/amd64` eller `windows/arm64` fra [GitHub Releases](https://github.com/gfire-sigs/gvx/releases) (hvert bygget av SLSA-utgivelsespipelinen med en Sigstore-proveniensbunt og `SHA256SUMS`), eller installere direkte fra kildekoden med `go install`:

```sh
# Alternativ A: Last ned en forhåndsbygd utgivelse og verifiser SLSA-byggproveniens
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

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

> På macOS (`darwin/arm64`) er det forhåndsbygde utgivelsesarkivet allerede signert med rettigheten `com.apple.security.hypervisor` (`xattr -d com.apple.quarantine rungv` fjerner karantene fra nettleseren). Hvis du bygger lokalt med `go install` eller `go build` på macOS, må du signere binærfilen med `codesign --sign - --entitlements entitlements.plist --force $(which rungv)`.

### 1. Kjøre en uprivilegert Docker-motor (`docker:dind`)

Etter [`docs/docker-engine.md`](https://github.com/gfire-sigs/gvx/blob/main/docs/docker-engine.md) kan du kjøre en umodifisert `docker:dind`-container inne i `rungv` på Windows, macOS eller Linux og styre den med din lokale `docker`-CLI:

```sh
# 1. Opprett vertskatalogen for det videresendte Unix-socket
mkdir -p ~/.gvx

# 2. Start docker:dind inne i en gvx-sandkasse med et ext4lite-volum
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 andre terminal peker du din lokale `docker`-CLI mot sandkassens socket:

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

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

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

### 2. Kjøre Kubernetes (`k3s` + `Calico`) i uprivilegerte sandkasser

Fordi `gvx` implementerer `/dev/kmsg`, `cgroup` v2 (`memory.max` OOM-drepen og `cpu.max`-båndbreddebegrensning), `/proc/diskstats`, netlink-enheter for `wireguard` og `vxlan`, `ipset` og `iptables-legacy` (`addrtype`, `conntrack`, `statistic`, `recent`), når et umodifisert `rancher/k3s`-image status `Ready` inne i én enkelt `rungv`-prosess:

```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å koble flere `gvx`-noder sammen over WireGuard (`flannel-backend=wireguard-native` eller et `wg0`-nett) med innebygd `etcd` og høy tilgjengelighet, eller kjøre **Calico** (`calico-vxlan.yaml` med `FELIX_IPTABLESBACKEND=Legacy`) for å håndheve Kubernetes `NetworkPolicy` helt i brukerrommet.

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

Go-applikasjoner kan bygge inn Linux-containere direkte uten 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)
}
```

---

## Videre lesning i denne serien

1. **[gvx: Kjøre Linux-containere, Docker og Kubernetes i én uprivilegert prosess](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)** (dette innlegget)
2. **[Kjøre Docker, docker build og docker compose uten root eller brukernavnerom](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)**: Hvordan starte `docker:dind` i låste sandkasser der `sudo`, `unshare(CLONE_NEWUSER)`, `mount(2)` og `/dev/fuse` er blokkert.
3. **[Kjøre Docker-in-Docker inne i gVisor og nestede sandkasser med gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Hvorfor `apt-get install docker.io` og nestet `runsc` feiler inne i `gVisor` på tvers av fem kjernebarrierer, og hvordan `gvx` kjører nestet `docker:dind` ved hjelp av en futex-løkke i delt minne.
4. **[Raske, isolerte Docker-miljøer for RL-utrullinger av AI-agenter med gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Skalering av `SWE-bench` og forsterkningslæringsutrullinger for agenter med hundrevis av parallelle uprivilegerte `docker:dind`-instanser og 100 millisekunders copy-on-write-tilbakestillinger av `.ext4`-volumer.
