補寫聲明:這篇的正文寫於 2026 年 9 月 2 日,發佈日期掛回當天。文中的版本號與 CRD 名稱,都以我撰寫那天官方 repo 上看到的內容為準。

agent 跑完一輪,手上多了一段它自己寫的 Python,說要執行看看對不對。你得給它一個地方跑。

這個地方要同時滿足幾件互相打架的事。它要快,因為 agent 一輪只等得起幾秒鐘,不是兩分鐘。它要髒得起,因為 agent 會亂裝套件、會寫一堆暫存檔、會寫出無窮迴圈。它還要能整個丟掉,下一輪從乾淨狀態重來。最後一件最麻煩:它跑的東西是模型當場生出來的,你沒有機會先 review。

最直覺的做法是開一個 Pod。快,幾秒就起來,kubectl delete 就收乾淨。問題出在那個「跑的東西沒人 review 過」——Pod 跟 node 共用同一個 kernel,agent 只要摸到一個 container escape,它就站在你的 node 上了。平常跑自家寫的服務這樣沒事,因為程式碼是你寫的。這裡不是。

換個方向,每個 session 配一台真的 VM。隔離的問題解掉了,換來的是開機時間,還有一個更煩的問題:誰負責回收。agent 的 session 沒有明確的結束訊號,它可能跑一半就斷了,你得自己寫一套東西去追「這台還有沒有人在用」。寫著寫著你會發現,你正在把 Kubernetes 已經做過的事再做一次。

它接手的是「編排」,不是「隔離」

kubernetes-sigs/agent-sandbox 這個專案在 2026 年 8 月 28 日發了 v1.0.0,就在兩天前。這個 repo 是 2025 年 8 月 12 日開的,從第一天到 v1.0.0 花了一年又半個月。它掛在 SIG Apps 底下,授權是 Apache-2.0。

先講它明講自己不做什麼,因為這決定了你該不該用它。README 的 Scope 那段寫得很直:

Scope: Agent Sandbox is a sandbox orchestrator. It delegates low-level container isolation to secure “Sandbox Runtimes” (like gVisor or Kata Containers) by managing Pods configured to use these runtimes (via RuntimeClass).

真正把 agent 關起來的還是 gVisor 或 Kata Containers,這些東西一個都沒變。它做的是上面那一層:把「開一個沙箱、給它一份設定、用完收掉」變成叢集裡可以用 YAML 宣告的資源。

這種切法看起來很無聊,其實是整件事最值錢的一步。隔離技術從來不是瓶頸,gVisor 都幾年了。卡住大家的是隔離之外的所有雜事——冷啟動要幾秒、同一份設定要在十個地方重複貼、沒人在用的沙箱誰去關。這些雜事沒有一件難,但它們加起來就是一套你不想自己維護的系統。

四個 CRD,各自去接一件雜事

核心只有一個 Sandbox,另外三個放在 extensions 模組,兩邊的 API group 不一樣:

CRD 定義位置/模組 API group
Sandbox api/v1beta1/sandbox_types.go agents.x-k8s.io/v1beta1
SandboxTemplateSandboxWarmPoolSandboxClaim extensions 模組 extensions.agents.x-k8s.io/v1beta1

SandboxTemplate 解掉的是重複設定。README 的說法是 “Provides a way to define reusable templates for creating Sandboxes”,白話講就是把「Python 3.12 加這幾個套件、記憶體給 2G」寫成一份範本,之後開沙箱指名字就好。

冷啟動則歸 SandboxWarmPool。它 “Manages a pool of pre-warmed Sandboxes that can be quickly allocated to users, reducing the time it takes to get a new Sandbox up and running”。餐廳先把飯煮好放保溫鍋,客人點餐時只要盛,不用從洗米開始。

SandboxClaim 是這組裡最容易被漏掉的一個,它的角色也最有意思。官方描述是 “Allows users to create Sandboxes from a SandboxWarmPool, abstracting away the details of the underlying Sandbox configuration”。你不是去跟某一個池子要一台特定的沙箱,你是提出一張「我要一個這種規格的沙箱」的單子,剩下的媒合交給 controller。如果你覺得這個形狀很眼熟,對,就是 PVC 對 PV 的那個形狀。K8s 在儲存那邊用同一招用了很多年,這次只是把同一個模式搬到沙箱上。

