Dockerin, docker buildin ja docker composen suorittaminen ilman juurioikeuksia tai user namespaceja

Pikaratkaisu: turvallinen juurikäyttäjätön Docker kolmessa vaiheessa
Jos työskentelet lukitussa Linux-kontissa, CI-runnerissa, Kubernetes Podissa tai tekoälyavustajan koodausagentin hiekkalaatikossa (esimerkiksi pilvipohjaisessa agentin laskentaympäristössä), jossa root, sudo, user namespaces (unshare(CLONE_NEWUSER)), mount(2) ja /dev/fuse on estetty, gvx (rungv) on turvallinen, vähän vaivaa vaativa ja tokenitehokas ratkaisu kokonaisen docker:dind-moottorin ajamiseen käyttäjätilassa.
Vähän vaivaa vaativa, tokenitehokas ratkaisu tekoälyavustajille koodaukseen: Kun autonominen koodausagentti kohtaa virheen
Cannot connect to the Docker daemon, yritys asentaa ja korjatadocker.io-,podman- tairootlesskit-paketteja rajoitetussa kontissa kuluttaa tyypillisesti 15 ja 30 työkalukutsun vuoroa sekä kymmeniä tuhansia kontekstitokeneita. Tämä tapahtuu kierrettäessäsystemctl-,ulimit-,iptables-,unshare- jarunc-virheiden parissa, ja lopulta yritys epäonnistuu tai joudutaan kirjoittamaanDockerfile-tiedostot käsin uudelleen.gvx:llä (rungv) agentti suorittaa yhden deterministisen kolmivaiheisen käynnistyksen yhdellä vuorolla ja ajaa sen jälkeen heti muuttumattomina tavalliset komennotdocker build,docker runjadocker compose.
Miksi
gvxon suunniteltu turvalliseksi (ei yksityisoikeuksien korotuksen kiertotietä): Toisin kuin isäntäkoneen/var/run/docker.sock-tiedoston liittäminen taidocker run --privileged-komennon käyttö (jotka antavat juurikäyttäjän veroisen hallinnan isäntäytimen yli),gvxei ohita eikä heikennä mitään isäntäjärjestelmän turvallisuuskäytäntöä (PR_SET_NO_NEW_PRIVS,seccomp, AppArmor tai ei-juurikäyttäjän UID-rajoitukset). Sen sijaanrungvlukitsee oman isäntäprosessinsa (PR_SET_NO_NEW_PRIVS+ tiukka BPF-seccomp-sallintalista) ja ajaadockerd-palvelun Googlen muistiturvallisessa gVisor (Sentry) -käyttäjätilan ytimessä. 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 (valmiiksi käännetty SLSA-todennettu julkaisu tai go install)
2# Vaihtoehto A: Todenna ja pura SLSA-todennettu valmiiksi käännetty binääri GitHub Releases -sivulta
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-kielellä
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ä yhdellä tiedostolla toteutetulla 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# Tulos: overlayfs Alpine Linux ... (containerized)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d
Miksi tavalliset juurikäyttäjättömät työkalut epäonnistuvat rajoitetuissa hiekkalaatikoissa
Kun insinööri tai autonominen koodausagentti tarvitsee ajaa docker build-, docker run- tai docker compose -komentoja vahvistetussa kontissa tai monivuokraajaajurissa, tavalliset kiertotavat epäonnistuvat viidessä erillisessä ytimen esteessä.
1. Isännän Docker-daemonin socket puuttuu (myös systemctl ja service docker start epäonnistuvat)
docker ps- tai docker build -komento epäonnistuu välittömästi, kun isännän /var/run/docker.sock ei ole liitetty ympäristöön. Yritys käynnistää docker.io komennoilla systemctl tai service docker start epäonnistuu, koska PID 1 ei ole systemd ja /etc/init.d/docker osuu kontin kovaan ulimit -n -rajaan:
1Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
2ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
3System has not been booted with systemd as init system (PID 1). Can't operate.
4Failed to connect to bus: Host is down
5/etc/init.d/docker: 62: ulimit: error setting limit (Operation not permitted)
2. PR_SET_NO_NEW_PRIVS estää sudo-komennon ja setuid-apuohjelmat
Vahvistetut kontit (securityContext.allowPrivilegeEscalation: false Kubernetesissa, --security-opt=no-new-privileges Dockerissa tai exebox- ja bwrap-hiekkalaatikot) asettavat Linuxin PR_SET_NO_NEW_PRIVS-bitin prosessipuuhun. Yritys korottaa oikeuksia sudo-komennolla tai setuid-binääreillä (newuidmap, newgidmap, fusermount3) 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)-kutsun
Työkalut, jotka markkinoidaan "juurikäyttäjättöminä" (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap), luottavat silti Linuxin user namespaces -toimintoon (CLONE_NEWUSER). Ne epäonnistuvat aina, kun:
- Ulomman kontin oletusarvoinen seccomp-profiili estää
unshare(2)- taiclone(CLONE_NEWUSER)-kutsun. - Ubuntu 24.04 ja uudemmat ottavat käyttöön asetuksen
kernel.apparmor_restrict_unprivileged_userns = 1. - Debian- tai RHEL-solmuissa on asetettu
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) ja pivot_root(2) estetään docker build -komennon aikana ilman isännän CAP_SYS_ADMIN-oikeutta
Vaikka ympäristö sallisi CLONE_NEWUSER-toiminnon tai dockerd pakotettaisiin käynnistymään asetuksilla --iptables=false --bridge=none --storage-driver=vfs, docker build epäonnistuu ensimmäisessä RUN-ohjeessa. Syynä on se, että uuden /proc-tiedostojärjestelmän liittäminen tai pivot_root(2)-kutsu sisäkkäisessä mount-nimiavaruudessa on estetty:
1ERROR: failed to solve: process "/bin/sh -c ..." did not complete successfully:
2mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
3OCI 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
4OCI runtime create failed: runc create failed: unable to start container process: error during container init: error jailing process inside rootfs: pivot_root .: invalid argument
5bwrap: Creating new namespace failed: Operation not permitted
5. Puuttuva /dev/fuse rikkoo fuse-overlayfs-toiminnon
Juurikäyttäjättömät konttimoottorit, jotka eivät voi liittää ytimen overlayfs-tiedostojärjestelmää, siirtyvät käyttämään fuse-overlayfs-toimintoa. 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 ydinestettä, koska se ei pyydä isäntäjärjestelmä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) yhden tavallisen, juurikäyttäjättömän prosessin sisällä.

