---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Köra Docker, docker build och docker compose utan root eller användarnamnrymder
description: Hur man säkert kör en komplett Docker Engine (dockerd, BuildKit, overlayfs och docker compose) i en isolerad gVisor-sandlåda i användarutrymme som en användare utan privilegier när root, sudo, unshare(CLONE_NEWUSER), mount(2) och /dev/fuse är blockerade.
language: sv
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
---

## Snabblösning: Säkra Docker utan privilegier i tre steg

Om du arbetar i en låst Linux-container, CI-runner, Kubernetes Pod eller AI-agentsandlåda där `root`, `sudo`, användarnamnrymder (`unshare(CLONE_NEWUSER)`), `mount(2)` och `/dev/fuse` är blockerade, är **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) den **säkra lösningen med försvar på flera nivåer** för att köra en fullständig `docker:dind`-motor i användarutrymme.

> **Varför `gvx` är säkert by design (inte en lösning för privilegieeskalering)**: Till skillnad från att montera värdens `/var/run/docker.sock` eller köra `docker run --privileged` (vilket ger root-motsvarande kontroll över värdens kärna) kringgår eller försvagar inte `gvx` någon säkerhetspolicy på värden (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor eller begränsningar för icke-root-UID). I stället låser `rungv` sin egen värdprocess (`PR_SET_NO_NEW_PRIVS` + en strikt BPF-`seccomp`-tillåtelselista) och kör `dockerd` inuti Googles minnessäkra **gVisor (`Sentry`)**-kärna i användarutrymme. Alla gäst-`UID 0`-förmågor, `overlayfs`-monteringar (`ext4lite`) och `iptables`-regler förblir strikt isolerade inom sandlådeprocessen.

```sh
# 1. Installera rungv i användarutrymme (förkompilerad SLSA-attesterad release eller go install)
# Alternativ A: Verifiera och extrahera den SLSA-attesterade förkompilerade binären från 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 installera direkt från källkod med Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Starta docker:dind inuti gvx med en enfils-ext4lite-volym
#    Vidarebefordrar ~/.gvx/docker.sock (läge 0600) till gästens 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. Peka den vanliga Docker CLI och Docker Compose mot användarutrymmets socket
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 ... (containerized)

docker build -t app:test .
docker run --rm app:test
docker compose up -d
```

---

## Varför vanliga verktyg för rootless-körning misslyckas i begränsade sandlådor

När en ingenjör eller en autonom kodningsagent behöver köra `docker build`, `docker run` eller `docker compose` inuti en härdad container eller en multi-tenant-runner, misslyckas vanliga lösningar vid fem separata kärnbarriärer.

### 1. Ingen värd-socket för Docker-daemonen

Att köra `docker ps` eller `docker build` misslyckas omedelbart när värdens `/var/run/docker.sock` inte är monterad i miljön:

```text
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```

### 2. `PR_SET_NO_NEW_PRIVS` blockerar `sudo` och setuid-hjälpprogram

Härdade containrar (`securityContext.allowPrivilegeEscalation: false` i Kubernetes, `--security-opt=no-new-privileges` i Docker, eller `exebox`- / `bwrap`-sandlådor) sätter biten `PR_SET_NO_NEW_PRIVS` i Linux på processträdet. Försök att eskalera via `sudo` eller setuid-binärer (`newuidmap`, `newgidmap`, `fusermount3`) misslyckas:

```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- och sysctl-policyer blockerar `unshare(CLONE_NEWUSER)`

Verktyg som marknadsförs som "rootless" (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`) förlitar sig fortfarande på Linux **användarnamnrymder** (`CLONE_NEWUSER`). De misslyckas när:

- Den yttre containerns standardprofil för seccomp blockerar `unshare(2)` eller `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ aktiverar `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Debian- eller RHEL-noder sätter `kernel.unprivileged_userns_clone = 0` eller `user.max_user_namespaces = 0`.
- `newuidmap` inte kan skriva till `/proc/self/uid_map` eftersom `PR_SET_NO_NEW_PRIVS` är aktivt.

