GoSuda

AI Ajanı RL Rollout'ları için gvx ile Hızlı ve İzole Docker Ortamları

By Lemon Mint views ...

Kodlama Ajanı RL Rollout'larında Güvenlik ve Altyapı Darboğazı

SWE-bench, SWE-ReX, R2E-Gym, SWE-Gym, Verl ve OpenHands gibi kıyaslamalar ve pekiştirmeli öğrenme (RL) çerçeveleri üzerinde yazılım mühendisliği ajanlarını eğitmek ve değerlendirmek, güvenilmeyen, LLM tarafından üretilen kodun binlerce eşzamanlı rollout'unun yürütülmesini gerektirir. Gerçek dünya yazılım mühendisliği görevlerinde bir ajan yalnızca metin dosyalarını düzenlemez: docker build komutunu çalıştırır, docker compose aracılığıyla veritabanları ve mikro hizmetleri ayağa kaldırır, entegrasyon test paketlerini yürütür ve konteyner günlüklerini inceler.

Rollout ölçeğinde (küme başına 128 ila 1.024 eşzamanlı episode), mevcut konteyner altyapısı dört sistemik güvenlik ve performans darboğazıyla karşılaşır:

  1. Host dockerd Kilit Çekişmesi ve Durum Sızıntısı: Yüzlerce eşzamanlı RL işçisini tek bir host /var/run/docker.sock dosyasına yönlendirmek, her ajana host daemon'ına kök eşdeğeri erişim verir, image katmanı çıkarmayı seri hale getirir, docker0 alt ağ tahsislerini tüketir, host iptables üzerinde Another app is currently holding the xtables lock hatalarını tetikler ve episode'lar arasında yetim konteynerleri sızdırır.
  2. Ayrıcalıklı DinD Konteyner Kaçış Riski: Standart docker:dind konteynerlerini çalıştırmak --privileged (CAP_SYS_ADMIN) gerektirir; bu da güvenilmeyen RL rollout'larına ham host blok aygıtlarını, cgroup release agent'larını ve kernel modüllerini açığa çıkarır.
  3. Donanım Sanallaştırma (/dev/kvm) Kısıtlamaları: MicroVM çalışma zamanları (Firecracker, QEMU, Kata Containers) iç çekirdekleri temiz biçimde izole eder, ancak /dev/kvm gerektirirler. İç içe sanallaştırması olmayan standart Kubernetes pod'ları, KVM'nin devre dışı bırakıldığı bare-metal bulut örnekleri ve mevcut gVisor (runsc) sandbox'ları KVM microVM'lerini başlatamaz.
  4. Yavaş Episode Sıfırlama (env.reset()) Gecikmesi: Her RL episode'u için yeni bir docker:dind ortamı başlatmak ve temel image'ları çekmek veya açmak 10 ila 60 saniye sürer; bu da ortam sıfırlamalarını beklerken GPU eğitim işçilerini boşta bırakır.