模式重複出現通常不是巧合。它代表這個問題的本質跟另一個已經被解過的問題是同一個:使用者要的是規格不是實例,中間需要一層媒合。

預熱這件事沒有免費的版本,順便講一下。池子裡溫著的沙箱是真的佔著記憶體跟 CPU 額度在等人來領,你省下的那幾秒冷啟動,是拿閒置資源換的。池子開多大,本質上是在賭「同時會有幾個 agent 要跑東西」。這個取捨 CRD 幫不了你,它只是讓你有地方把數字寫下來。賭小了照樣要等冷啟動,賭大了帳單漂亮不起來。

這裡有個很容易讀錯的地方

repo 的 examples/firecracker-sandbox/sandbox-firecracker.yaml 長這樣:

1
2
3
4
5
6
7
8
9
10
apiVersion: agents.x-k8s.io/v1beta1
kind: Sandbox
metadata:
name: firecracker-example
spec:
podTemplate:
spec:
runtimeClassName: kata-fc
nodeSelector:
kata-firecracker: "true"

kata-fc 這個名字擺在官方範例裡,很自然會被讀成「這個專案新做的沙箱 runtime」。不是。它是 Kata Containers 配 Firecracker 這組 VMM 的 RuntimeClass 名字,agent-sandbox 只是在 podTemplate 裡填了它。上面 Scope 那段就是在防這個誤讀:它委派,它不隔離。

這不是在計較用詞。如果你以為裝了它就有沙箱,你會裝完發現叢集裡根本沒有那個 RuntimeClass,然後在錯的地方找兩個小時。你要先有能跑的 gVisor 或 Kata,這個專案才有東西可以編排。

順帶一提,v1.0.0 是專案的 release tag,跟 API 版本是兩件事。API 目前是 v1beta1,兩個 group 都是。看到 1.0.0 就寫成 v1 的 YAML,套不上去。

還沒解完的部分

v1.0.0 這個數字容易讓人以為東西都定型了。翻一下 repo 就知道沒有。

專案自己有一套 KEP 編號,放在 docs/keps/,跟 k/k 主線的 KEP 不同號。挑幾個看得出現在走到哪:

KEP 進度

694 號「Suspend and Resume API for Beta」狀態是 implemented

暫停跟恢復這條路是通的。

119 號「Agent Sandbox Suspended Condition Status」還是 implementable、階段 alpha

也就是「暫停」這件事的狀態回報還沒定案。

208 號在處理 SandboxClaim 裡 warmpool 跟 template 互斥時要怎麼辦

也還在 implementable。

最值得盯的是 539.2 號,標題叫 “Standardizing Sandbox Runtime Interfaces & sandboxd Hybrid Protocol”,同樣還沒 implemented。它要標準化的正是底下 runtime 的介面。在它落地之前,你的 YAML 裡還是得寫死 runtimeClassName: kata-fc 這種東西,換 runtime 就是換字串。編排這層抽象好了,被編排的那層還沒。

還有一個實務上會咬人的細節:核心跟 extensions 是兩個不同的 API group。你裝了 Sandbox 不等於 SandboxWarmPool 也在,kubectl get sandboxwarmpool 告訴你沒有這個資源型別的時候,先確認 extensions 那組 CRD 有沒有裝上去,不要先去懷疑 controller。repo 裡另外放了一份 docs/api-migration-guide.md,會準備遷移指南通常就代表欄位動過,從舊版升上來之前先讀它。

回到那段 Python

現在 agent 手上那段程式碼要跑,你的選擇長這樣:叢集裡先裝好 gVisor 或 Kata 其中一個,寫一份 SandboxTemplate 描述那個執行環境,開一個 SandboxWarmPool 讓池子裡永遠溫著幾台,agent 每要跑一次就送一張 SandboxClaim。回收交給 controller,你不用寫那套追蹤誰還在用的程式。

值不值得這樣搞,看你一天開幾次沙箱。開個位數,寫個腳本刪 Pod 就夠了,多裝一套 CRD 只是多一個要維護的東西。真正划算的是 agent 已經在替你跑成千上萬次不受控程式碼的那種量級,那時候「誰去關沒人用的沙箱」不再是雜事,是帳單。