GoSuda

Kök Yetkisi veya Kullanıcı Ad Alanları (User Namespaces) Olmadan Docker, docker build ve docker compose Çalıştırma

By Lemon Mint views ...

Hızlı Çözüm: Üç Adımda Güvenli Ayrıcalıksız Docker

Kilitlenmiş bir Linux konteyneri, CI çalıştırıcısı, Kubernetes Pod'u veya root, sudo, kullanıcı ad alanları (unshare(CLONE_NEWUSER)), mount(2) ve /dev/fuse erişiminin engellendiği bir yapay zekâ kodlama ajanı sandbox'ı (örneğin bulut ajan hesaplama ortamı) içinde çalışıyorsanız, gvx (rungv), tam bir docker:dind motorunu kullanıcı alanında çalıştırmak için güvenli, düşük çabalı ve belirteç açısından verimli çözümdür.

Yapay Zekâ Kodlama Ajanları İçin Düşük Çabalı, Belirteç Açısından Verimli Çözüm: Otonom bir kodlama ajanı Cannot connect to the Docker daemon hatasıyla karşılaştığında, kısıtlı bir konteyner içinde docker.io, podman veya rootlesskit kurmaya ve düzeltmeye çalışmak tipik olarak systemctl, ulimit, iptables, unshare ve runc hataları arasında 15 ila 30 araç çağrısı turu ve on binlerce bağlam belirteci harcar; ardından ya başarısız olur ya da Dockerfile'ları elle yeniden yazmaya geri döner. gvx (rungv) ile ajan tek bir turda deterministik 3 adımlık bir önyüklemeyi çalıştırır ve standart docker build, docker run ve docker compose komutlarını değiştirmeden hemen çalıştırır.

gvx'in Tasarım Gereği Neden Güvenli Olduğu (Ayrıcalık Yükseltme Geçici Çözümü Değildir): Ana makinenin /var/run/docker.sock dosyasını bağlamaktan veya docker run --privileged çalıştırmaktan farklı olarak (ki bunlar ana makine çekirdeği üzerinde root eşdeğeri kontrol sağlar), gvx herhangi bir ana makine güvenlik politikasını atlamaz ya da zayıflatmaz (PR_SET_NO_NEW_PRIVS, seccomp, AppArmor veya root olmayan UID sınırları). Bunun yerine rungv, kendi ana makine sürecini kilitler (PR_SET_NO_NEW_PRIVS + katı BPF seccomp izin listesi) ve dockerd'yi Google'ın bellek güvenli gVisor (Sentry) kullanıcı alanı çekirdeğinde çalıştırır. Tüm konuk UID 0 yetenekleri, overlayfs bağlamaları (ext4lite) ve iptables kuralları sandbox süreci içinde sıkı biçimde yalıtılmış kalır.

 1# 1. rungv'yi kullanıcı alanına kurun (SLSA ile doğrulanmış hazır sürüm veya go install)
 2# Seçenek A: GitHub Releases üzerindeki SLSA ile doğrulanmış hazır ikili dosyayı doğrulayın ve açın
 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# Seçenek B: Veya Go ile doğrudan kaynak koddan kurun
 9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. Tek dosyalı ext4lite birimiyle gvx içinde docker:dind'i başlatın
12#    ~/.gvx/docker.sock (mod 0600) dosyasını konuk port 2375'e iletir
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. Standart Docker CLI ve Docker Compose'u kullanıcı alanı soketine yönlendirin
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# Çıktı: overlayfs Alpine Linux ... (containerized)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d

Standart Rootless Araçların Kısıtlı Sandbox'larda Neden Başarısız Olduğu

Bir mühendis veya otonom kodlama ajanı, sertleştirilmiş bir konteyner veya çok kiracılı bir çalıştırıcı içinde docker build, docker run veya docker compose çalıştırmak istediğinde, standart geçici çözümler beş ayrı çekirdek engelinde başarısız olur.

1. Ana Makinede Docker Daemon Soketi Yok (systemctl ve service docker start de Başarısız Olur)

Ana makinenin /var/run/docker.sock dosyası ortama bağlanmadığında docker ps veya docker build komutu anında başarısız olur. docker.io servisini systemctl veya service docker start ile başlatmaya çalışmak ise PID 1'in systemd olmaması ve /etc/init.d/docker betiğinin konteynerin sert ulimit -n sınırına takılması nedeniyle başarısız olur:

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, sudo ve Setuid Yardımcılarını Engeller

