---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Изпълнение на Docker, docker build и docker compose без root права или user namespaces
description: Как сигурно да се стартира пълноценен Docker Engine (dockerd, BuildKit, overlayfs и docker compose) в изолирана gVisor sandbox среда в потребителското пространство като непривилегирован потребител, когато root, sudo, unshare(CLONE_NEWUSER), mount(2) и /dev/fuse са блокирани.
language: bg
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
---

## Бързо решение: Сигурен непривилегирован Docker в три стъпки

Ако работите в заключен Linux контейнер, CI runner, Kubernetes Pod или среда за AI агент, където `root`, `sudo`, user namespaces (`unshare(CLONE_NEWUSER)`), `mount(2)` и `/dev/fuse` са блокирани, **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) е **сигурното решение с дълбока защита (defense-in-depth)** за стартиране на пълен `docker:dind` engine в потребителското пространство.

> **Защо `gvx` е безопасен по дизайн (не е заобиколно решение за ескалация на привилегии)**: За разлика от монтирането на хостовия `/var/run/docker.sock` или изпълнението на `docker run --privileged` (които дават контрол, еквивалентен на root, върху ядрото на хоста), `gvx` не заобикаля и не отслабва никоя политика за сигурност на хоста (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor или ограниченията за non-root UID). Вместо това `rungv` заключва собствения си хост процес (`PR_SET_NO_NEW_PRIVS` + строг BPF `seccomp` allowlist) и стартира `dockerd` в рамките на безопасното по отношение на паметта **gVisor (`Sentry`)** потребителско ядро на Google. Всички възможности на гост `UID 0`, монтиранията `overlayfs` (`ext4lite`) и правилата на `iptables` остават строго изолирани в рамките на sandbox процеса.

```sh
# 1. Инсталиране на rungv в потребителското пространство (предварително компилирано SLSA-атестирано издание или go install)
# Опция A: Проверка и извличане на предварително компилирания SLSA-атестиран двоичен файл от 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

# Опция Б: Или инсталиране директно от изходния код с Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Стартиране на docker:dind в gvx с единичен ext4lite volume във файл
#    Препраща ~/.gvx/docker.sock (режим 0600) към порт 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. Насочване на стандартния Docker CLI и Docker Compose към потребителския 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}}'
# Изход: overlayfs Alpine Linux ... (containerized)

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

---

## Защо стандартните rootless инструменти се провалят в ограничени среди

Когато инженер или автономен агент за писане на код има нужда да изпълни `docker build`, `docker run` или `docker compose` в укрепен контейнер или многопотребителски runner, стандартните заобиколни решения се провалят на пет отделни бариери на ниво ядро.

### 1. Няма сокет на хостовия Docker демон

Изпълнението на `docker ps` или `docker build` се проваля незабавно, когато хостовият `/var/run/docker.sock` не е монтиран в средата:

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

### 2. `PR_SET_NO_NEW_PRIVS` блокира `sudo` и setuid помощните програми

Укрепените контейнери (`securityContext.allowPrivilegeEscalation: false` в Kubernetes, `--security-opt=no-new-privileges` в Docker, или `exebox` / `bwrap` sandboxes) задават битовете Linux `PR_SET_NO_NEW_PRIVS` в дървото на процесите. Опитът за ескалация чрез `sudo` или setuid двоични файлове (`newuidmap`, `newgidmap`, `fusermount3`) се проваля:

```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 и sysctl блокират `unshare(CLONE_NEWUSER)`

