Kjøring av Docker, docker build og docker compose uten Root eller User Namespaces

Rask løsning: Sikker, uprivilegert Docker i tre steg
Hvis du arbeider i en låst Linux-container, CI-runner, Kubernetes Pod eller AI-agentsandkasse der root, sudo, brukernavnrom (unshare(CLONE_NEWUSER)), mount(2) og /dev/fuse er blokkert, er gvx (rungv) den sikre løsningen med dybdeforsvar for å kjøre en fullstendig docker:dind-motor i brukerrom.
Hvorfor
gvxer trygt by design (ikke en omgåelse av rettighetseskalering): I motsetning til å montere vertens/var/run/docker.sockeller kjøredocker run --privileged(som gir root-tilsvarende kontroll over vertskjernen), omgår eller svekker ikkegvxnoen sikkerhetspolicy på verten (PR_SET_NO_NEW_PRIVS,seccomp, AppArmor eller begrensninger for ikke-root-UID). I stedet låserrungvsin egen vertsprosess (PR_SET_NO_NEW_PRIVS+ streng BPFseccomp-tillatelsesliste) og kjørerdockerdinne i Googles minnesikre gVisor (Sentry)-kjerne i brukerrom. Alle gjestensUID 0-egenskaper,overlayfs-monteringer (ext4lite) ogiptables-regler forblir strengt isolert inne i sandkasseprosessen.
1# 1. Installer rungv i brukerrom (forhåndsbygd SLSA-attestert utgivelse eller go install)
2# Alternativ A: Verifiser og pakk ut den SLSA-attesterte forhåndsbygde binærfilen fra GitHub Releases
3gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
4 --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
5 --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
6tar -xzf rungv-v0.2.0-linux-amd64.tar.gz && install -m 0755 rungv-v0.2.0-linux-amd64/rungv ~/.local/bin/rungv
7
8# Alternativ B: Eller installer direkte fra kildekode med Go
9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. Start docker:dind i gvx med et enfils ext4lite-volum
12# Videresender ~/.gvx/docker.sock (modus 0600) til gjestens port 2375
13mkdir -p ~/.gvx
14~/.local/bin/rungv run \
15 -p unix:~/.gvx/docker.sock:2375 \
16 -p 127.0.0.1:9000-9019:9000-9019 \
17 -v gvx-docker:/var/lib/docker \
18 -e DOCKER_TLS_CERTDIR= \
19 docker:dind --tls=false &
20
21# 3. Pek standard Docker-CLI og Docker Compose mot socketen i brukerrom
22export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
23until docker info >/dev/null 2>&1; do sleep 0.5; done
24docker info --format '{{.Driver}} {{.OperatingSystem}}'
25# Utdata: overlayfs Alpine Linux ... (containerisert)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d
Hvorfor standard rootless-verktøy feiler i begrensede sandkasser
Når en ingeniør eller en autonom kodeagent trenger å kjøre docker build, docker run eller docker compose inne i en herdet container eller en flerbrukerrunner, feiler standardløsninger ved fem distinkte kjernebarrierer.
1. Ingen vertens Docker-daemon-socket
Kommandoene docker ps og docker build feiler umiddelbart når vertens /var/run/docker.sock ikke er montert inn i miljøet:
1Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
2. PR_SET_NO_NEW_PRIVS blokkerer sudo og setuid-hjelpere
Herdede containere (securityContext.allowPrivilegeEscalation: false i Kubernetes, --security-opt=no-new-privileges i Docker, eller exebox- eller bwrap-sandkasser) setter Linux-biten PR_SET_NO_NEW_PRIVS på prosesstreet. Forsøk på å eskalere via sudo eller setuid-binærfiler (newuidmap, newgidmap, fusermount3) feiler:
1sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
2sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
3. Seccomp- og sysctl-policyer blokkerer unshare(CLONE_NEWUSER)
Verktøy som markedsføres som «rootless» (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap) er fortsatt avhengige av Linux-brukernavnrom (CLONE_NEWUSER). De feiler når:
- Den ytre containerens standard seccomp-profil blokkerer
unshare(2)ellerclone(CLONE_NEWUSER). - Ubuntu 24.04+ aktiverer
kernel.apparmor_restrict_unprivileged_userns = 1. - Debian- eller RHEL-noder setter
kernel.unprivileged_userns_clone = 0elleruser.max_user_namespaces = 0. newuidmapikke kan skrive til/proc/self/uid_mapfordiPR_SET_NO_NEW_PRIVSer aktiv.
Feilmeldingene ser slik ut:
1unshare: unshare failed: Operation not permitted
2cannot clone: Operation not permitted
3Error: cannot re-exec process to join the existing user namespace
4newuidmap: write to uid_map failed: Operation not permitted
5RootlessKit: parent: failed to start the child: fork/exec /proc/self/exe: operation not permitted
4. mount(2) er blokkert uten vertens CAP_SYS_ADMIN
Selv om et miljø tillater CLONE_NEWUSER, feiler montering av en ny /proc inne i et nestet monteringsnavnerom hvis den ytre containeren har maskert /proc-undertrær (/proc/acpi, /proc/kcore, /proc/keys) eller fjernet mount(2) fra seccomp:
1mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
2OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "proc" to rootfs at "/proc": mount proc:/proc (via /proc/self/fd/6), flags: 0xe: operation not permitted
3bwrap: Creating new namespace failed: Operation not permitted
5. Manglende /dev/fuse ødelegger fuse-overlayfs
Rootless-containermotorer som ikke kan montere kjerne-overlayfs, faller tilbake til fuse-overlayfs. I minimale containere eller Kubernetes-pods uten videresending av enheten /dev/fuse feiler fuse-overlayfs umiddelbart:
1fuse: device not found, try 'modprobe fuse' first
2fusermount3: failed to open /dev/fuse: No such file or directory
3error initializing graphdriver: driver not supported: fuse-overlayfs
Hvordan gvx kjører docker:dind helt i brukerrom
gvx omgår alle fem kjernebarrierene fordi den ikke ber vertens Linux-kjerne om å opprette navnerom, montere filsystemer eller konfigurere nettverksgrensesnitt. I stedet kjører rungv en intern Linux-kjerne i brukerrom (gVisor Sentry) og en nettverksstakk i brukerrom (netstack) inne i én vanlig, uprivilegert prosess.

