---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Spúšťanie Dockeru, docker build a docker compose bez root oprávnení alebo používateľských menných priestorov
description: Ako bezpečne spustiť kompletný Docker Engine (dockerd, BuildKit, overlayfs a docker compose) vo vnútri izolovanej používateľskej sandboxu gVisor ako neprivilegovaný používateľ, keď sú root, sudo, unshare(CLONE_NEWUSER), mount(2) a /dev/fuse zablokované.
language: sk
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
---

## Rýchle riešenie: Bezpečný neprivilegovaný Docker v troch krokoch

Ak pracujete vo vnútri uzamknutého Linuxového kontajnera, CI runnera, Kubernetes Pod alebo sandboxu AI agenta, kde sú blokované `root`, `sudo`, používateľské menné priestory (`unshare(CLONE_NEWUSER)`), `mount(2)` a `/dev/fuse`, je **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) **bezpečným riešením s viacvrstvovou obranou** na spustenie úplného enginu `docker:dind` v používateľskom priestore.

> **Prečo je `gvx` bezpečný už z návrhu (nejde o obídenie eskalácie oprávnení)**: Na rozdiel od pripojenia hostiteľského `/var/run/docker.sock` alebo spustenia `docker run --privileged` (ktoré poskytujú kontrolu ekvivalentnú roote nad jadrom hostiteľa), `gvx` neobchádza ani neoslabuje žiadnu bezpečnostnú politiku hostiteľa (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor alebo obmedzenia neroot UID). Namiesto toho `rungv` uzamkne svoj vlastný hostiteľský proces (`PR_SET_NO_NEW_PRIVS` + prísny BPF `seccomp` allowlist) a spúšťa `dockerd` vo vnútri používateľského jadra **gVisor (`Sentry`)** od Google, ktoré je odolné voči chybám pamäte. Všetky schopnosti `UID 0` v hosťovi, pripojenia `overlayfs` (`ext4lite`) a pravidlá `iptables` zostávajú prísne izolované vo vnútri procesu sandboxu.

```sh
# 1. Nainštalujte rungv do používateľského priestoru (predkompilované vydanie overené cez SLSA alebo go install)
# Možnosť A: Overte a rozbaľte predkompilovaný binárny súbor overený cez SLSA z 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

# Možnosť B: Alebo nainštalujte priamo zo zdrojového kódu pomocou Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Spustite docker:dind vo vnútri gvx s jedným súborovým zväzkom ext4lite
#    Preposiela ~/.gvx/docker.sock (režim 0600) na port 2375 hosťa
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. Nasmerujte štandardné Docker CLI a Docker Compose na socket v používateľskom priestore
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}}'
# Výstup: overlayfs Alpine Linux ... (containerized)

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

---

## Prečo štandardné nástroje bez roota zlyhávajú v obmedzených sandboxoch

Keď inžinier alebo autonómny kódovací agent potrebuje spustiť `docker build`, `docker run` alebo `docker compose` vo vnútri vyztuženého kontajnera alebo viacnájomného runnera, štandardné obchádzky zlyhajú na piatich odlišných bariérach jadra.

### 1. Žiadny socket démona Docker na hostiteľovi

Spustenie `docker ps` alebo `docker build` okamžite zlyhá, ak nie je hostiteľský `/var/run/docker.sock` pripojený do prostredia:

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

### 2. `PR_SET_NO_NEW_PRIVS` blokuje `sudo` a pomocné programy setuid

Vyztužené kontajnery (`securityContext.allowPrivilegeEscalation: false` v Kubernetes, `--security-opt=no-new-privileges` v Dockeri alebo sandboxy `exebox` / `bwrap`) nastavujú bit Linuxu `PR_SET_NO_NEW_PRIVS` v strome procesov. Pokus o eskaláciu cez `sudo` alebo binárne súbory setuid (`newuidmap`, `newgidmap`, `fusermount3`) zlyhá:

```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. Politiky seccomp a sysctl blokujú `unshare(CLONE_NEWUSER)`

