---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Spouštění Dockeru, docker build a docker compose bez oprávnění root nebo jmenných prostorů uživatelů
description: Jak bezpečně spustit kompletní Docker Engine (dockerd, BuildKit, overlayfs a docker compose) uvnitř izolovaného uživatelskopro­storového sandboxu gVisor jako neprivilegovaný uživatel, když jsou blokovány root, sudo, unshare(CLONE_NEWUSER), mount(2) a /dev/fuse.
language: cs
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
---

## Rychlé řešení: Bezpečný neprivilegovaný Docker ve třech krocích

Pokud pracujete uvnitř zabezpečeného Linuxového kontejneru, CI runneru, Kubernetes Podu nebo sandboxu AI agenta, kde jsou blokovány `root`, `sudo`, user namespaces (`unshare(CLONE_NEWUSER)`), `mount(2)` a `/dev/fuse`, je **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) **bezpečné řešení založené na principu defense-in-depth** pro spuštění plnohodnotného enginu `docker:dind` v uživatelském prostoru.

> **Proč je `gvx` bezpečný již svým návrhem (nejde o obejití eskalace oprávnění)**: Na rozdíl od připojení hostitelského `/var/run/docker.sock` nebo spuštění `docker run --privileged` (které poskytují řízení jádra hostitele ekvivalentní rootovi) `gvx` neobchází ani neoslabuje žádnou bezpečnostní politiku hostitele (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor ani omezení non-root UID). Místo toho `rungv` uzamkne vlastní hostitelský proces (`PR_SET_NO_NEW_PRIVS` + přísný BPF `seccomp` allowlist) a spouští `dockerd` uvnitř jádra v uživatelském prostoru **gVisor (`Sentry`)** od Googlu, které je chráněno proti chybám v práci s pamětí. Všechny `UID 0` schopnosti hosta, připojení `overlayfs` (`ext4lite`) a pravidla `iptables` zůstávají přísně izolovány uvnitř procesu sandboxu.

```sh
# 1. Nainstalujte rungv v uživatelském prostoru (předkompilované vydání s attestací SLSA nebo go install)
# Možnost A: Ověřte a rozbalte předkompilovanou binárku s attestací 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žnost B: Nebo nainstalujte přímo ze zdrojového kódu pomocí Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Spusťte docker:dind uvnitř gvx se svazkem ext4lite tvořeným jediným souborem
#    Přesměrovává ~/.gvx/docker.sock (režim 0600) na port 2375 guesta
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. Nasměrujte standardní Docker CLI a Docker Compose na socket v uživatelském prostoru
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 ... (v kontejneru)

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

---

## Proč standardní nástroje pro běh bez roota selhávají v omezených sandboxech

Když inženýr nebo autonomní kódovací agent potřebuje spustit `docker build`, `docker run` nebo `docker compose` uvnitř zpevněného kontejneru nebo multi-tenant runneru, standardní obcházení selhávají na pěti odlišných jaderných bariérách.

### 1. Žádný socket démona Dockeru na hostiteli

Spuštění `docker ps` nebo `docker build` okamžitě selže, pokud není hostitelský `/var/run/docker.sock` připojen do prostředí:

```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 setuid pomocné programy

Zpevněné kontejnery (`securityContext.allowPrivilegeEscalation: false` v Kubernetes, `--security-opt=no-new-privileges` v Dockeru, nebo sandboxy `exebox` / `bwrap`) nastavují příznak Linuxu `PR_SET_NO_NEW_PRIVS` na stromu procesů. Pokus o eskalaci přes `sudo` nebo setuid binárky (`newuidmap`, `newgidmap`, `fusermount3`) selže:

```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é jako „rootless“ (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`) se stále spoléhají na Linuxové **user namespaces** (`CLONE_NEWUSER`). Selhávají vždy, když:

- Výchozí seccomp profil vnějšího kontejneru blokuje `unshare(2)` nebo `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ zapíná `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Uzly Debianu nebo RHEL nastavují `kernel.unprivileged_userns_clone = 0` nebo `user.max_user_namespaces = 0`.
- `newuidmap` nemůže zapisovat do `/proc/self/uid_map`, protože je aktivní `PR_SET_NO_NEW_PRIVS`.

