Dockerin, docker buildin ja docker composen suorittaminen ilman juurioikeuksia tai user namespaces-ominaisuuksia

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 (rungv) on turvallinen ja useita suojakerroksia hyödyntävä ratkaisu täyden docker:dind-moottorin ajamiseen käyttäjätilassa.
Miksi
gvxon suunnittelultaan turvallinen (ei oikeuksien eskaloinnin kiertotapa): Toisin kuin isännän/var/run/docker.sock-socketin liittäminen taidocker run --privileged-komento (jotka antavat juuritason vastineen hallinnan isännän ytimeen),gvxei ohita eikä heikennä mitään isännän turvallisuuskäytäntöä (PR_SET_NO_NEW_PRIVS,seccomp, AppArmor tai ei-juuri-UID-rajoitukset). Sen sijaanrungvlukitsee oman isäntäprosessinsa (PR_SET_NO_NEW_PRIVS+ tiukka BPFseccomp-sallintalista) ja ajaadockerd:n Googlen muistiturvallisessa gVisor (Sentry) -käyttäjätilaytimessä. Kaikki vierasjärjestelmänUID 0-valtuudet,overlayfs-liitokset (ext4lite) jaiptables-säännöt pysyvät tiukasti eristettyinä hiekkalaatikkoprosessin sisällä.
1# 1. Asenna rungv käyttäjätilaan (SLSA-todennettu esikäännetty julkaisu tai go install)
2# Vaihtoehto A: Todenna ja pura SLSA-todennettu esikäännetty binääri GitHub Releasesista
3gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
4 --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
5 --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
6tar -xzf rungv-v0.2.0-linux-amd64.tar.gz && install -m 0755 rungv-v0.2.0-linux-amd64/rungv ~/.local/bin/rungv
7
8# Vaihtoehto B: Tai asenna suoraan lähdekoodista Go:n avulla
9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. Käynnistä docker:dind gvx:n sisällä yhden tiedoston ext4lite-volyymillä
12# Välittää ~/.gvx/docker.sock-tiedoston (oikeudet 0600) vierasportille 2375
13mkdir -p ~/.gvx
14~/.local/bin/rungv run \
15 -p unix:~/.gvx/docker.sock:2375 \
16 -p 127.0.0.1:9000-9019:9000-9019 \
17 -v gvx-docker:/var/lib/docker \
18 -e DOCKER_TLS_CERTDIR= \
19 docker:dind --tls=false &
20
21# 3. Osoita tavallinen Docker CLI ja Docker Compose käyttäjätilan socketiin
22export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
23until docker info >/dev/null 2>&1; do sleep 0.5; done
24docker info --format '{{.Driver}} {{.OperatingSystem}}'
25# Tuloste: overlayfs Alpine Linux ... (containerized)
26
27docker build -t app:test .
28docker run --rm app:test
29docker 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:
1Cannot 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:
1sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
2sudo: 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)- taiclone(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 = 0taiuser.max_user_namespaces = 0. newuidmapei voi kirjoittaa tiedostoon/proc/self/uid_map, koskaPR_SET_NO_NEW_PRIVSon aktiivinen.
Syntyvät virheet näyttävät tältä:
1unshare: unshare failed: Operation not permitted
2cannot clone: Operation not permitted
3Error: cannot re-exec process to join the existing user namespace
4newuidmap: write to uid_map failed: Operation not permitted
5RootlessKit: 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:
1mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
2OCI 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
3bwrap: 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:
1fuse: device not found, try 'modprobe fuse' first
2fusermount3: failed to open /dev/fuse: No such file or directory
3error 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.

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)jamount(2)toimivat Sentryn muistissa olevan tehtävähierarkian jaVFS2-liitostaulun (procfs,sysfs,tmpfs,devpts,cgroupfsv2) kanssa, kun isäntäprosessirungvtoimii 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
dockerdluodocker0-sillan (172.17.0.1/16), liittää virtuaalisiaveth-pareja sisäkkäisille konteille ja ohjelmoiNAT- (DOCKER,POSTROUTING) jaFILTER-ketjutaddrtype- jaconntrack-vastaavuuksillagvx:n käyttäjätilannetstack-pinossa. - Kun välität
-p unix:~/.gvx/docker.sock:2375, sidotaan isännän Unix-domain-socket (oikeudet0600) ja yhteydet välitetään suoraan hiekkalaatikon sisällä olevandockerd:n porttiin2375.
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:
ptrace(PTRACE_ATTACH)omaan lapsisäikeeseensä kerran alustuksen aikana:systrapkäynnistää paikallisen stub-apusäikeen käynnistyessään, liittyy siihen alustaakseen jaetun muistin kontekstin ja irrottautuu. Jos isäntä asettaa arvonkernel.yama.ptrace_scope = 3(joka kytkeeptrace-kutsut pois käytöstä koko järjestelmässä) tai estääptrace-kutsun ulomman seccomp-suodattimen kautta,systrap:n alustus ei voi valmistua. (Asetuksellayama.ptrace_scope = 1, joka on oletus Ubuntussa ja Debianissa,gvxonnistuu, koska vanhemman ja lapsen välinen jäljitys on sallittu.)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 käsitellään,gvxtoimii sekä silloin, kunSECCOMP_FILTER_FLAG_NEW_LISTENERon käytettävissä, että silloin, kun se palauttaa arvonEBUSYsisäkkäisessä hiekkalaatikossa.mmap(..., PROT_EXEC, ...): Käytetään vierasjärjestelmän ELF-segmenttien jasystrap: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:
1mkdir -p ~/.gvx
2rungv run \
3 -p unix:~/.gvx/docker.sock:2375 \
4 -v gvx-docker:/var/lib/docker \
5 -e DOCKER_TLS_CERTDIR= \
6 docker:dind --tls=false &
7DIND_PID=$!
8
9export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
10until docker info >/dev/null 2>&1; do sleep 0.5; done
11
12mkdir -p /tmp/demo-app && cd /tmp/demo-app
13cat <<'EOF' > Dockerfile
14FROM alpine:3.20
15RUN apk add --no-cache redis
16CMD ["redis-cli", "-h", "cache", "ping"]
17EOF
18
19# Rakenna image käyttäen overlayfs-tiedostojärjestelmää ext4lite-levyllä
20docker build -t demo-ping:latest .
21
22# Luo siltaverkko, käynnistä Redis ja varmista yhteys konttien välillä
23docker network create demo-net
24docker run -d --name cache --network demo-net redis:7-alpine
25docker run --rm --network demo-net demo-ping:latest
26# Tuloste: PONG
27
28# Siivoa työkuormakontit ja pysäytä hiekkalaatikko
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID
Lisälukemista tästä sarjasta
- gvx: Linux-konttien, Dockerin ja Kubernetesin ajaminen yhdessä käyttäjätason prosessissa:
gvx:n arkkitehtuurin yleiskatsaus, sen alustakohtaiset suoritusmoottorit (whpx,hvf,systrap),VFS2(erofs,ext4lite,hostfsv2) janetstack. - Docker-, docker build- ja docker compose -komentojen ajaminen ilman juurioikeuksia tai käyttäjänimiavaruuksia (tämä kirjoitus)
- Docker-in-Docker gVisorin ja sisäkkäisten hiekkalaatikoiden sisällä gvx:n avulla: Miten
gvxratkaiseemodprobe-,iptables-nft-,overlay2gofer-ajurilla ja sisäkkäisenSECCOMP_FILTER_FLAG_NEW_LISTENER-kutsun (EBUSY)gVisor- (runsc) -ympäristössä. - Nopeat eristetyt Docker-ympäristöt AI-agenttien RL-ajoihin gvx:llä: Rinnakkaisten
SWE-bench- ja RL-ajoympäristöjen skaalaaminen 100 millisekunnin Copy-on-Write.ext4-volyymien palautuksilla.