gvx (rungv CLI ve z.gfire.dev/gvx/pkg/gvx Go SDK), dört darboğazın tamamını çözen güvenli, düşük çabalı, token açısından verimli bir rollout çalışma zamanı sunar. Her rollout ortamı, tek bir ayrıcalıksız, kendi kendini kilitleyen kullanıcı alanı süreci olarak çalışır (Google'ın gVisor Sentry çekirdeği, pkg/hostlockdown ve bellek içi bir netstack ile izole edilmiş) ve tüm /var/lib/docker durumu tek bir copy-on-write .ext4 dosyasının (ext4lite) içinde bulunur.

Ajanlar için Düşük Çabalı, Token Açısından Verimli Yürütme: docker build veya docker compose her bölümde kutudan çıktığı gibi çalıştığında (ya da ajan tarafından rungv aracılığıyla tek bir 3 komutluk turda başlatılabildiğinde), RL rollout'ları service docker start ulimit hatalarını, iptables-nft hatalarını veya runc pivot_root reddetmelerini gidermek için bağlam penceresi token'larını veya adım bütçelerini harcamaz. Trajektorideki her token gerçek yazılım mühendisliği görevini çözmeye yöneltilir.

Güvenilmeyen Ajan Rollout'ları İçin Sıfır Ayrıcalık Güvenliği: Her gvx episode'u, konuk kodu çalıştırmadan önce kendi host işletim sistemi sürecini kilitler (Linux'ta PR_SET_NO_NEW_PRIVS + BPF seccomp, macOS'ta Seatbelt deny default, Windows'ta Restricted Token + Job Object). Bir RL ajanı episode'u içinde docker run --privileged veya yıkıcı rm -rf / komutlarını çalıştırsa bile, bu işlemler kesin olarak o episode'un kullanıcı alanı Sentry çekirdeği ve geçici .ext4 birim dosyası ile sınırlı kalır.


Rollout Mimarisi: Paralel Ayrıcalıksız Örnekler + Reflink Anlık Görüntüleri

gvx içinde her rollout işçisi, kendi gVisor Sentry çekirdeğine, kendi kullanıcı alanı netstack (10.0.2.15/24) yapılandırmasına ve kendi ext4lite blok birimine (ep-N.ext4) sahip, sıradan bir ayrıcalıksız işletim sistemi sürecidir; ayrıca host sayfa önbelleğini salt okunur, içerik adresli bir erofs OCI image önbelleğiyle paylaşır.

gvx ile Paralel Ajan RL Rollout Mimarisi

Tek Dosyalı ext4lite Birimleri RL Sıfırlama Ekonomisini Neden Değiştirir

gvx'in ext4lite dosya sistemi, tüm JBD2 günlüklü bir ext4 birimini (Docker'ın overlayfs katman dizinleri, trusted.overlay.* genişletilmiş öznitelikleri, whiteout aygıt düğümleri ve image metadata dahil) tek bir normal host dosyasının içinde sakladığından, episode yaşam döngüsü yönetimi tek bir dosya işlemine dönüşür:

  1. cp --reflink=always ile 100 Milisaniyelik env.reset():
    • Ön çekilmiş temel image'lar (python:3.11, postgres:16, redis:7 veya göreve özgü SWE-bench temel image'ları) içeren golden-docker.ext4 dosyasını bir kez oluşturursunuz.
    • Her RL episode'unun başında, cp --reflink=always golden-docker.ext4 ep-0042.ext4 komutu (XFS, Btrfs, ZFS veya macOS APFS üzerinde) altlarındaki disk bloklarını kopyalamadan 100 milisaniyenin altında bağımsız bir Copy-on-Write klonu oluşturur.
    • Yalnızca o belirli episode sırasında kirletilen 4 KiB bloklar ek disk alanı tüketir.
  2. Sıfır Artık Kapatma (env.close()):
    • rungv sürecini sonlandırmak (Go'da sb.Close()) ve ep-0042.ext4 dosyasının bağlantısını kaldırmak, episode'un tüm süreçlerini, ağ soketlerini, bağlama noktalarını ve depolamasını yaklaşık 10 milisaniyede geri kazanır. Host çekirdeğinin bağlama tablosunda hiçbir şey bağlanmaz ve host cgroup'larına kaydedilmez.

Adım Adım İş Akışı: Altın .ext4 Anlık Görüntüsü ve Hızlı Episode Sıfırlama

rungv'yi her rollout işçi düğümüne, GitHub Releases üzerinden SLSA ile doğrulanmış önceden derlenmiş ikiliyi indirerek (gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml --deny-self-hosted-runners) veya CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest komutunu çalıştırarak kurabilirsiniz.

Adım 1: Altın docker:dind Birimini Bir Kez Oluşturun

 1mkdir -p /srv/rl-snapshots /srv/rl-episodes
 2
 3# 1. golden-docker.ext4 ile desteklenen bir seed docker:dind örneği başlatın
 4rungv run \
 5  -p unix:/srv/rl-snapshots/seed.sock:2375 \
 6  --mount type=volume,src=/srv/rl-snapshots/golden-docker.ext4,dst=/var/lib/docker \
 7  -e DOCKER_TLS_CERTDIR= \
 8  docker:dind --tls=false &
 9SEED_PID=$!
10
11# 2. golden-docker.ext4 içinde temel image'ları ve build önbelleğini ön doldurun
12export DOCKER_HOST="unix:///srv/rl-snapshots/seed.sock"
13until docker info >/dev/null 2>&1; do sleep 0.5; done
14
15docker pull python:3.11-slim
16docker pull redis:7-alpine
17docker pull postgres:16-alpine
18
19# 3. ext4lite'ın image'ı boşaltıp sıkıştırabilmesi için seed örneğini zarifçe durdurun
20kill -INT $SEED_PID
21wait $SEED_PID

Adım 2: 100 Milisaniyede Paralel RL Episode'ları Başlatın

Her paralel rollout işçisi golden-docker.ext4 dosyasını reflink ile klonlar ve tüm image'ları zaten /var/lib/docker içinde bulunan yalıtılmış bir docker:dind örneği başlatır:

 1EPISODE_ID="ep-0042"
 2SOCK="/srv/rl-episodes/${EPISODE_ID}.sock"
 3
 4# Anında Copy-on-Write klonu (XFS/Btrfs/APFS üzerinde ~100 ms)
 5cp --reflink=always \
 6  /srv/rl-snapshots/golden-docker.ext4 \
 7  "/srv/rl-episodes/${EPISODE_ID}.ext4"
 8
 9# 4 GiB RAM ve 2 CPU ile izole, ayrıcalıksız episode başlatın
10rungv run \
11  -m 4g --cpus 2 \
12  -p "unix:${SOCK}:2375" \
13  --mount "type=volume,src=/srv/rl-episodes/${EPISODE_ID}.ext4,dst=/var/lib/docker" \
14  -e DOCKER_TLS_CERTDIR= \
15  docker:dind --tls=false &
16EP_PID=$!
17
18export DOCKER_HOST="unix://${SOCK}"
19until docker info >/dev/null 2>&1; do sleep 0.2; done
20
21# Rollout işçisinin içinde image'lar ağ çekmesi olmadan hemen kullanılabilir
22docker images
23
24# Ödül hesaplamasından sonra episode'un sonlandırılması (~10 ms)
25kill -KILL $EP_PID
26rm -f "/srv/rl-episodes/${EPISODE_ID}.ext4" "${SOCK}"

z.gfire.dev/gvx/pkg/gvx Go SDK'sını Kullanan Programlı Rollout Havuzu

RL ortam sunucunuz veya değerlendirme harness'iniz Go ile yazılmışsa (ya da gRPC üzerinden bir Go rollout daemon'ını çağırıyorsa), paralel konteyner episode'larını doğrudan z.gfire.dev/gvx/pkg/gvx üzerinden yönetebilirsiniz:

 1package main
 2
 3import (
 4	"bytes"
 5	"context"
 6	"fmt"
 7	"log"
 8	"os"
 9	"os/exec"
10	"path/filepath"
11	"time"
12
13	"z.gfire.dev/gvx/pkg/gvx"
14)
15
16func runEpisode(ctx context.Context, goldenExt4, scratchDir string, epID int) error {
17	epExt4 := filepath.Join(scratchDir, fmt.Sprintf("ep-%04d.ext4", epID))
18	defer os.Remove(epExt4)
19
20	// 1. Altın ext4lite birimini reflink ile klonlayın
21	cpCmd := exec.CommandContext(ctx, "cp", "--reflink=always", goldenExt4, epExt4)
22	if err := cpCmd.Run(); err != nil {
23		return fmt.Errorf("clone golden volume: %w", err)
24	}
25
26	// 2. Bölüm başına duvar saati zaman aşımını uygulayın
27	epCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
28	defer cancel()
29
30	var stdout, stderr bytes.Buffer
31	sb, err := gvx.New(epCtx, gvx.Config{
32		Platform:               gvx.PlatformAuto,
33		NetworkMode:            gvx.NetModeNAT,
34		NetRaw:                 true,
35		AllowPacketSocketWrite: true,
36		AllowSUID:              true,
37		OCIImage:               "docker:dind",
38		Entrypoint:             []string{"sh", "-c"},
39		EntrypointSet:          true,
40		Cmd: []string{
41			"dockerd-entrypoint.sh --tls=false >/var/log/dockerd.log 2>&1 & " +
42				"until docker info >/dev/null 2>&1; do sleep 0.2; done && " +
43				"docker run --rm python:3.11-slim python -c 'print(6 * 7)'",
44		},
45		Envv: []string{"DOCKER_TLS_CERTDIR="},
46		Mounts: []gvx.Mount{
47			{
48				Kind:      gvx.MountVolume,
49				ImagePath: epExt4,
50				GuestPath: "/var/lib/docker",
51			},
52		},
53		Resources: gvx.Resources{
54			MemoryBytes: 4 << 30, // 4 GiB üst sınır
55			CPUMillis:   2000,    // 2.0 CPU
56		},
57		Stdout: &stdout,
58		Stderr: &stderr,
59	})
60	if err != nil {
61		return fmt.Errorf("init episode %d: %w", epID, err)
62	}
63	defer sb.Close()
64
65	exitCode, err := sb.Run(epCtx)
66	if err != nil {
67		return fmt.Errorf("run episode %d: %w", epID, err)
68	}
69
70	log.Printf("episode %d finished: exit=%d stdout=%q", epID, exitCode, stdout.String())
71	return nil
72}
73
74func main() {
75	ctx := context.Background()
76	if err := runEpisode(ctx, "/srv/rl-snapshots/golden-docker.ext4", "/srv/rl-episodes", 1); err != nil {
77		log.Fatal(err)
78	}
79}

