---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Kjøring av Docker, docker build og docker compose uten Root eller User Namespaces
description: Hvordan man sikkert kjører en fullstendig Docker Engine (dockerd, BuildKit, overlayfs og docker compose) inne i en isolert gVisor-sandkasse i brukerrom som en uprivilegert bruker, når root, sudo, unshare(CLONE_NEWUSER), mount(2) og /dev/fuse er blokkert.
language: "no"
date: 2026-11-06T12:02:56.050897958Z
path: /blog/posts/run-docker-without-root-or-userns-gvx-z48916d02
go_package: z.gfire.dev/gvx
go_repourl: https://github.com/gfire-sigs/gvx.git
category: ops
---

## 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](https://github.com/gfire-sigs/gvx)** (`rungv`) den **sikre løsningen med dybdeforsvar** for å kjøre en fullstendig `docker:dind`-motor i brukerrom.

> **Hvorfor `gvx` er trygt by design (ikke en omgåelse av rettighetseskalering)**: I motsetning til å montere vertens `/var/run/docker.sock` eller kjøre `docker run --privileged` (som gir root-tilsvarende kontroll over vertskjernen), omgår eller svekker ikke `gvx` noen sikkerhetspolicy på verten (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor eller begrensninger for ikke-root-UID). I stedet låser `rungv` sin egen vertsprosess (`PR_SET_NO_NEW_PRIVS` + streng BPF `seccomp`-tillatelsesliste) og kjører `dockerd` inne i Googles minnesikre **gVisor (`Sentry`)**-kjerne i brukerrom. Alle gjestens `UID 0`-egenskaper, `overlayfs`-monteringer (`ext4lite`) og `iptables`-regler forblir strengt isolert inne i sandkasseprosessen.

```sh
# 1. Installer rungv i brukerrom (forhåndsbygd SLSA-attestert utgivelse eller go install)
# Alternativ A: Verifiser og pakk ut den SLSA-attesterte forhåndsbygde binærfilen fra GitHub Releases
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
tar -xzf rungv-v0.2.0-linux-amd64.tar.gz && install -m 0755 rungv-v0.2.0-linux-amd64/rungv ~/.local/bin/rungv

# Alternativ B: Eller installer direkte fra kildekode med Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Start docker:dind i gvx med et enfils ext4lite-volum
#    Videresender ~/.gvx/docker.sock (modus 0600) til gjestens port 2375
mkdir -p ~/.gvx
~/.local/bin/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 &

# 3. Pek standard Docker-CLI og Docker Compose mot socketen i brukerrom
export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
until docker info >/dev/null 2>&1; do sleep 0.5; done
docker info --format '{{.Driver}} {{.OperatingSystem}}'
# Utdata: overlayfs Alpine Linux ... (containerisert)

docker build -t app:test .
docker run --rm app:test
docker 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:

```text
Cannot 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:

```text
sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
sudo: 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)` eller `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ aktiverer `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Debian- eller RHEL-noder setter `kernel.unprivileged_userns_clone = 0` eller `user.max_user_namespaces = 0`.
- `newuidmap` ikke kan skrive til `/proc/self/uid_map` fordi `PR_SET_NO_NEW_PRIVS` er aktiv.

Feilmeldingene ser slik ut:

```text
unshare: unshare failed: Operation not permitted
cannot clone: Operation not permitted
Error: cannot re-exec process to join the existing user namespace
newuidmap: write to uid_map failed: Operation not permitted
RootlessKit: 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:

```text
mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
OCI 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
bwrap: 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:

```text
fuse: device not found, try 'modprobe fuse' first
fusermount3: failed to open /dev/fuse: No such file or directory
error 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.

![Kjører uprivilegert Docker-in-Docker med gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 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)` og `mount(2)` opererer på Sentry sin oppgavehierarki i minnet og `VFS2`-monteringstabellen (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), mens vertsprosessen `rungv` kjø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 `dockerd` oppretter `docker0`-broen (`172.17.0.1/16`), kobler til virtuelle `veth`-par for nestede containere, og programmerer `NAT`- (`DOCKER`, `POSTROUTING`) og `FILTER`-kjeder med `addrtype`- og `conntrack`-treff inne i `gvx` sin `netstack` i brukerrom.
- Ved å sende `-p unix:~/.gvx/docker.sock:2375` binder man en vertens Unix-domenesocket (modus `0600`) og videresender tilkoblinger direkte til port `2375` på `dockerd` inne 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:

1. **`ptrace(PTRACE_ATTACH)` på sin egen barnetråd én gang under initialisering**: `systrap` starter en lokal stub-hjelpertråd ved oppstart, kobler seg til den for å initialisere den delte minnekonteksten, og kobler seg fra. Hvis verten setter `kernel.yama.ptrace_scope = 3` (som deaktiverer all `ptrace` systemomfattende) eller blokkerer `ptrace` i et ytre seccomp-filter, kan ikke `systrap`-initialiseringen fullføres. (Under `yama.ptrace_scope = 1`, standard på Ubuntu og Debian, lykkes `gvx` fordi sporing fra forelder til barn er tillatt.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Brukes til å fange gjestens systemkall fra containerens stub-tråder. Som beskrevet i [del 3 av denne serien](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03), fungerer `gvx` både når `SECCOMP_FILTER_FLAG_NEW_LISTENER` er tilgjengelig og når den returnerer `EBUSY` inne i en nestet sandkasse.
3. **`mmap(..., PROT_EXEC, ...)`**: Brukes til å mappe gjestens ELF-segmenter og `systrap`-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:

```sh
mkdir -p ~/.gvx
rungv run \
  -p unix:~/.gvx/docker.sock:2375 \
  -v gvx-docker:/var/lib/docker \
  -e DOCKER_TLS_CERTDIR= \
  docker:dind --tls=false &
DIND_PID=$!

export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
until docker info >/dev/null 2>&1; do sleep 0.5; done

mkdir -p /tmp/demo-app && cd /tmp/demo-app
cat <<'EOF' > Dockerfile
FROM alpine:3.20
RUN apk add --no-cache redis
CMD ["redis-cli", "-h", "cache", "ping"]
EOF

# Bygg imaget med overlayfs på ext4lite
docker build -t demo-ping:latest .

# Opprett et bro-nettverk, start Redis og verifiser tilkobling mellom containerne
docker network create demo-net
docker run -d --name cache --network demo-net redis:7-alpine
docker run --rm --network demo-net demo-ping:latest
# Utdata: PONG

# Rydd opp i arbeidscontainerne og stopp sandkassen
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Videre lesning i denne serien

1. **[gvx: Kjør Linux-containere, Docker og Kubernetes i én uprivilegert prosess](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Arkitekturoversikt over `gvx`, dets plattformuavhengige kjøremotorer (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) og `netstack`.
2. **[Kjøre Docker, docker build og docker compose uten root eller brukernavnrom](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (dette innlegget)
3. **[Kjøre Docker-in-Docker inne i gVisor og nestede sandkasser med gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Hvordan `gvx` løser `modprobe`, `iptables-nft`, `overlay2` på `gofer`, og nestet `SECCOMP_FILTER_FLAG_NEW_LISTENER` (`EBUSY`) inne i `gVisor` (`runsc`).
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 parallelle `SWE-bench`- og RL-utrullingsmiljøer med tilbakestillinger av `.ext4`-volumer med copy-on-write på 100 millisekunder.