Инструментите, рекламирани като "rootless" (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`), все още разчитат на Linux **user namespaces** (`CLONE_NEWUSER`). Те се провалят, когато:

- Профилът по подразбиране на seccomp на външния контейнер блокира `unshare(2)` или `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ активира `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Debian или RHEL възли задават `kernel.unprivileged_userns_clone = 0` или `user.max_user_namespaces = 0`.
- `newuidmap` не може да записва в `/proc/self/uid_map`, защото `PR_SET_NO_NEW_PRIVS` е активен.

Получените грешки изглеждат така:

```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)` е блокиран без `CAP_SYS_ADMIN` на хоста

Дори ако средата позволява `CLONE_NEWUSER`, монтирането на нов `/proc` във вложено mount namespace се проваля, ако външният контейнер е маскирал поддървета на `/proc` (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) или е премахнал `mount(2)` от 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. Липсата на `/dev/fuse` нарушава `fuse-overlayfs`

Rootless контейнерните engines, които не могат да монтират ядрен `overlayfs`, преминават към `fuse-overlayfs`. В минимални контейнери или Kubernetes pods без проброс на устройството `/dev/fuse`, `fuse-overlayfs` се проваля незабавно:

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

---

## Как `gvx` изпълнява `docker:dind` изцяло в потребителското пространство

`gvx` преодолява и петте бариери на ниво ядро, защото не изисква от ядрото на Linux на хоста да създава namespaces, да монтира файлови системи или да конфигурира мрежови интерфейси. Вместо това `rungv` стартира вътрешно потребителско Linux ядро (gVisor `Sentry`) и потребителски мрежов стек (`netstack`) в рамките на един обикновен непривилегирован процес.

![Изпълнение на непривилегирован Docker-in-Docker с gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Namespaces в паметта и таблица на монтиранията (`VFS2`)

Когато `dockerd`, `containerd` и `runc` се изпълняват в `rungv`, `systrap` прихваща техните системни извиквания и ги насочва към вътрешното ядро `Sentry`, а не към ядрото на хоста:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)` и `mount(2)` работят върху йерархията на задачите в паметта на `Sentry` и върху таблицата на монтиранията `VFS2` (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), докато хост процесът `rungv` работи под вашия непривилегирован хост UID.

### 2. Нативен `overlayfs` върху `ext4lite` томове от единичен файл

Когато подадете `-v gvx-docker:/var/lib/docker` (или `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`), `gvx` монтира вградената си файлова система **`ext4lite`** в `/var/lib/docker`.

Тъй като `ext4lite` реализира `ext4` файлова система с JBD2 журналиране в рамките на единствен файл на хоста (`gvx-docker.ext4`), с поддръжка на разширените атрибути `trusted.overlay.*`, символните whiteout устройства (`0:0`), `d_type` и `RENAME_EXCHANGE`, `dockerd` използва собствения си драйвер за съхранение **`overlayfs`** в госта. Многоетапните операции `docker build` споделят Copy-on-Write слоеве без `/dev/fuse` и без експлозията на дисковото пространство, характерна за резервния драйвер `vfs` на Docker.

### 3. Потребителски мост `docker0` и `iptables-legacy`

Когато `docker:dind` стартира в `gvx`:

- `dockerd` на госта създава моста `docker0` (`172.17.0.1/16`), свързва виртуални `veth` двойки за вложените контейнери и програмира веригите `NAT` (`DOCKER`, `POSTROUTING`) и `FILTER` с мачове `addrtype` и `conntrack` в потребителския `netstack` на `gvx`.
- Подаването на `-p unix:~/.gvx/docker.sock:2375` свързва хостов Unix domain socket (режим `0600`) и препраща връзките директно към порт `2375` на `dockerd` в sandbox средата.

---

## Сравнение с съществуващи инструменти за контейнери