1. Navnerom i minnet og monteringstabell (VFS2)
Når dockerd, containerd og runc kjører inne i rungv, fanger systrap opp systemkallene deres og sender dem til den prosessinterne Sentry-kjernen i stedet for vertskjernen:
unshare(2),clone(2),pivot_root(2),chroot(2)ogmount(2)opererer på Sentry sin oppgavehierarki i minnet ogVFS2-monteringstabellen (procfs,sysfs,tmpfs,devpts,cgroupfsv2), mens vertsprosessenrungvkjører under din uprivilegerte UID på verten.
2. Native overlayfs på enfils ext4lite-volumer
Når du sender -v gvx-docker:/var/lib/docker (eller --mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker), monterer gvx sitt innebygde ext4lite-filsystem på /var/lib/docker.
Fordi ext4lite implementerer et JBD2-journalført ext4-filsystem inne i én enkelt vertsfil (gvx-docker.ext4) med støtte for trusted.overlay.*-utvidede attributter, tegn-whiteout-enheter (0:0), d_type og RENAME_EXCHANGE, bruker dockerd sin native overlayfs-lagringsdriver inne i gjesten. Flertrinns docker build-operasjoner deler Copy-on-Write-lag uten /dev/fuse og uten den eksplosive økningen i diskbruk som kommer med Dockers vfs-reservedriver.
3. Brukerrom-docker0-bro og iptables-legacy
Når docker:dind starter inne i gvx:
- Gjestens
dockerdoppretterdocker0-broen (172.17.0.1/16), kobler til virtuelleveth-par for nestede containere, og programmererNAT- (DOCKER,POSTROUTING) ogFILTER-kjeder medaddrtype- ogconntrack-treff inne igvxsinnetstacki brukerrom. - Ved å sende
-p unix:~/.gvx/docker.sock:2375binder man en vertens Unix-domenesocket (modus0600) og videresender tilkoblinger direkte til port2375pådockerdinne i sandkassen.
Sammenligning med eksisterende containerverktøy
| Egenskap / Begrensning | Standard Docker (dockerd) | Rootless Docker / Podman | Kaniko / Buildah (uprivilegert) | gvx (rungv + docker:dind) |
|---|---|---|---|---|
Krever vert-root eller sudo | Ja | Nei | Nei | Nei |
Fungerer med PR_SET_NO_NEW_PRIVS=1 | Nei | Nei (newuidmap feiler) | Delvis | Ja |
Fungerer når unshare(CLONE_NEWUSER) er blokkert (EPERM) | N/A | Nei | Buildah: Nei / Kaniko: Ja | Ja |
Fungerer uten /dev/fuse | Ja (bruker kjerne-overlay2) | Kun via treg vfs-kopiering | Ja | Ja (overlayfs på ext4lite) |
Støtter docker build (BuildKit) | Ja | Ja (hvis userns er tillatt) | Kun bygging av images (ingen kjøring) | Ja |
Støtter docker run og docker compose up | Ja | Ja (hvis userns er tillatt) | Nei | Ja |
| Kjører på Windows og macOS uten Linux-VM | Nei (krever WSL2 / VM) | Nei (krever Linux-VM) | Nei | Ja (whpx, hvf, systrap) |
Eksakte vertskjernekrav på Linux
gvx krever null forhøyede egenskaper (CapEff: 0000000000000000) og null brukernavnrom. På en Linux-vert er rungv avhengig av bare tre standard uprivilegerte kjerneprimitiver:
ptrace(PTRACE_ATTACH)på sin egen barnetråd én gang under initialisering:systrapstarter en lokal stub-hjelpertråd ved oppstart, kobler seg til den for å initialisere den delte minnekonteksten, og kobler seg fra. Hvis verten setterkernel.yama.ptrace_scope = 3(som deaktiverer allptracesystemomfattende) eller blokkererptracei et ytre seccomp-filter, kan ikkesystrap-initialiseringen fullføres. (Underyama.ptrace_scope = 1, standard på Ubuntu og Debian, lykkesgvxfordi sporing fra forelder til barn er tillatt.)seccomp(SECCOMP_SET_MODE_FILTER): Brukes til å fange gjestens systemkall fra containerens stub-tråder. Som beskrevet i del 3 av denne serien, fungerergvxbåde nårSECCOMP_FILTER_FLAG_NEW_LISTENERer tilgjengelig og når den returnererEBUSYinne i en nestet sandkasse.mmap(..., PROT_EXEC, ...): Brukes til å mappe gjestens ELF-segmenter ogsystrap-trampolinen for delt minne.
Ende-til-ende-eksempel: Bygge og teste en flercontainerapp uten root
Følgende skript kjører en fullstendig docker build og en integrasjonstest med to containere (redis + applikasjonscontainer) inne i en uprivilegert brukerøkt:
1mkdir -p ~/.gvx
2rungv run \
3 -p unix:~/.gvx/docker.sock:2375 \
4 -v gvx-docker:/var/lib/docker \
5 -e DOCKER_TLS_CERTDIR= \
6 docker:dind --tls=false &
7DIND_PID=$!
8
9export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
10until docker info >/dev/null 2>&1; do sleep 0.5; done
11
12mkdir -p /tmp/demo-app && cd /tmp/demo-app
13cat <<'EOF' > Dockerfile
14FROM alpine:3.20
15RUN apk add --no-cache redis
16CMD ["redis-cli", "-h", "cache", "ping"]
17EOF
18
19# Bygg imaget med overlayfs på ext4lite
20docker build -t demo-ping:latest .
21
22# Opprett et bro-nettverk, start Redis og verifiser tilkobling mellom containerne
23docker network create demo-net
24docker run -d --name cache --network demo-net redis:7-alpine
25docker run --rm --network demo-net demo-ping:latest
26# Utdata: PONG
27
28# Rydd opp i arbeidscontainerne og stopp sandkassen
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID
Videre lesning i denne serien
- gvx: Kjør Linux-containere, Docker og Kubernetes i én uprivilegert prosess: Arkitekturoversikt over
gvx, dets plattformuavhengige kjøremotorer (whpx,hvf,systrap),VFS2(erofs,ext4lite,hostfsv2) ognetstack. - Kjøre Docker, docker build og docker compose uten root eller brukernavnrom (dette innlegget)
- Kjøre Docker-in-Docker inne i gVisor og nestede sandkasser med gvx: Hvordan
gvxløsermodprobe,iptables-nft,overlay2pågofer, og nestetSECCOMP_FILTER_FLAG_NEW_LISTENER(EBUSY) inne igVisor(runsc). - Raske, isolerte Docker-miljøer for RL-utrullinger av AI-agenter med gvx: Skalering av parallelle
SWE-bench- og RL-utrullingsmiljøer med tilbakestillinger av.ext4-volumer med copy-on-write på 100 millisekunder.