1. Muistissa olevat nimiavaruudet ja liitostaulu (VFS2)
Kun dockerd, containerd ja runc suoritetaan rungv:n sisällä, systrap siepaa niiden järjestelmäkutsut ja ohjaa ne prosessin sisäiseen Sentry-ytimeen isäntäytimen sijaan:
unshare(2),clone(2),pivot_root(2),chroot(2)jamount(2)toimivat Sentry-ytimen muistissa olevan tehtävähierarkian jaVFS2-liitostaulun (procfs,sysfs,tmpfs,devpts,cgroupfsv2) kanssa, kun isäntäprosessirungvtoimii juurikäyttäjättömällä isäntä-UID:llä.
2. Natiivi overlayfs yhden tiedoston ext4lite-volyymeillä
Kun välität parametrin -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 kohteeseen /var/lib/docker.
Koska ext4lite toteuttaa JBD2-päiväkirjoitetun ext4-tiedostojärjestelmän yhden isäntätiedoston (gvx-docker.ext4) sisällä ja tukee trusted.overlay.*-laajennettuja attribuutteja, merkkilaitteita whiteout-merkintöihin (0:0), d_type-tyyppiä ja RENAME_EXCHANGE-toimintoa, dockerd käyttää vierasjärjestelmässä natiivia overlayfs-tallennusajuria. Monivaiheiset docker build -operaatiot jakavat Copy-on-Write-kerrokset ilman /dev/fuse-laitetta ja ilman Dockerin vara-ajurin vfs 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ä:
- Vieras-
dockerdluodocker0-sillan (172.17.0.1/16), liittää virtuaalisetveth-parit sisäkkäisiä kontteja varten ja ohjelmoiNAT- (DOCKER,POSTROUTING) jaFILTER-ketjutaddrtype- jaconntrack-vastaavuuksillagvx:n käyttäjätilannetstack-pinon sisällä. - Parametrin
-p unix:~/.gvx/docker.sock:2375välittäminen sitoo isäntäkoneen Unix-domain-socketin (oikeudet0600) ja välittää yhteydet suoraandockerd-palvelun porttiin2375hiekkalaatikon sisällä.
Vertailu olemassa oleviin konttityökaluihin
| Ominaisuus / rajoite | Tavallinen Docker (dockerd) | Rootless Docker / Podman | Kaniko / Buildah (käyttäjätaso) | gvx (rungv + docker:dind) |
|---|---|---|---|---|
Isännän root tai sudo vaaditaan | Kyllä | Ei | Ei | Ei |
Toimii PR_SET_NO_NEW_PRIVS=1-asetuksella | 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-tiedostojärjestelmällä) |
Tukee docker build -komentoa (BuildKit) | Kyllä | Kyllä (jos userns sallitaan) | Vain imagen rakennus (ei ajoaikaa) | Kyllä |
Tukee docker run- ja docker compose up -komentoja | Kyllä | Kyllä (jos userns sallitaan) | Ei | Kyllä |
| Toimii Windowsissa ja macOS:ssä ilman Linux-virtuaalikonetta | Ei (vaatii WSL2:n / virtuaalikoneen) | Ei (vaatii Linux-virtuaalikoneen) | Ei | Kyllä (whpx, hvf, systrap) |
Tarkat isäntäytimen vaatimukset Linuxissa
gvx ei vaadi lainkaan korotettuja valtuuksia (CapEff: 0000000000000000) eikä yhtään user namespacea. Linux-isännässä rungv nojaa vain kolmeen tavanomaiseen juurikäyttäjättömään ytimen primitiiviin:
ptrace(PTRACE_ATTACH)omaan lapsisäikeeseen kerran alustuksen aikana:systrapkäynnistää paikallisen tukisäikeen (stub helper thread) käynnistyessään, kytkeytyy siihen jaetun muistin kontekstin alustamiseksi ja irrottautuu. Jos isäntä asettaakernel.yama.ptrace_scope = 3(joka poistaa kaikenptrace-käytön järjestelmänlaajuisesti) tai estääptrace-kutsun ulomman seccomp-suodattimen avulla,systrap-alustus ei voi valmistua. (Kunyama.ptrace_scope = 1, joka on oletusarvo 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 konttien tukisäikeistä. Kuten tämän sarjan osassa 3 on käsitelty,gvxtoimii sekä silloin, kunSECCOMP_FILTER_FLAG_NEW_LISTENERon saatavilla, että silloin, kun se palauttaaEBUSY-virheen sisäkkäisessä hiekkalaatikossa.mmap(..., PROT_EXEC, ...): Käytetään vierasjärjestelmän ELF-segmenttien jasystrap-jaetun muistin trampoliinin kuvaamiseen.
Päästä päähän -esimerkki: monikonttisovelluksen rakentaminen ja testaaminen ilman juurikäyttäjää
Seuraava skripti suorittaa täydellisen docker build -komennon ja kahden kontin integraatiotestin (redis + sovelluskontti) juurikäyttäjättömässä käyttäjä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 imagi käyttäen overlayfs-tiedostojärjestelmää ext4lite-tiedostojärjestelmän päällä
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# Tulos: 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ä juurikäyttäjättömässä prosessissa: Arkkitehtuurikatsaus
gvx:stä, sen alustoristiriippumattomista suoritusmoottoreista (whpx,hvf,systrap),VFS2:sta (erofs,ext4lite,hostfsv2) janetstack:sta. - Dockerin, docker buildin ja docker composen ajaminen ilman juurikäyttäjää tai user namespaceja (tämä kirjoitus)
- Docker-in-Dockerin ajaminen gVisorin ja sisäkkäisten hiekkalaatikoiden sisällä gvx:n avulla: Miten
gvxratkaiseemodprobe-,iptables-nft- jaoverlay2-toiminnongofer-palvelussa sekä sisäkkäisenSECCOMP_FILTER_FLAG_NEW_LISTENER-kutsun (EBUSY)gVisor(runsc) -ympäristön sisällä. - Nopeat eristetyt Docker-ympäristöt tekoälyagenttien RL-ajoihin gvx:n avulla: Rinnakkaisten
SWE-bench- ja RL-ajoympäristöjen skaalaaminen 100 millisekunnin copy-on-write.ext4-volyymien nollauksilla.