| Възможност / Ограничение                                     | Стандартен Docker (`dockerd`) | Rootless Docker / Podman  | Kaniko / Buildah (непривилегирован) | `gvx` (`rungv` + `docker:dind`)     |
| :----------------------------------------------------------- | :---------------------------- | :------------------------ | :---------------------------------- | :---------------------------------- |
| **Изисква хостов `root` или `sudo`**                         | Да                            | Не                        | Не                                  | **Не**                              |
| **Работи с `PR_SET_NO_NEW_PRIVS=1`**                         | Не                            | Не (`newuidmap` се проваля) | Частично                          | **Да**                              |
| **Работи, когато `unshare(CLONE_NEWUSER)` е блокиран (`EPERM`)** | Не се прилага            | Не                        | Buildah: Не / Kaniko: Да            | **Да**                              |
| **Работи без `/dev/fuse`**                                   | Да (използва ядрен `overlay2`) | Само чрез бавен драйвер `vfs` | Да                              | **Да (`overlayfs` върху `ext4lite`)** |
| **Поддържа `docker build` (BuildKit)**                       | Да                            | Да (ако `userns` е разрешен) | Само изграждане на образи (без runtime) | **Да**                         |
| **Поддържа `docker run` и `docker compose up`**              | Да                            | Да (ако `userns` е разрешен) | **Не**                            | **Да**                              |
| **Работи на Windows и macOS без Linux VM**                   | Не (изисква WSL2 / VM)        | Не (изисква Linux VM)     | Не                                  | **Да (`whpx`, `hvf`, `systrap`)**   |

---

## Точни изисквания към ядрото на Linux хост

`gvx` не изисква никакви повишени възможности (`CapEff: 0000000000000000`) и никакви user namespaces. На Linux хост `rungv` разчита единствено на три стандартни непривилегировани примитива на ядрото:

1. **`ptrace(PTRACE_ATTACH)` върху собствената му дъщерна нишка еднократно при инициализация**: `systrap` стартира локална помощна нишка-стъб при старт, прикрепя се към нея, за да инициализира споделения контекст на паметта, и се отделя. Ако хостът зададе `kernel.yama.ptrace_scope = 3` (което деактивира всички `ptrace` в системата) или блокира `ptrace` във външен seccomp филтър, инициализацията на `systrap` не може да завърши. (При `yama.ptrace_scope = 1`, стойността по подразбиране на Ubuntu и Debian, `gvx` работи успешно, тъй като проследяването от родител към дете е разрешено.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Използва се за прихващане на системни извиквания на госта от нишките-стъбове на контейнерите. Както е описано в [Част 3 от тази серия](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03), `gvx` работи както когато `SECCOMP_FILTER_FLAG_NEW_LISTENER` е наличен, така и когато връща `EBUSY` във вложена sandbox среда.
3. **`mmap(..., PROT_EXEC, ...)`**: Използва се за картиране на ELF сегментите на госта и на споделения паметов трамплин на `systrap`.

---

## Пример от край до край: Изграждане и тестване на многоконтейнерно приложение без root

Следният скрипт изпълнява пълен `docker build` и интеграционен тест с два контейнера (`redis` + контейнер с приложението) в непривилегирована потребителска сесия:

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

# Изграждане на образа с overlayfs върху ext4lite
docker build -t demo-ping:latest .

# Създаване на мрежа с мост, стартиране на Redis и проверка на връзката между контейнерите
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
# Изход: PONG

# Почистване на работните контейнери и спиране на sandbox средата
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Допълнително четене в тази серия

1. **[gvx: Изпълнение на Linux контейнери, Docker и Kubernetes в един непривилегирован процес](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Архитектурен преглед на `gvx`, неговите междуплатформени изпълнителни engines (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2) и `netstack`.
2. **[Изпълнение на Docker, docker build и docker compose без root или User Namespaces](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (тази публикация)
3. **[Изпълнение на Docker-in-Docker в gVisor и вложени sandbox среди с gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Как `gvx` решава `modprobe`, `iptables-nft`, `overlay2` върху `gofer` и вложения `SECCOMP_FILTER_FLAG_NEW_LISTENER` (`EBUSY`) в `gVisor` (`runsc`).
4. **[Бързи изолирани Docker среди за RL rollouts на AI агенти с gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Мащабиране на паралелни `SWE-bench` и RL rollout среди с 100-милисекундни копирай-при-запис (copy-on-write) `.ext4` томове с нулиране.