Výsledné chyby vypadají 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 blokován bez `CAP_SYS_ADMIN` na hostiteli

I když prostředí povoluje `CLONE_NEWUSER`, připojení čerstvého `/proc` uvnitř vnořeného mount namespace selže, pokud vnější kontejner maskuje podstromy `/proc` (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) nebo má v seccomp zakázaný `mount(2)`:

```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. Chybějící `/dev/fuse` rozbíjí `fuse-overlayfs`

Rootless enginy kontejnerů, které nedokážou připojit jaderný `overlayfs`, přecházejí na `fuse-overlayfs`. V minimálních kontejnerech nebo Kubernetes podech bez předání zařízení `/dev/fuse` `fuse-overlayfs` okamžitě selže:

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

---

## Jak `gvx` spouští `docker:dind` zcela v uživatelském prostoru

`gvx` obchází všech pět jaderných bariér, protože nežádá hostitelské Linuxové jádro o vytváření namespaces, připojování souborových systémů ani konfiguraci síťových rozhraní. Místo toho `rungv` spouští interní Linuxové jádro v uživatelském prostoru (gVisor `Sentry`) a síťový zásobník v uživatelském prostoru (`netstack`) uvnitř jediného běžného neprivilegovaného procesu.

![Spuštění neprivilegovaného Docker-in-Docker pomocí gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Namespaces a tabulka připojení v paměti (`VFS2`)

Když `dockerd`, `containerd` a `runc` běží uvnitř `rungv`, `systrap` zachytává jejich systémová volání a směruje je do procesního jádra `Sentry` místo jádra hostitele:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)` a `mount(2)` pracují nad hierarchií úloh Sentry v paměti a tabulkou připojení `VFS2` (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), zatímco hostitelský proces `rungv` běží pod vaším neprivilegovaným UID na hostiteli.

### 2. Nativní `overlayfs` na svazcích `ext4lite` tvořených jediným souborem

Když předáte `-v gvx-docker:/var/lib/docker` (nebo `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`), `gvx` připojí svůj vestavěný souborový systém **`ext4lite`** na `/var/lib/docker`.

Protože `ext4lite` implementuje souborový systém `ext4` s žurnálem JBD2 uvnitř jediného souboru na hostiteli (`gvx-docker.ext4`) s podporou rozšiřujících atributů `trusted.overlay.*`, znakových whiteout zařízení (`0:0`), `d_type` a `RENAME_EXCHANGE`, `dockerd` uvnitř guesta používá svůj nativní storage driver **`overlayfs`**. Vícestupňové operace `docker build` sdílejí vrstvy Copy-on-Write bez `/dev/fuse` a bez explozivního růstu využití disku, který způsobuje záložní driver `vfs` od Dockeru.

### 3. Most `docker0` v uživatelském prostoru a `iptables-legacy`

Když se `docker:dind` spustí uvnitř `gvx`:

- `dockerd` v guestovi vytváří most `docker0` (`172.17.0.1/16`), připojuje virtuální páry `veth` pro vnořené kontejnery a programuje řetězce `NAT` (`DOCKER`, `POSTROUTING`) a `FILTER` s pravidly `addrtype` a `conntrack` uvnitř síťového zásobníku `netstack` v uživatelském prostoru `gvx`.
- Předání `-p unix:~/.gvx/docker.sock:2375` naváže hostitelský Unix doménový socket (režim `0600`) a přesměruje spojení přímo na port `2375` démona `dockerd` uvnitř sandboxu.

---

## Srovnání s existujícími nástroji pro kontejnery