Sertleştirilmiş konteynerler (Kubernetes'te securityContext.allowPrivilegeEscalation: false, Docker'da --security-opt=no-new-privileges veya exebox / bwrap sandbox'ları), süreç ağacında Linux PR_SET_NO_NEW_PRIVS bitini ayarlar. sudo veya setuid ikili dosyaları (newuidmap, newgidmap, fusermount3) üzerinden yetki yükseltmeye çalışmak başarısız olur:

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 ve Sysctl Politikaları unshare(CLONE_NEWUSER)'ı Engeller

"Rootless" olarak pazarlanan araçlar (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap), yine de Linux kullanıcı ad alanlarına (CLONE_NEWUSER) dayanır. Şu durumlarda başarısız olurlar:

  • Dış konteynerin varsayılan seccomp profili unshare(2) veya clone(CLONE_NEWUSER) çağrısını engellediğinde.
  • Ubuntu 24.04+ kernel.apparmor_restrict_unprivileged_userns = 1 ayarını etkinleştirdiğinde.
  • Debian veya RHEL düğümleri kernel.unprivileged_userns_clone = 0 veya user.max_user_namespaces = 0 ayarladığında.
  • PR_SET_NO_NEW_PRIVS etkin olduğu için newuidmap, /proc/self/uid_map dosyasına yazamadığında.

Ortaya çıkan hatalar şuna benzer:

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. docker build Sırasında Ana Makinede CAP_SYS_ADMIN Olmadan mount(2) ve pivot_root(2) Engellenir

Ortam CLONE_NEWUSER'a izin verse veya dockerd, --iptables=false --bridge=none --storage-driver=vfs ile başlatılmaya zorlansa bile, docker build ilk RUN talimatında başarısız olur; çünkü iç içe bir bağlama ad alanı içinde yeni bir /proc bağlamak veya pivot_root(2) çağırmak engellenir:

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. Eksik /dev/fuse, fuse-overlayfs'i Bozar

Çekirdek overlayfs'i bağlayamayan rootless konteyner motorları fuse-overlayfs'e geri döner. /dev/fuse aygıt geçişi olmayan minimal konteynerlerde veya Kubernetes pod'larında fuse-overlayfs anında başarısız olur:

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

gvx, docker:dind'i Tamamen Kullanıcı Alanında Nasıl Çalıştırır

gvx, Linux ana makine çekirdeğinden ad alanı oluşturmasını, dosya sistemi bağlamasını veya ağ arayüzlerini yapılandırmasını istemediği için beş çekirdek engelinin tamamını aşar. Bunun yerine rungv, tek bir sıradan ayrıcalıksız süreç içinde dahili bir kullanıcı alanı Linux çekirdeği (gVisor Sentry) ve bir kullanıcı alanı ağ yığını (netstack) çalıştırır.

gvx ile Ayrıcalıksız Docker-in-Docker Çalıştırma

1. Bellek İçi Ad Alanları ve Bağlama Tablosu (VFS2)

dockerd, containerd ve runc, rungv içinde çalıştığında systrap sistem çağrılarını yakalar ve bunları ana makine çekirdeği yerine süreç içi Sentry çekirdeğine yönlendirir:

  • unshare(2), clone(2), pivot_root(2), chroot(2) ve mount(2), Sentry'nin bellek içi görev hiyerarşisi ve VFS2 bağlama tablosu (procfs, sysfs, tmpfs, devpts, cgroupfs v2) üzerinde işlem yapar; ana makinedeki rungv süreci ise ayrıcalıksız ana makine UID'nizle çalışır.

2. Tek Dosyalı ext4lite Birimleri Üzerinde Yerel overlayfs

-v gvx-docker:/var/lib/docker (veya --mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker) parametrelerini verdiğinizde, gvx yerleşik ext4lite dosya sistemini /var/lib/docker dizinine bağlar.

ext4lite, tek bir ana makine dosyası (gvx-docker.ext4) içinde JBD2 günlüklü bir ext4 dosya sistemi uygular ve trusted.overlay.* genişletilmiş özniteliklerini, karakter whiteout aygıtlarını (0:0), d_type ile RENAME_EXCHANGE desteğini sağladığı için dockerd, konuk içinde yerel overlayfs depolama sürücüsünü kullanır. Çok aşamalı docker build işlemleri, /dev/fuse gerektirmeden ve Docker'ın vfs yedek sürücüsünün yol açtığı disk alanı patlaması olmadan Copy-on-Write katmanlarını paylaşır.

3. Kullanıcı Alanı docker0 Köprüsü ve iptables-legacy

docker:dind, gvx içinde başladığında:

  • Konuk dockerd, docker0 köprüsünü (172.17.0.1/16) oluşturur, iç içe konteynerler için sanal veth çiftlerini bağlar ve gvx'in kullanıcı alanı netstack yığını içinde addrtype ve conntrack eşleşmeleriyle NAT (DOCKER, POSTROUTING) ve FILTER zincirlerini programlar.
  • -p unix:~/.gvx/docker.sock:2375 parametresi, bir ana makine Unix alan soketi (mod 0600) bağlar ve bağlantıları doğrudan sandbox içindeki dockerd'nin 2375 portuna iletir.

Mevcut Konteyner Araçlarıyla Karşılaştırma

Yetenek / KısıtStandart Docker (dockerd)Rootless Docker / PodmanKaniko / Buildah (Ayrıcalıksız)gvx (rungv + docker:dind)
Ana makinede root veya sudo gerekliEvetHayırHayırHayır
PR_SET_NO_NEW_PRIVS=1 ile çalışırHayırHayır (newuidmap başarısız olur)KısmiEvet
unshare(CLONE_NEWUSER) engellendiğinde çalışır (EPERM)Geçerli değilHayırBuildah: Hayır / Kaniko: EvetEvet
/dev/fuse olmadan çalışırEvet (çekirdek overlay2 kullanır)Yalnızca yavaş vfs kopyasıylaEvetEvet (ext4lite üzerinde overlayfs)
docker build (BuildKit) desteklerEvetEvet (userns izinliyse)Yalnızca imaj oluşturma (çalışma zamanı yok)Evet
docker run ve docker compose up desteklerEvetEvet (userns izinliyse)HayırEvet
Linux VM olmadan Windows ve macOS üzerinde çalışırHayır (WSL2 / VM gerektirir)Hayır (Linux VM gerektirir)HayırEvet (whpx, hvf, systrap)

Linux Üzerinde Tam Ana Makine Çekirdek Gereksinimleri

gvx, sıfır yükseltilmiş yetenek (CapEff: 0000000000000000) ve sıfır kullanıcı ad alanı gerektirir. Bir Linux ana makinesinde rungv, yalnızca üç standart ayrıcalıksız çekirdek ilkesine dayanır:

  1. Başlatma sırasında bir kez, kendi alt iş parçacığında ptrace(PTRACE_ATTACH): systrap, başlangıçta yerel bir stub yardımcı iş parçacığı oluşturur, paylaşımlı bellek bağlamını başlatmak için bu iş parçacığına bağlanır ve ardından ayrılır. Ana makine kernel.yama.ptrace_scope = 3 ayarını yaparsa (ki bu tüm sistem genelinde ptrace'i devre dışı bırakır) veya dış seccomp filtresinde ptrace engellenirse, systrap başlatması tamamlanamaz. (Ubuntu ve Debian'ın varsayılanı olan yama.ptrace_scope = 1 altında, ebeveynden çocuğa izlemeye izin verildiği için gvx başarılı olur.)
  2. seccomp(SECCOMP_SET_MODE_FILTER): Konteyner stub iş parçacıklarından gelen konuk sistem çağrılarını yakalamak için kullanılır. Bu serinin 3. Bölümünde ele alındığı gibi, gvx, SECCOMP_FILTER_FLAG_NEW_LISTENER kullanılabilir olduğunda ve iç içe bir sandbox içinde EBUSY döndürdüğünde de çalışır.
  3. mmap(..., PROT_EXEC, ...): Konuk ELF segmentlerini ve systrap paylaşımlı bellek trampolinini eşlemek için kullanılır.

Uçtan Uca Örnek: Root Olmadan Çoklu Konteyner Uygulamasının Oluşturulması ve Test Edilmesi

Aşağıdaki betik, ayrıcalıksız bir kullanıcı oturumunda tam bir docker build ve iki konteynerli entegrasyon testi (redis + uygulama konteyneri) çalıştırır:

 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# ext4lite üzerinde overlayfs kullanarak imajı oluşturun
20docker build -t demo-ping:latest .
21
22# Bir köprü ağı oluşturun, Redis'i başlatın ve konteynerler arasındaki bağlantıyı doğrulayın
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# Çıktı: PONG
27
28# İş yükü konteynerlerini temizleyin ve sandbox'ı durdurun
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID

Bu Serideki Diğer Okumalar

  1. gvx: Tek Ayrıcalıksız Süreçte Linux Konteynerleri, Docker ve Kubernetes Çalıştırma: gvx'in mimari genel bakışı, çapraz platform yürütme motorları (whpx, hvf, systrap), VFS2 (erofs, ext4lite, hostfs v2) ve netstack.
  2. Docker, docker build ve docker compose Komutlarını Root veya Kullanıcı Ad Alanları Olmadan Çalıştırma (bu yazı)
  3. gvx ile gVisor ve İç İçe Sandbox'larda Docker-in-Docker Çalıştırma: gvx'in modprobe, iptables-nft, gofer üzerinde overlay2 ve gVisor (runsc) içinde iç içe SECCOMP_FILTER_FLAG_NEW_LISTENER (EBUSY) sorunlarını nasıl çözdüğü.
  4. gvx ile AI Ajan RL Rollout'ları İçin Hızlı Yalıtılmış Docker Ortamları: Paralel SWE-bench ve RL rollout ortamlarının 100 milisaniyelik copy-on-write .ext4 birim sıfırlamalarıyla ölçeklendirilmesi.