---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Dockerin, docker buildin ja docker composen suorittaminen ilman juurioikeuksia tai user namespaces-ominaisuuksia
description: Kuinka ajaa turvallisesti täydellinen Docker Engine (dockerd, BuildKit, overlayfs ja docker compose) eristetyssä gVisor-käyttäjätilan hiekkalaatikossa käyttäjänä ilman oikeuksia, kun root, sudo, unshare(CLONE_NEWUSER), mount(2) ja /dev/fuse on estetty.
language: fi
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
---

## Pikaratkaisu: turvallinen käyttäjätason Docker kolmessa vaiheessa

Jos työskentelet lukitussa Linux-kontissa, CI-ajurissa, Kubernetes Podissa tai AI-agentin hiekkalaatikossa, jossa `root`, `sudo`, käyttäjänimiavaruudet (`unshare(CLONE_NEWUSER)`), `mount(2)` ja `/dev/fuse` on estetty, **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) on **turvallinen ja useita suojakerroksia hyödyntävä ratkaisu** täyden `docker:dind`-moottorin ajamiseen käyttäjätilassa.

> **Miksi `gvx` on suunnittelultaan turvallinen (ei oikeuksien eskaloinnin kiertotapa)**: Toisin kuin isännän `/var/run/docker.sock`-socketin liittäminen tai `docker run --privileged` -komento (jotka antavat juuritason vastineen hallinnan isännän ytimeen), `gvx` ei ohita eikä heikennä mitään isännän turvallisuuskäytäntöä (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor tai ei-juuri-UID-rajoitukset). Sen sijaan `rungv` lukitsee oman isäntäprosessinsa (`PR_SET_NO_NEW_PRIVS` + tiukka BPF `seccomp` -sallintalista) ja ajaa `dockerd`:n Googlen muistiturvallisessa **gVisor (`Sentry`)** -käyttäjätilaytimessä. Kaikki vierasjärjestelmän `UID 0` -valtuudet, `overlayfs`-liitokset (`ext4lite`) ja `iptables`-säännöt pysyvät tiukasti eristettyinä hiekkalaatikkoprosessin sisällä.

```sh
# 1. Asenna rungv käyttäjätilaan (SLSA-todennettu esikäännetty julkaisu tai go install)
# Vaihtoehto A: Todenna ja pura SLSA-todennettu esikäännetty binääri GitHub Releasesista
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

# Vaihtoehto B: Tai asenna suoraan lähdekoodista Go:n avulla
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Käynnistä docker:dind gvx:n sisällä yhden tiedoston ext4lite-volyymillä
#    Välittää ~/.gvx/docker.sock-tiedoston (oikeudet 0600) vierasportille 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. Osoita tavallinen Docker CLI ja Docker Compose käyttäjätilan socketiin
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}}'
# Tuloste: overlayfs Alpine Linux ... (containerized)

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

---

## Miksi tavalliset rootless-työkalut epäonnistuvat rajoitetuissa hiekkalaatikoissa

Kun insinööri tai autonominen koodausagentti tarvitsee `docker build`-, `docker run`- tai `docker compose` -komentoja kovennetussa kontissa tai monivuokraajaajossa, tavalliset kiertotavat epäonnistuvat viidessä eri ydinrajoitteessa.

### 1. Isännän Docker-daemonin socket puuttuu

Komennot `docker ps` ja `docker build` epäonnistuvat välittömästi, jos isännän `/var/run/docker.sock`-socketia ei ole liitetty ympäristöö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` estää `sudo`- ja setuid-apuohjelmat

Kovennetut kontit (`securityContext.allowPrivilegeEscalation: false` Kubernetesissa, `--security-opt=no-new-privileges` Dockerissa tai `exebox`- / `bwrap`-hiekkalaatikot) asettavat Linuxin `PR_SET_NO_NEW_PRIVS`-bitin prosessipuuhun. Yritys nostaa oikeuksia `sudo`:n tai setuid-binäärien (`newuidmap`, `newgidmap`, `fusermount3`) kautta epäonnistuu:

```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- ja sysctl-käytännöt estävät `unshare(CLONE_NEWUSER)`:n

"Rootless"-työkalut (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`) nojaavat silti Linuxin **käyttäjänimiavaruuksiin** (`CLONE_NEWUSER`). Ne epäonnistuvat aina, kun:

- Ulomman kontin oletusarvoinen seccomp-profiili estää `unshare(2)`- tai `clone(CLONE_NEWUSER)`-kutsun.
- Ubuntu 24.04+ ottaa käyttöön asetuksen `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Debian- tai RHEL-solmut asettavat arvon `kernel.unprivileged_userns_clone = 0` tai `user.max_user_namespaces = 0`.
- `newuidmap` ei voi kirjoittaa tiedostoon `/proc/self/uid_map`, koska `PR_SET_NO_NEW_PRIVS` on aktiivinen.

Syntyvät virheet näyttävät tältä:

```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)` on estetty ilman isännän `CAP_SYS_ADMIN`-oikeutta

Vaikka ympäristö sallisi `CLONE_NEWUSER`:n, uuden `/proc`-liitoksen luominen sisäkkäiseen mount-nimiavaruuteen epäonnistuu, jos ulompi kontti on peittänyt `/proc`-alipuita (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) tai jättänyt `mount(2)`-kutsun seccomp-suodattimen ulkopuolelle:

```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. Puuttuva `/dev/fuse` rikkoo `fuse-overlayfs`:n