Agent RL Sandbox Çalışma Zamanlarının Karşılaştırması

Metrik / GereksinimPaylaşımlı Host dockerdAyrıcalıklı docker:dindFirecracker / KVM MicroVMStandart gVisor (runsc)gvx (rungv / pkg/gvx)
Host root veya --privileged gerekliEvet (docker.sock = root)Evet (--privileged)/dev/kvm + TAP kurulumu gerekirEvet (veya userns + mount)Hayır (tek ayrıcalıksız süreç)
Ayrıcalıksız K8s Pod'ları / mevcut runsc içinde çalışırHayırHayırHayır (/dev/kvm yok)Başarısız (iç içe seccomp'ta EBUSY)Evet (otomatik futex döngüsü yedeği)
İç docker build ve docker compose desteğiHost daemon'ı paylaşırEvetEvetHost DinD ayarı olmadan başarısızEvet (ext4lite üzerinde overlayfs)
Episode başına ağ izolasyonuPaylaşımlı docker0 / xtables kilidiAyrı ad alanıAyrı VM NIC'iAyrı netnsSüreç içi izole netstack
Sıcak episode sıfırlama gecikmesi (env.reset())5 sn ila 30 sn (konteyner/birim temizleme)10 sn ila 60 sn (soğuk daemon)~150 ms (VM anlık görüntüsü)5 sn ila 20 sn~100 ms (cp --reflink=always .ext4)
Platformlar arası yerel geliştirme (Windows / macOS / Linux)Linux VM gerekirLinux VM gerekirYalnızca Linux KVMYalnızca LinuxWindows, macOS ve Linux'ta yerel

Bu Serideki Diğer Okumalar

  1. gvx: Tek Bir Ayrıcalıksız Süreçte Linux Konteynerleri, Docker ve Kubernetes Çalıştırma: Windows (whpx, systrap), macOS (hvf) ve Linux (systrap) genelinde gvx için eksiksiz mimari anlatım.
  2. Root veya Kullanıcı Ad Alanı Olmadan Docker, docker build ve docker compose Çalıştırma: sudo, unshare(CLONE_NEWUSER), mount(2) ve /dev/fuse engellendiğinde hızlı 3 adımlı önyükleme ve sorun giderme kılavuzu.
  3. gvx ile gVisor ve İç İçe Sandbox'lar İçinde Docker-in-Docker Çalıştırma: docker.io ve iç içe runsc'in gVisor (runsc) içinde neden başarısız olduğuna ve gvx'in EBUSY durumunda _RUN_SYSCALL_LOOP futex döngüsüne nasıl geri döndüğüne dair derinlemesine inceleme.
  4. AI Ajanı RL Rollout'ları için gvx ile Hızlı İzole Docker Ortamları (bu yazı)