Cloudflare 在 9 月 30 日發表的 Containers 改寫裡,初步的爆量測試顯示單一帳號在 5.387 秒內,於六個地點啟動了 100,000 個 Container;median 啟動時間則從 4.049 秒降到 648 毫秒。兩組數字背後是同一個改動:決定「這個 sandbox 要跑什麼」的時間點,從部署當下搬到了請求當下。
Containers 重寫:agent sandbox 的啟動
舊版 Containers 把 sandbox 的環境綁在部署上,agent 卻是每個任務現場開一個 sandbox。這道縫隙撐了多久,文章沒有交代;它交代的是 Cloudflare 怎麼收掉它,開頭一句是「Today, we're making Cloudflare Containers more programmable and optimized for agent workloads.」故事從那兩個被定死的決定開始。
兩個在部署時就定死的決定
文章的診斷是:對 agent sandbox 最重要的兩個決定,「the two decisions that matter most for an agent sandbox were locked in at deploy time: which image it runs and how much compute it gets」。一個是跑哪個 image,一個是分到多少運算資源,兩者在部署當下就已經定案。
對一般的 web 服務,這不構成問題,image 和規格本來就是部署時決定、事後靠 rollout 換版。agent 的用法不同。文章形容 agent 的行為是「Agents don't deploy sandboxes ahead of time. They create sandboxes on demand, for each task, expect them to be ready immediately」。部署時決定的平台,碰上現場決定的用法,縫隙就得靠多開部署來補。
縫隙的樣子,文章寫得很具體:「Each combination of image and instance type was its own Containers application, with its own Durable Object namespace」,緊接著一句是「Every new environment meant another deployment」。用我自己的算術來推,一個平台若要提供 Node 與 Python 兩種 image,各配大小兩種規格,就會是四個 application、四個 namespace。這個四是我舉的例子,不是文章的數字,但組合數相乘的方向,從文章的描述可以直接讀出來。
更新 image 的代價更大。文章說「updating an image meant updating the whole application」,而 rollout 由三個動作組成:「You set grace periods, so running instances could drain, defined percentage splits to move traffic gradually, and called our API to push the new configuration」。設 grace period 讓執行中的 instance 排空,定義百分比切分讓流量逐步移動,再呼叫 API 把新設定推上去。換多快、換哪些 instance,都是平台控制面按你送去的設定在執行,操作的單位是整個 application。每個任務都要自己選環境的 agent 平台,很難配合這種送設定、等平台替換的流程。文章沒有用這句話下結論,這句只是我讀完三個動作後的判斷。
問題因此有兩層:環境選擇的時間點太早,啟動本身要走的路也太長。文章先處理啟動路徑,再回到環境選擇。
每次啟動都要先問一次全球控制平面
舊的啟動路徑,文章只用一句話交代:「Previously, starting a Container required our global control plane to resolve the application configuration, find capacity, and coordinate placement」。解析 application 設定、找容量、協調放置,三件事都發生在 sandbox 真正開機之前。
這三件事的共同點,是都在回答同一組問題:請求該落在哪個 application、用哪份設定、放到哪裡。舊設計把答案寫進部署,所以每次啟動都得回頭問一次全球控制平面。前面引的那句形容 agent 的話是現場建立、期待馬上可用,兩邊的時間尺度差了一截:一邊要先經過控制平面的三個步驟才輪到開機,另一邊要的是任務一開始 sandbox 就已就緒。
舊路徑:全球控制平面先處理
- 解析 application 設定
- 找容量
- 協調放置
- 從頭開機一台 VM
新路徑:從 Durable Object 出發
- 需求從 Durable Object 開始
- 還原一台預備好、尚未分配的 VM
各步驟占多少時間,文章沒有拆分。
新路徑的描述同樣短。第一句是「With the `durable_object` scheduling policy, demand begins at the Durable Object」;第二句是「Instead of booting a new virtual machine from scratch, the new runtime restores a prepared virtual machine that isn't yet assigned」。兩處改動疊在一起:決策點換了位置,VM 的來源也換了。
新路徑的描述裡,需求從 Durable Object 開始,解析設定、找容量、協調放置這三件事不再被列為前置步驟;原本從頭開機的 VM,換成一台已經預備好、尚未分配給任何人的 VM。從措辭看,開機的工作量應該被挪到了請求到來之前,這是我對 prepared 與 isn't yet assigned 兩個詞的讀法,文章沒有展開機制。舊路徑的 median 4.049 秒涵蓋上述全部步驟,新路徑的 648 毫秒涵蓋的是從 Durable Object 出發與還原預備 VM 這兩項,能放在一起比較的,只有這兩個總數。
文章沒有說這兩處各貢獻了多少毫秒。上面的圖把步驟數畫成四對二,但步驟數不等於時間,圖下方那行小字就是在提醒這點。要歸因的話,站得住的說法只有一個:兩處改動都在文章裡,快了 6 倍左右是它們合起來的結果。
量測方式也要交代。文章引用的是 ComputeSDK 的 Burst TTI Benchmark,一次同時啟動 100 個 sandbox。表格的三列是 median 從 4.049 秒到 648 毫秒、標示為 6.2x faster;95th percentile 從 5.839 秒到 910 毫秒,6.4x faster;99th percentile 從 6.717 秒到 1129 毫秒,5.9x faster。下面的圖把三組數字畫在同一條秒數軸上,按鈕可以單看某個百分位。
點選百分位,單看一組前後對照 · 3 個百分位
median 4.049 秒到 0.648 秒,6.2 倍;95th 5.839 秒到 0.910 秒,6.4 倍;99th 6.717 秒到 1.129 秒,5.9 倍。
表中的數字可以再算兩個東西,都是我用文章的數字相減,文章本身沒有寫。一個是尾端的拉開程度:舊設計下 median 到 99th 差 2.668 秒,新設計下只差 0.481 秒。另一個是倍率與絕對值的落差:99th 的 5.9 倍是三者最小,但省下的時間最多,6.717 減 1.129 是 5.588 秒。agent 一次開很多 sandbox 時,要等的是最慢的那幾個,所以尾端收斂的實際意義,很可能比中位數的 6.2 倍更大。文章沒有討論 fan-out 工作流如何受尾端影響,這一步是推測。
這組基準測試也有它回答不了的問題。同時啟動 100 個 sandbox 測的是爆量下的啟動延遲,文章沒有說用的是哪一種 image、多大的規格,也沒有說 sandbox 啟動之後第一個指令要多久才跑完。小節標題是「Faster first commands」,關心的似乎是到第一個指令為止的時間,但表格量的是啟動本身。讀這組數字的合理方式是:它證明新路徑在文章設定的條件下明顯較短,至於你自己的 image 會省多少,要在自己的環境裡重量一次。
另一個數字是規模:文章說在初步的爆量測試(preliminary burst test)中,「a single account started 100,000 Containers in 5.387 seconds across six locations」。單一帳號、六個地點、5.387 秒。它和 100 個 sandbox 的基準是兩件不同的測試,前者測的是爆量的上限,後者測的是啟動延遲的分布,不要把兩者混成一個「十萬個 sandbox 都是 648 毫秒」的說法,文章沒有這樣講。
image 與規格,變成啟動時才傳的參數
啟動路徑縮短,是原來那兩個固定決定被解開的前提。文章對新設計的陳述很簡單:「The image and instance type are now arguments your code passes when the sandbox starts」。讓這件事成立的是新的 durable_object scheduling policy,它拿掉了部署時綁定的限制。Durable Object 內的程式碼可以依任務挑工具鏈與規格,過去要靠另開 application 才能做到的事,現在是一段條件判斷。
文章在診斷之後接的一句是「The new `durable_object` scheduling policy removes that」,that 指的就是前面那個部署時綁定的限制。限制解除之後,原本由 application 數量承擔的環境組合,改由啟動呼叫的兩個參數承擔,application 與 namespace 的數量不必再隨環境種類一起增加。
更新 image 的方式也跟著變。舊流程是前面那三個動作:設 grace period、定百分比、呼叫 API。新流程是程式碼,文章舉了三個例子。一個是用 Durable Object ID 做 hash,把新工具鏈只開給新 sandbox 的 5%。一個是讓進行中的專案固定在目前的 image,原文是「Pin active projects to their current image, so an agent never has its environment swapped out mid-task.」另一個是在下一個 session 或 snapshot 之後這類自然的檢查點,遷移整個工作區。
第一個例子的寫法,有一個細節可以多想一步。雜湊值對同一個輸入是固定的,所以同一個 sandbox 每次啟動,應該都落在同一側,不會今天用新工具鏈、明天又退回舊的。文章沒有明說這一點,它是從 hash 的性質推出來的,實作前仍要自己確認。
這三個例子對照舊流程看最清楚。舊流程裡,「誰先換、換多快」由 application 層級的設定決定,單位是整個 application。新寫法裡,單位縮到單一 sandbox 與單一專案,決定權在你的程式碼。「任務中途不被換環境」在舊模型下要靠 grace period 之類的間接手段,新模型下是一個 if 判斷。下表把前後兩種做法並排,每一列都對應上面引用的文章句子。
| 項目 | 舊設計 | 新設計(durable_object policy) |
|---|---|---|
| image 與規格 | 部署時決定 | 啟動 sandbox 時由程式碼傳入 |
| 多一種環境 | 多一個 application 與 Durable Object namespace | 在 Durable Object 內的程式碼選擇 |
| 更新 image | 更新整個 application,設 grace period、定流量百分比、呼叫 API | 程式碼:canary、固定專案、在檢查點遷移 |
| 啟動流程 | 全球控制平面解析設定、找容量、協調放置 | 需求從 Durable Object 開始,還原預備好的 VM |
| 預設環境 | 自備 Dockerfile、建 image、推到 Cloudflare | cloudflare/debian-trixie |
決定改由程式碼負責,維運責任也跟著搬家。過去 rollout 的行為寫在設定與平台流程裡,現在寫在你自己的 Durable Object 程式裡,會和其他程式碼一起進版本控制、一起被測試、一起出錯。文章強調的是 rollout 變成程式碼片段帶來的彈性,沒有討論測試與回復由誰負責。對小團隊,過去需要多個 application 的場景集中到一處,這個取捨可能划算;大團隊則要先決定誰擁有這段選 image 的邏輯。
表中最後一列的預設環境,是文章新增的系統 image cloudflare/debian-trixie,文章稱它是「a ready-to-use system image for agents that can configure their environment at runtime, containing Debian Trixie Slim and Node.js 24.20.0 LTS」。用它的好處,文章寫成「your agent can start a Linux sandbox without first creating a Dockerfile, building an image, or pushing it to Cloudflare」,Dockerfile、建置、推送三步都省了。這個預設環境把起跑線往前挪了一步:agent 拿到的是 Debian Trixie Slim 加 Node.js 24.20.0 LTS 的基底,其餘的設定留到執行時再做,需要別的工具鏈時,再用啟動參數指定 image。
它還有一個和啟動速度有關的細節:「we can distribute and prepare it across eligible Containers hosts before requests arrive」。請求到來之前,Cloudflare 就已經把這個 image 發到符合條件的主機上。這可能是新路徑能還原預備好 VM 的條件之一,但文章沒有把兩件事連成因果,只能算推測。可以確定的是,自備 image 的使用者要自己承擔建置與推送,系統 image 則由 Cloudflare 預先分發。
工作區可以存檔,也可以分叉
啟動變快、環境變成參數之後,下一個問題是 agent 的工作做到一半怎麼辦。文章的 filesystem snapshot 處理的就是這件事,目前是公開 beta:「Snapshots let an agent begin a task in a prepared environment, save its workspace when the task pauses, and restore those files when the session resumes」。
公開 beta 這個標籤也要一併讀進去。文章描述的是三個動作:在準備好的環境裡開始任務,任務暫停時存下工作區,session 恢復時還原檔案。依賴這項功能的設計,得把 beta 階段的限制與變動當成尚未定案的部分,文章沒有列出那些限制。
注意動詞是 restore those files。文章談的是檔案系統的快照,沒有提到行程狀態或記憶體內容會被保存。所以「存檔」指的是工作區裡的檔案,例如裝好的依賴與下載好的 repository。這個範圍影響你的設計:需要跨 session 保存的東西,要確保它最終落在檔案裡。
更有意思的是文章接著說的「Since snapshots are immutable and reusable, multiple Containers can start independently of the same prepared environment and make their own changes from there」。snapshot 不可變,多個 Container 可以各自從同一個準備好的環境獨立啟動,再各自修改。文章把這個性質用在評估情境:「One snapshot can start many isolated environments from the same baseline, reducing setup time and preventing environment drift from affecting the results」。下面的圖把這個關係畫出來,滑桿調整的是從同一個 snapshot 分出多少個 sandbox,數量只是示意,不是文章的數字。
拖曳滑桿改變分出的 sandbox 數量 · 1 到 6 個(示意)
評估場景值得多說幾句,因為它是文章點名最清楚的用途。評估要比較的是模型或 agent 的表現,環境本身最好是常數。如果每次評估都從頭安裝依賴,安裝當下的網路狀況、套件版本的變動,都會變成混進結果的雜訊,這就是文章所說的 environment drift。把準備好的環境凍成不可變的 snapshot,之後每一次嘗試都從它出發,變數就只剩被測的那一個。
snapshot 與前一節的系統 image 分工不同,值得分開看。系統 image 解決「環境從哪裡來」,內容是 Debian Trixie Slim 與 Node.js 24.20.0 LTS,所有人拿到的都一樣。snapshot 解決「這個任務做到哪裡了」,裡面是 agent 自己裝好的依賴與 clone 下來的 repository。前者由 Cloudflare 預先分發,後者由 agent 在任務中產生。
文章還列了另一種用法:讓同一個工作區跨 session 延續,agent 隔幾天回來可以接著做。裝依賴、clone repository 這類重複的準備工作只做一次,之後從 snapshot 啟動。
Durable Object 站到前台,舊 class 年底退場
前面談的所有新能力,都掛在同一個前提上:每個 Container 仍然附著在一個 Durable Object 上,文章的說法是這個 Durable Object 保留 sandbox 的 identity、state、policy 與 lifecycle。身分與狀態因此有一個固定的主人,agent 保持可用而工作區睡著,這種分離看來就是靠管理這些東西的那一層不住在 Container 裡面才成立。這次改動的關鍵詞是「we're making the Durable Object explicit in the developer experience」,原本藏在 Container class 後面的那一層,現在由你的程式碼直接擁有。
文章列出這種架構對 agent 特別有用的幾點,其中三點寫得很具體。一個是「An agent can remain available while its Linux workspace sleeps.」,agent 本身可以保持可用,Linux 工作區卻睡著。再來是「The Durable Object can program the security boundary around its Container.」,安全邊界由 Durable Object 在 Container 外圍設計。最後一個是「Evals and reinforcement learning systems can supervise each attempt from outside the environment being tested.」,評估與強化學習系統可以從被測環境之外監督每一次嘗試。下面的圖把這三個角色擺在 Durable Object 周圍,點選可以看對應的原文。
點選角色,讀文章對應的原句 · 3 個角色
圖中三個角色都掛在 Durable Object 上,Container 在它之下。選一個角色可以讀到文章的原句。
Base44 的說法是「Cloudflare Containers gives each app an isolated development environment where our AI can execute commands, install dependencies, and bring changes to life in a live preview.」,每個 app 一個隔離環境,指令、依賴與即時預覽都發生在裡面。文章另外把 Cursor Cloud Agents、Devin Outposts、OpenAI Agents API 與 Claude Managed Agents 列為整合,這幾項只有名單,沒有客戶的原話,所以只能說明它們出現在文章裡,說不出各自怎麼使用。
文章引了 Base44 與 Kilo Code 兩家客戶的說法,重點都落在隔離環境與 on demand。Kilo Code 的原話是「Cloudflare Containers lets us create those isolated environments on demand」,正好是前面「現場建立、期待馬上可用」那個需求的另一端說法。
這個架構有一個期限。文章寫「We'll maintain the `Container` class and legacy `Sandbox` class through December 31, 2026」,Container class 與舊的 Sandbox class 只維護到 2026 年 12 月 31 日。同時,所有新能力只在新 API 上:「New capabilities are native-only. The `durable_object` scheduling policy, faster startup, runtime image and instance selection, and filesystem snapshots are available only through `ctx.container`」。本文前面談的每一項,都要經由 ctx.container。
兩個日期放在一起看:新能力在 9 月 30 日發表,舊 class 維護到 12 月 31 日,中間約三個月,這是我用兩個日期算出來的區間,文章沒有稱它為遷移窗口。同一篇文章還把 Sandbox SDK 1.0 定位成工具集合,不再是 base class,繼承式的寫法在文章的新設計裡已經沒有位置。
文章的用詞是「維護」,期限寫到 12 月 31 日。正在用舊 class 的團隊,起點是盤點哪些程式碼繼承了 Container 或 Sandbox 的 base class。用到 scheduling policy、runtime 選 image、filesystem snapshot 任何一項,就得遷到 ctx.container,清單文章已經列好。遷移要改多少程式碼,文章沒有量化,只能自己評估。
Sandbox SDK 的定位也跟著變,文章說「Sandbox SDK 1.0 is a set of utilities, not a base class」。要更高層的抽象,文章指向 @cloudflare/computer,它「combines Dynamic Workers and Containers with a synchronized filesystem」。平台把原本包在 class 裡的決策拆開,交到使用者的 Durable Object 手上,SDK 退到輔助的位置。
評估這套新設計時,有幾個問題在我讀到的範圍內,文章沒有回答:snapshot 的大小與還原需要多久、snapshot 能保存多久、公開 beta 期間有哪些限制,以及新路徑的計費方式與舊路徑有什麼差別。文章給的是方向與一組基準測試,這些空白得靠文件與自己的實測補上。
Decision point:如果你的 agent 平台目前用 Container 或舊 Sandbox class,期限是 2026 年 12 月 31 日,新能力一律只在 ctx.container 上;動手前,先拿自己的 image 量一次啟動時間,別直接套用文章的 648 毫秒。