Rootless-konttimoottorit, jotka eivät voi liittää ytimen `overlayfs`-järjestelmää, siirtyvät `fuse-overlayfs`-ratkaisuun. Minimaalisissa konteissa tai Kubernetes-podeissa ilman `/dev/fuse`-laitteen läpivientiä `fuse-overlayfs` epäonnistuu välittömästi:

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

---

## Miten `gvx` ajaa `docker:dind`-moottorin kokonaan käyttäjätilassa

`gvx` ohittaa kaikki viisi ydinrajoitetta, koska se ei pyydä isännän Linux-ydintä luomaan nimiavaruuksia, liittämään tiedostojärjestelmiä tai määrittämään verkkoliittymiä. Sen sijaan `rungv` ajaa sisäisen käyttäjätilan Linux-ytimen (gVisor `Sentry`) ja käyttäjätilan verkkopinon (`netstack`) yhdessä tavallisessa, ei-juurioikeuksisessa prosessissa.

![Käyttäjätason Docker-in-Docker gvx:llä](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Muistissa olevat nimiavaruudet ja liitostaulu (`VFS2`)

Kun `dockerd`, `containerd` ja `runc` suoritetaan `rungv`:n sisällä, `systrap` sieppaa niiden järjestelmäkutsut ja ohjaa ne prosessin sisäiseen `Sentry`-ytimeen isännän ytimen sijaan:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)` ja `mount(2)` toimivat Sentryn muistissa olevan tehtävähierarkian ja `VFS2`-liitostaulun (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2) kanssa, kun isäntäprosessi `rungv` toimii sinun ei-juurioikeuksisella isäntä-UID:lla.

### 2. Natiivi `overlayfs` yhden tiedoston `ext4lite`-volyymeillä

Kun välität `-v gvx-docker:/var/lib/docker` (tai `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`), `gvx` liittää sisäänrakennetun **`ext4lite`**-tiedostojärjestelmän kohtaan `/var/lib/docker`.

Koska `ext4lite` toteuttaa JBD2-journaloidun `ext4`-tiedostojärjestelmän yhden isäntätiedoston (`gvx-docker.ext4`) sisällä ja tukee `trusted.overlay.*`-laajennettuja attribuutteja, merkkityyppisiä whiteout-laitteita (`0:0`), `d_type`-tietoa ja `RENAME_EXCHANGE`-toimintoa, `dockerd` käyttää vierasjärjestelmässä natiivia **`overlayfs`**-tallennusajuria. Monivaiheiset `docker build` -operaatiot jakavat Copy-on-Write-kerroksia ilman `/dev/fuse`-laitetta ja ilman Dockerin `vfs`-varajärjestelmän aiheuttamaa levytilan räjähdysmäistä kasvua.

### 3. Käyttäjätilan `docker0`-silta ja `iptables-legacy`

Kun `docker:dind` käynnistyy `gvx`:n sisällä:

- Vierasjärjestelmän `dockerd` luo `docker0`-sillan (`172.17.0.1/16`), liittää virtuaalisia `veth`-pareja sisäkkäisille konteille ja ohjelmoi `NAT`- (`DOCKER`, `POSTROUTING`) ja `FILTER`-ketjut `addrtype`- ja `conntrack`-vastaavuuksilla `gvx`:n käyttäjätilan `netstack`-pinossa.
- Kun välität `-p unix:~/.gvx/docker.sock:2375`, sidotaan isännän Unix-domain-socket (oikeudet `0600`) ja yhteydet välitetään suoraan hiekkalaatikon sisällä olevan `dockerd`:n porttiin `2375`.

---

## Vertailu olemassa oleviin konttityökaluihin

| Ominaisuus / Rajoite | Tavallinen Docker (`dockerd`) | Rootless Docker / Podman | Kaniko / Buildah (ilman oikeuksia) | `gvx` (`rungv` + `docker:dind`) |
| :----------------------------------------------------------- | :--------------------------- | :------------------------ | :------------------------------ | :---------------------------------- |
| **Vaatii isännän `root`- tai `sudo`-oikeudet**               | Kyllä                        | Ei                        | Ei                              | **Ei**                              |
| **Toimii, kun `PR_SET_NO_NEW_PRIVS=1`**                      | Ei                           | Ei (`newuidmap` epäonnistuu) | Osittain                     | **Kyllä**                           |
| **Toimii, kun `unshare(CLONE_NEWUSER)` on estetty (`EPERM`)** | Ei sovellu                   | Ei                        | Buildah: Ei / Kaniko: Kyllä     | **Kyllä**                           |
| **Toimii ilman `/dev/fuse`-laitetta**                        | Kyllä (käyttää ytimen `overlay2`-ajuria) | Vain hitaan `vfs`-kopioinnin kautta | Kyllä                  | **Kyllä (`overlayfs` ext4lite-levyllä)** |
| **Tukee `docker build` -komentoa (BuildKit)**                | Kyllä                        | Kyllä (jos `userns` on sallittu) | Vain image-rakennus (ei ajoaikaa) | **Kyllä**                        |
| **Tukee `docker run`- ja `docker compose up` -komentoja**    | Kyllä                        | Kyllä (jos `userns` on sallittu) | **Ei**                       | **Kyllä**                           |
| **Toimii Windowsissa ja macOS:ssä ilman Linux-VM:ää**        | Ei (vaatii WSL2:n tai VM:n)  | Ei (vaatii Linux-VM:n)    | Ei                              | **Kyllä (`whpx`, `hvf`, `systrap`)** |

---

## Tarkat isäntäjärjestelmän ydinvaatimukset Linuxissa

`gvx` ei vaadi lainkaan korotettuja valtuuksia (`CapEff: 0000000000000000`) eikä käyttäjänimiavaruuksia. Linux-isännällä `rungv` nojaa vain kolmeen tavalliseen ei-juurioikeuksiseen ydinprimitiiviin:

1. **`ptrace(PTRACE_ATTACH)` omaan lapsisäikeeseensä kerran alustuksen aikana**: `systrap` käynnistää paikallisen stub-apusäikeen käynnistyessään, liittyy siihen alustaakseen jaetun muistin kontekstin ja irrottautuu. Jos isäntä asettaa arvon `kernel.yama.ptrace_scope = 3` (joka kytkee `ptrace`-kutsut pois käytöstä koko järjestelmässä) tai estää `ptrace`-kutsun ulomman seccomp-suodattimen kautta, `systrap`:n alustus ei voi valmistua. (Asetuksella `yama.ptrace_scope = 1`, joka on oletus Ubuntussa ja Debianissa, `gvx` onnistuu, koska vanhemman ja lapsen välinen jäljitys on sallittu.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Käytetään vierasjärjestelmän järjestelmäkutsujen sieppaamiseen kontin stub-säikeistä. Kuten [tämän sarjan osassa 3](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03) käsitellään, `gvx` toimii sekä silloin, kun `SECCOMP_FILTER_FLAG_NEW_LISTENER` on käytettävissä, että silloin, kun se palauttaa arvon `EBUSY` sisäkkäisessä hiekkalaatikossa.
3. **`mmap(..., PROT_EXEC, ...)`**: Käytetään vierasjärjestelmän ELF-segmenttien ja `systrap`:n jaetun muistin trampoliinin kuvaamiseen.

---

## Päästä päähän -esimerkki: monikonttisovelluksen rakentaminen ja testaaminen ilman juurioikeuksia

Seuraava skripti suorittaa täydellisen `docker build` -komennon ja kahden kontin integraatiotestin (`redis` ja sovelluskontti) käyttäjätason istunnossa:

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

# Rakenna image käyttäen overlayfs-tiedostojärjestelmää ext4lite-levyllä
docker build -t demo-ping:latest .

# Luo siltaverkko, käynnistä Redis ja varmista yhteys konttien välillä
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
# Tuloste: PONG

# Siivoa työkuormakontit ja pysäytä hiekkalaatikko
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Lisälukemista tästä sarjasta

1. **[gvx: Linux-konttien, Dockerin ja Kubernetesin ajaminen yhdessä käyttäjätason prosessissa](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: `gvx`:n arkkitehtuurin yleiskatsaus, sen alustakohtaiset suoritusmoottorit (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) ja `netstack`.
2. **[Docker-, docker build- ja docker compose -komentojen ajaminen ilman juurioikeuksia tai käyttäjänimiavaruuksia](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (tämä kirjoitus)
3. **[Docker-in-Docker gVisorin ja sisäkkäisten hiekkalaatikoiden sisällä gvx:n avulla](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Miten `gvx` ratkaisee `modprobe`-, `iptables-nft`-, `overlay2` gofer-ajurilla ja sisäkkäisen `SECCOMP_FILTER_FLAG_NEW_LISTENER`-kutsun (`EBUSY`) `gVisor`- (`runsc`) -ympäristössä.
4. **[Nopeat eristetyt Docker-ympäristöt AI-agenttien RL-ajoihin gvx:llä](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Rinnakkaisten `SWE-bench`- ja RL-ajoympäristöjen skaalaaminen 100 millisekunnin Copy-on-Write `.ext4`-volyymien palautuksilla.