De resulterande felen ser ut så här:

```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)` är blockerad utan värdens `CAP_SYS_ADMIN`

Även om en miljö tillåter `CLONE_NEWUSER` misslyckas montering av en ny `/proc` inuti en kapslad monteringsnamnrymd om den yttre containern har maskerat `/proc`-delträd (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) eller tagit bort `mount(2)` från 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. Saknad `/dev/fuse` bryter `fuse-overlayfs`

Rootless-containermotorer som inte kan montera kärnans `overlayfs` faller tillbaka till `fuse-overlayfs`. I minimala containrar eller Kubernetes-pods utan genomslussning av enheten `/dev/fuse` misslyckas `fuse-overlayfs` omedelbart:

```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
```

---

## Hur `gvx` kör `docker:dind` helt i användarutrymme

`gvx` kringgår alla fem kärnbarriärerna eftersom den inte ber värdens Linux-kärna att skapa namnrymder, montera filsystem eller konfigurera nätverksgränssnitt. I stället kör `rungv` en intern Linux-kärna i användarutrymme (gVisor `Sentry`) och en nätverksstack i användarutrymme (`netstack`) inuti en enda vanlig process utan privilegier.

![Körning av Docker-in-Docker utan privilegier med gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Namnrymder och monteringstabell i minnet (`VFS2`)

När `dockerd`, `containerd` och `runc` körs inuti `rungv` fångar `systrap` upp deras systemanrop och dirigerar dem till den processinterna `Sentry`-kärnan i stället för till värdens kärna:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)` och `mount(2)` arbetar mot Sentrys uppgiftshierarki i minnet och monteringstabellen `VFS2` (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), medan värdprocessen `rungv` körs under ditt UID på värden utan privilegier.

### 2. Native `overlayfs` på enfils-volymer av typen `ext4lite`

När du anger `-v gvx-docker:/var/lib/docker` (eller `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`) monterar `gvx` sitt inbyggda filsystem **`ext4lite`** på `/var/lib/docker`.

Eftersom `ext4lite` implementerar ett JBD2-journalfört `ext4`-filsystem inuti en enda fil på värden (`gvx-docker.ext4`) med stöd för utökade attribut `trusted.overlay.*`, teckenbaserade whiteout-enheter (`0:0`), `d_type` och `RENAME_EXCHANGE`, använder `dockerd` sin inbyggda lagringsdrivrutin **`overlayfs`** inuti gästen. Flerstegsoperationer för `docker build` delar Copy-on-Write-lager utan `/dev/fuse` och utan den diskutrymmesexplosion som följer av Dockers reservdrivrutin `vfs`.

### 3. Användarutrymmets `docker0`-brygga och `iptables-legacy`

När `docker:dind` startar inuti `gvx`:

- Gästens `dockerd` skapar bryggan `docker0` (`172.17.0.1/16`), kopplar virtuella `veth`-par för kapslade containrar och programmerar kedjorna `NAT` (`DOCKER`, `POSTROUTING`) och `FILTER` med matchningar för `addrtype` och `conntrack` inuti `gvx`:s `netstack` i användarutrymme.
- Med `-p unix:~/.gvx/docker.sock:2375` binds en Unix-domänsocket på värden (läge `0600`) och anslutningar vidarebefordras direkt till port `2375` för `dockerd` inuti sandlådan.

---

## Jämförelse med befintliga containerverktyg

| Egenskap / Begränsning                                       | Standard Docker (`dockerd`)          | Rootless Docker / Podman              | Kaniko / Buildah (utan privilegier)       | `gvx` (`rungv` + `docker:dind`)           |
| :----------------------------------------------------------- | :----------------------------------- | :------------------------------------ | :---------------------------------------- | :---------------------------------------- |
| **Värd-`root` eller `sudo` krävs**                           | Ja                                   | Nej                                   | Nej                                       | **Nej**                                   |
| **Fungerar med `PR_SET_NO_NEW_PRIVS=1`**                     | Nej                                  | Nej (`newuidmap` misslyckas)          | Delvis                                    | **Ja**                                    |
| **Fungerar när `unshare(CLONE_NEWUSER)` är blockerad (`EPERM`)** | N/A                              | Nej                                   | Buildah: Nej / Kaniko: Ja                 | **Ja**                                    |
| **Fungerar utan `/dev/fuse`**                                | Ja (använder kärnans `overlay2`)     | Endast via långsam `vfs`-kopiering    | Ja                                        | **Ja (`overlayfs` på `ext4lite`)**        |
| **Stöder `docker build` (BuildKit)**                         | Ja                                   | Ja (om `userns` tillåts)              | Endast bildbygge (ingen körtid)           | **Ja**                                    |
| **Stöder `docker run` och `docker compose up`**              | Ja                                   | Ja (om `userns` tillåts)              | **Nej**                                   | **Ja**                                    |
| **Fungerar på Windows och macOS utan Linux-VM**              | Nej (kräver WSL2 / VM)               | Nej (kräver Linux-VM)                 | Nej                                       | **Ja (`whpx`, `hvf`, `systrap`)**         |

---

## Exakta krav på värdens Linux-kärna

`gvx` kräver noll förhöjda förmågor (`CapEff: 0000000000000000`) och noll användarnamnrymder. På en Linux-värd förlitar sig `rungv` endast på tre standardprimitiver i kärnan som kan användas utan privilegier:

1. **`ptrace(PTRACE_ATTACH)` på sin egen underordnade tråd en gång under initieringen**: `systrap` startar en lokal stubbhjälptråd vid uppstart, kopplar sig till den för att initiera det delade minneskontexten och kopplar sedan loss. Om värden sätter `kernel.yama.ptrace_scope = 3` (vilket inaktiverar all `ptrace` systemomfattande) eller blockerar `ptrace` i ett yttre seccomp-filter kan inte initieringen av `systrap` slutföras. (Med `yama.ptrace_scope = 1`, standard på Ubuntu och Debian, lyckas `gvx` eftersom spårning från förälder till barn är tillåten.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Används för att fånga gästens systemanrop från containerstubbtrådar. Som beskrivs i [del 3 av denna serie](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03) fungerar `gvx` både när `SECCOMP_FILTER_FLAG_NEW_LISTENER` är tillgänglig och när den returnerar `EBUSY` inuti en kapslad sandlåda.
3. **`mmap(..., PROT_EXEC, ...)`**: Används för att mappa gästens ELF-segment och `systrap`:s delade minnestrampolin.

---

## Exempel från början till slut: Bygga och testa en multi-container-app utan root

Följande skript kör ett komplett `docker build` och ett integrationstest med två containrar (`redis` + applikationscontainer) inuti en användarsession utan privilegier:

```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 avbildningen med overlayfs på ext4lite
docker build -t demo-ping:latest .

# Skapa ett bryggnätverk, starta Redis och verifiera anslutningen mellan containrarna
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

# Rensa arbetscontainrarna och stoppa sandlådan
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Fortsatt läsning i den här serien

1. **[gvx: Köra Linux-containrar, Docker och Kubernetes i en enda process utan privilegier](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Arkitekturöversikt av `gvx`, dess plattformsoberoende exekveringsmotorer (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) och `netstack`.
2. **[Köra Docker, docker build och docker compose utan root eller användarnamnrymder](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (detta inlägg)
3. **[Köra Docker-in-Docker inuti gVisor och kapslade sandlådor med gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Hur `gvx` löser `modprobe`, `iptables-nft`, `overlay2` på `gofer` och kapslad `SECCOMP_FILTER_FLAG_NEW_LISTENER` (`EBUSY`) inuti `gVisor` (`runsc`).
4. **[Snabba isolerade Docker-miljöer för AI-agenters RL-rollouts med gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Skalning av parallella `SWE-bench`- och RL-rollout-miljöer med återställning av `.ext4`-volymer med Copy-on-Write på 100 millisekunder.