Nástroje propagované ako „rootless“ (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`) sa stále spoliehajú na používateľské menné priestory Linuxu (**user namespaces**, `CLONE_NEWUSER`). Zlyhajú vždy, keď:

- Predvolený profil seccomp vonkajšieho kontajnera blokuje `unshare(2)` alebo `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ aktivuje `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Uzly Debianu alebo RHEL nastavujú `kernel.unprivileged_userns_clone = 0` alebo `user.max_user_namespaces = 0`.
- `newuidmap` nemôže zapisovať do `/proc/self/uid_map`, pretože je aktívny `PR_SET_NO_NEW_PRIVS`.

Výsledné chyby vyzerajú takto:

```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)` je blokovaný bez `CAP_SYS_ADMIN` na hostiteľovi

Aj keď prostredie povoľuje `CLONE_NEWUSER`, pripojenie nového `/proc` vo vnútri vnoreného menného priestoru pripojení zlyhá, ak vonkajší kontajner maskuje podstromy `/proc` (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) alebo zakázal `mount(2)` v 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. Chýbajúci `/dev/fuse` narušuje `fuse-overlayfs`

Rootless enginy kontajnerov, ktoré nedokážu pripojiť jadrový `overlayfs`, sa vracajú k `fuse-overlayfs`. V minimalistických kontajneroch alebo v Kubernetes podoch bez priechodu zariadenia `/dev/fuse` `fuse-overlayfs` okamžite zlyhá:

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

---

## Ako `gvx` spúšťa `docker:dind` úplne v používateľskom priestore

`gvx` obchádza všetkých päť bariér jadra, pretože od hostiteľského jadra Linuxu nežiada vytváranie menných priestorov, pripájanie súborových systémov ani konfiguráciu sieťových rozhraní. Namiesto toho `rungv` spúšťa interné používateľské jadro Linuxu (gVisor `Sentry`) a sieťový zásobník v používateľskom priestore (`netstack`) vo vnútri jedného bežného neprivilegovaného procesu.

![Spustenie neprivilegovaného Docker-in-Docker pomocou gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Menné priestory a tabuľka pripojení v pamäti (`VFS2`)

Keď `dockerd`, `containerd` a `runc` bežia vo vnútri `rungv`, `systrap` zachytáva ich systémové volania a smeruje ich do jadra `Sentry` v rámci procesu namiesto hostiteľského jadra:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)` a `mount(2)` pracujú nad pamäťovou hierarchiou úloh a tabuľkou pripojení `VFS2` jadra Sentry (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), zatiaľ čo hostiteľský proces `rungv` beží pod vaším neprivilegovaným UID na hostiteľovi.

### 2. Natívny `overlayfs` na jednosúborových zväzkoch `ext4lite`

Keď odovzdáte `-v gvx-docker:/var/lib/docker` (alebo `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`), `gvx` pripojí svoj vstavaný súborový systém **`ext4lite`** do `/var/lib/docker`.

Keďže `ext4lite` implementuje súborový systém `ext4` s žurnálom JBD2 vo vnútri jedného súboru hostiteľa (`gvx-docker.ext4`) s podporou rozšírených atribútov `trusted.overlay.*`, znakových whiteout zariadení (`0:0`), `d_type` a `RENAME_EXCHANGE`, `dockerd` používa vo vnútri hosťa svoj natívny ovládač úložiska **`overlayfs`**. Viacstupňové operácie `docker build` zdieľajú vrstvy Copy-on-Write bez `/dev/fuse` a bez nárastu miesta na disku, ktorý spôsobuje záložný ovládač `vfs` Dockeru.

### 3. Most `docker0` v používateľskom priestore a `iptables-legacy`

Keď sa `docker:dind` spustí vo vnútri `gvx`:

- `dockerd` hosťa vytvorí most `docker0` (`172.17.0.1/16`), pripojí virtuálne páry `veth` pre vnorené kontajnery a naprogramuje reťazce `NAT` (`DOCKER`, `POSTROUTING`) a `FILTER` so zhodami `addrtype` a `conntrack` vo vnútri sieťového zásobníka `netstack` v používateľskom priestore `gvx`.
- Odovzdanie `-p unix:~/.gvx/docker.sock:2375` viaže hostiteľský socket Unix domény (režim `0600`) a smeruje spojenia priamo na port `2375` služby `dockerd` vo vnútri sandboxu.

---

## Porovnanie s existujúcimi nástrojmi pre kontajnery