| Schopnost / omezení                                          | Standardní Docker (`dockerd`) | Rootless Docker / Podman  | Kaniko / Buildah (neprivilegovaný) | `gvx` (`rungv` + `docker:dind`)     |
| :----------------------------------------------------------- | :--------------------------- | :------------------------ | :--------------------------------- | :---------------------------------- |
| **Vyžadován `root` nebo `sudo` na hostiteli**                | Ano                          | Ne                        | Ne                                 | **Ne**                              |
| **Funguje s `PR_SET_NO_NEW_PRIVS=1`**                        | Ne                           | Ne (`newuidmap` selže)    | Částečně                           | **Ano**                             |
| **Funguje, když je `unshare(CLONE_NEWUSER)` blokováno (`EPERM`)** | N/A                     | Ne                        | Buildah: Ne / Kaniko: Ano          | **Ano**                             |
| **Funguje bez `/dev/fuse`**                                  | Ano (používá jaderný `overlay2`) | Pouze přes pomalou kopii `vfs` | Ano                          | **Ano (`overlayfs` na `ext4lite`)** |
| **Podporuje `docker build` (BuildKit)**                      | Ano                          | Ano (pokud je `userns` povolen) | Pouze sestavení image (bez runtime) | **Ano**                       |
| **Podporuje `docker run` a `docker compose up`**             | Ano                          | Ano (pokud je `userns` povolen) | **Ne**                        | **Ano**                             |
| **Běží na Windows a macOS bez virtuálního stroje s Linuxem** | Ne (vyžaduje WSL2 / VM)      | Ne (vyžaduje VM s Linuxem) | Ne                                | **Ano (`whpx`, `hvf`, `systrap`)**  |

---

## Přesné požadavky na jádro hostitele Linux

`gvx` nevyžaduje žádné zvýšené schopnosti (`CapEff: 0000000000000000`) ani žádné user namespaces. Na hostiteli Linux se `rungv` spoléhá pouze na tři standardní neprivilegovaná primitiva jádra:

1. **`ptrace(PTRACE_ATTACH)` na vlastním podřízeném vlákně jednou během inicializace**: `systrap` při startu spustí lokální pomocné stub vlákno, připojí se k němu, aby inicializoval sdílený kontext paměti, a odpojí se. Pokud hostitel nastaví `kernel.yama.ptrace_scope = 3` (což zakáže veškeré `ptrace` v celém systému) nebo zablokuje `ptrace` ve vnějším seccomp filtru, inicializace `systrap` nemůže být dokončena. (Při `yama.ptrace_scope = 1`, což je výchozí nastavení na Ubuntu a Debianu, `gvx` uspěje, protože sledování z rodiče na potomka je povoleno.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Používá se k zachycení systémových volání guesta z pomocných stub vláken kontejneru. Jak je popsáno v [části 3 této série](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03), `gvx` funguje jak tehdy, když je k dispozici `SECCOMP_FILTER_FLAG_NEW_LISTENER`, tak tehdy, když vrací `EBUSY` uvnitř vnořeného sandboxu.
3. **`mmap(..., PROT_EXEC, ...)`**: Používá se k mapování segmentů ELF guesta a sdíleného trampolinu `systrap` v paměti.

---

## Příklad od začátku do konce: sestavení a testování aplikace s více kontejnery bez roota

Následující skript spustí kompletní `docker build` a integrační test se dvěma kontejnery (`redis` + kontejner aplikace) uvnitř neprivilegované uživatelské relace:

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

# Sestavte image pomocí overlayfs na ext4lite
docker build -t demo-ping:latest .

# Vytvořte síť typu bridge, spusťte Redis a ověřte spojení mezi kontejnery
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

# Uklidněte pracovní kontejnery a zastavte sandbox
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Další čtení v této sérii

1. **[gvx: Spouštění Linuxových kontejnerů, Dockeru a Kubernetes v jediném neprivilegovaném procesu](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Architektonický přehled `gvx`, jeho multiplatformních výpočetních enginů (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) a `netstack`.
2. **[Spouštění Dockeru, docker build a docker compose bez roota nebo user namespaces](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (tento článek)
3. **[Spouštění Docker-in-Docker uvnitř gVisor a vnořených sandboxů pomocí gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Jak `gvx` řeší `modprobe`, `iptables-nft`, `overlay2` na `gofer` a vnořený `SECCOMP_FILTER_FLAG_NEW_LISTENER` (`EBUSY`) uvnitř `gVisor` (`runsc`).
4. **[Rychlá izolovaná prostředí Dockeru pro RL rollouty AI agentů pomocí gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Škálování paralelních prostředí `SWE-bench` a RL rolloutů se 100milisekundovými resety svazků `.ext4` typu copy-on-write.