| Schopnosť / obmedzenie                                       | Štandardný Docker (`dockerd`) | Rootless Docker / Podman    | Kaniko / Buildah (neprivilegovaný) | `gvx` (`rungv` + `docker:dind`)      |
| :----------------------------------------------------------- | :---------------------------- | :-------------------------- | :--------------------------------- | :----------------------------------- |
| **Vyžaduje `root` alebo `sudo` na hostiteľovi**              | Áno                           | Nie                         | Nie                                | **Nie**                              |
| **Funguje s `PR_SET_NO_NEW_PRIVS=1`**                        | Nie                           | Nie (`newuidmap` zlyhá)     | Čiastočne                          | **Áno**                              |
| **Funguje, keď je `unshare(CLONE_NEWUSER)` blokované (`EPERM`)** | N/A                       | Nie                         | Buildah: Nie / Kaniko: Áno         | **Áno**                              |
| **Funguje bez `/dev/fuse`**                                  | Áno (používa jadrový `overlay2`) | Len cez pomalú kópiu `vfs` | Áno                              | **Áno (`overlayfs` na `ext4lite`)**  |
| **Podporuje `docker build` (BuildKit)**                      | Áno                           | Áno (ak je `userns` povolené) | Iba zostavenie obrazu (bez runtime) | **Áno**                        |
| **Podporuje `docker run` a `docker compose up`**             | Áno                           | Áno (ak je `userns` povolené) | **Nie**                          | **Áno**                              |
| **Beží na Windows a macOS bez virtuálneho stroja Linux**     | Nie (vyžaduje WSL2 / VM)      | Nie (vyžaduje virtuálny stroj Linux) | Nie                       | **Áno (`whpx`, `hvf`, `systrap`)**   |

---

## Presné požiadavky na jadro hostiteľa Linux

`gvx` nevyžaduje žiadne zvýšené schopnosti (`CapEff: 0000000000000000`) ani žiadne používateľské menné priestory. Na hostiteľovi Linux sa `rungv` spolieha iba na tri štandardné neprivilegované primitíva jadra:

1. **`ptrace(PTRACE_ATTACH)` na vlastnom podriadenom vlákne jedenkrát počas inicializácie**: `systrap` pri spustení vytvorí lokálne pomocné stub vlákno, pripojí sa k nemu, aby inicializoval zdieľaný kontext pamäte, a potom sa odpojí. Ak hostiteľ nastaví `kernel.yama.ptrace_scope = 3` (čo zakazuje všetky `ptrace` v celom systéme) alebo blokuje `ptrace` vo vonkajšom filtri seccomp, inicializácia `systrap` sa nemôže dokončiť. (Pri `yama.ptrace_scope = 1`, čo je predvolené nastavenie na Ubuntu a Debian, `gvx` uspeje, pretože sledovanie z rodiča na potomka je povolené.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Používa sa na zachytávanie systémových volaní hosťa z pomocných stub vlákien kontajnera. Ako je popísané v [3. časti tejto série](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03), `gvx` funguje tak, keď je k dispozícii `SECCOMP_FILTER_FLAG_NEW_LISTENER`, ako aj vtedy, keď vracia `EBUSY` vo vnorenom sandboxe.
3. **`mmap(..., PROT_EXEC, ...)`**: Používa sa na mapovanie segmentov ELF hosťa a trampolíny `systrap` v zdieľanej pamäti.

---

## Príklad od začiatku do konca: zostavenie a testovanie viackontajnerovej aplikácie bez roota

Nasledujúci skript spúšťa kompletné `docker build` a integračný test s dvoma kontajnermi (`redis` + kontajner aplikácie) v neprivilegovanej používateľskej relácii:

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

# Zostavenie obrazu pomocou overlayfs na ext4lite
docker build -t demo-ping:latest .

# Vytvorenie mostovej siete, spustenie Redis a overenie konektivity medzi kontajnermi
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
# Výstup: PONG

# Vyčistenie pracovných kontajnerov a zastavenie sandboxu
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Ďalšie čítanie v tejto sérii

1. **[gvx: Spúšťanie Linuxových kontajnerov, Dockeru a Kubernetes v jednom neprivilegovanom procese](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Architektonický prehľad `gvx`, jeho multiplatformných vykonávacích enginov (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) a `netstack`.
2. **[Spúšťanie Dockeru, docker build a docker compose bez roota alebo používateľských menných priestorov](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (tento príspevok)
3. **[Spúšťanie Docker-in-Docker vo vnútri gVisor a vnorených sandboxov pomocou gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Ako `gvx` rieši `modprobe`, `iptables-nft`, `overlay2` na `gofer` a vnorený `SECCOMP_FILTER_FLAG_NEW_LISTENER` (`EBUSY`) vo vnútri `gVisor` (`runsc`).
4. **[Rýchle izolované prostredia Dockeru pre RL rollouty AI agentov pomocou gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Škálovanie paralelných prostredí `SWE-bench` a RL rolloutov pomocou resetov zväzkov `.ext4` s copy-on-write v trvaní 100 milisekúnd.
