在開發複雜 AI Agent 需要儲存運行狀態時,為實現沙箱環境的快速複用,可通過 E2B SDK 調用 Checkpoint 功能對運行中容器建立快照並執行複製,確保檔案系統與記憶體資料一致並降低環境初始化成本。
準備工作
升級
acs-virtual-node組件至 v2.17.0 及以上版本。
使用限制
當前僅支援ACS通用算力使用 Checkpoint 功能。
Pod狀態為 Running 且 Ready 之後才可提交 Checkpoint。
同一個Pod,只能同時存在一個運行中的 Checkpoint。Checkpoint 達到終態(成功或失敗)後,可再次提交 Checkpoint。
Checkpoint 任務進入 Running 狀態後,無法通過刪除 Checkpoint 資源來中斷任務。
配置 Checkpoint 保留內容
Checkpoint 支援保留以下內容:
檔案系統(filesystem):預設保留。
記憶體(memory):可選保留。
預設情況下,通過 E2B 介面建立的 Checkpoint 將繼承原始 Sandbox 的spec.persistentContents欄位配置,並自動忽略ip保留配置。
此外,可以通過 SandboxSet 批量控制該模板下所有 Sandbox 的保留內容:
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: code-interpreter-fs
namespace: default
spec:
replicas: 2
persistentContents:
- filesystem # 僅保留檔案系統,不保留記憶體
...建立沙箱快照並複製沙箱
E2B SDK方式
建立原始沙箱
以下樣本通過兩個不同的 SandboxSet 模板(分別配置為“保留記憶體”和“不保留記憶體”)示範復原。
部署 SandboxSet,將以下內容儲存為YAML檔案,然後執行
kubectl apply -f <YAML_FILE>命令。通過 E2B SDK建立沙箱,詳細操作請參考建立Agent Sandbox。
# Import the E2B SDK from e2b_code_interpreter import Sandbox # 建立開啟記憶體保留的沙箱 sbx_with_mem = Sandbox.create("code-interpreter-mem") print(f"mem-sandbox id: {sbx_with_mem.sandbox_id}") # 建立僅保留檔案系統的沙箱 sbx_no_mem = Sandbox.create("code-interpreter-no-mem") print(f"fs-sandbox id: {sbx_no_mem.sandbox_id}")初始化狀態:在沙箱中寫入記憶體變數和檔案系統資料。
def init_mem_fs(sbx): sbx.run_code("a = 1") # 寫入記憶體變數 sbx.files.write("/my-file", "hello") # 寫入檔案 # 驗證資料寫入成功 print(sbx.run_code("print(a)")) print(sbx.files.read("/my-file")) init_mem_fs(sbx_with_mem) init_mem_fs(sbx_no_mem)
建立 Checkpoint
將以下<YOUR_SANDBOX_XXX_ID>替換成實際沙箱id,為沙箱建立目前狀態的快照。
sbx_with_mem = Sandbox.connect("<YOUR_SANDBOX_WITH_MEMORY_ID>")
sbx_no_mem = Sandbox.connect("<YOUR_SANDBOX_WITHOUT_MEMORY_ID>")
snapshot_with_mem = sbx_with_mem.create_snapshot()
snapshot_no_mem = sbx_no_mem.create_snapshot(headers={
"x-e2b-kruise-snapshot-keep-running": "true", # Checkpoint 建立後 Sandbox 是否繼續運行。如果是 false,對應 Pod 狀態將會變為 Succeeded。預設為 true。
"x-e2b-kruise-snapshot-ttl": "30m", # 建立的 Checkpoint 存在時間,超期後自動刪除。預設不配置,除非手動刪除,永久存在。
"x-e2b-kruise-snapshot-persistent-contents": "filesystem", # Checkpoint 的保留內容,預設繼承 Sandbox 的保留內容。目前只支援 filesystem 與 memory,filesystem 兩種組合。
"x-e2b-kruise-snapshot-wait-success-seconds": "60", # 建立 Checkpoint 時,服務端等待其完成的逾時時間。預設為 60。
})
print(f"Snapshot ID with memory: {snapshot_with_mem.snapshot_id}")
print(f"Snapshot ID without memory: {snapshot_no_mem.snapshot_id}")
# Checkpoint 建立完成後,可安全刪除原始沙箱
sbx_with_mem.kill()
sbx_no_mem.kill()從 Checkpoint 複製沙箱
複製時,將上一步返回的
Snapshot ID作為 template 參數傳入 create 介面。標準的 timeout、auto_pause 及 CSI 掛載等擴充參數在複製介面中依然有效。# 使用快照 ID 作為模板建立新沙箱 clone_with_mem = Sandbox.create("<YOUR_SNAPSHOT_WITH_MEMORY_ID>") clone_no_mem = Sandbox.create("<YOUR_SNAPSHOT_WITHOUT_MEMORY_ID>")檢查複製後的沙箱資料,驗證復原。
# 驗證開啟記憶體保留的複製 print(clone_with_mem.run_code("print(a)")) print(clone_with_mem.files.read("/my-file")) print(clone_no_mem.run_code("print(a)")) print(clone_no_mem.files.read("/my-file"))預期輸出:
Execution(Results: [], Logs: Logs(stdout: ['1\n'], stderr: []), Error: None) hello Execution(Results: [], Logs: Logs(stdout: [], stderr: []), Error: ExecutionError(name='NameError', value="name 'a' is not defined", traceback="---------------------------------------------------------------------------NameError Traceback (most recent call last)Cell In[1], line 3\n 1 import os; os.environ['E2B_SANDBOX'] = 'true'\n----> 3 print(a)\nNameError: name 'a' is not defined")) hello兩個複製沙箱均能正確恢複檔案系統中的
/my-file。僅
clone_with_mem成功恢複了記憶體變數 a。
Sandbox CR方式
建立沙箱
將以下內容儲存為sandbox.yaml檔案,然後執行kubectl apply -f sandbox.yaml命令。
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
metadata:
name: code-demo
spec:
template:
metadata:
labels:
agent: code-demo
# 使用ACS算力
alibabacloud.com/acs: "true"
spec:
automountServiceAccountToken: false
containers:
- name: my-session
image: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6
env:
- name: GODEBUG
value: multipathtcp=0
resources:
requests:
cpu: 1
memory: 1Gi
ephemeral-storage: "30Gi" #聲明儲存空間為30 GiB
ports:
- containerPort: 49999
name: interpreter建立Checkpoint
通過建立 Checkpoint CR 對目標沙箱建立快照,將以下內容儲存為
sandbox-checkpoint.yaml檔案,然後執行kubectl apply -f sandbox-checkpoint.yaml命令。apiVersion: agents.kruise.io/v1alpha1 kind: Checkpoint metadata: name: checkpoint-code-demo namespace: default spec: # 目標Pod Name podName: code-demo # 建立 Checkpoint 後,是否要求 Pod 保持 Running 狀態。如果配置 false ,Pod狀態變為 Succeeded keepRunning: true # Checkpoint 回收時間,系統在 ttlAfterFinished 逾時後將自動回收 Checkpoint 資源 # 如果不配置,系統預設不會回收,使用者主動刪除 Checkpoint CR 時回收底層 checkpoint 資源 ttlAfterFinished: 30h # 格式,例如 30m, 30h, 30d persistentContents: # 目前僅支援 filesystem以及 memory,filesystem 兩種組合。預設啟用 memory,filesystem - memory - filesystem查看
checkpointId。kubectl get checkpoint checkpoint-code-demo -n default -o jsonpath='{.status.checkpointId}'
複製新沙箱
替換以下
<CHECKPOINT_ID>為上一步的checkpointId,將以下內容儲存為sandbox-clone.yaml檔案,然後執行kubectl apply -f sandbox-clone.yaml命令。apiVersion: agents.kruise.io/v1alpha1 kind: Sandbox metadata: name: code-demo-clone spec: template: metadata: labels: agent: code-demo-clone # 使用ACS算力 alibabacloud.com/acs: "true" annotations: # 必須配置此註解,才允許對 Pod 建立 Checkpoint ops.alibabacloud.com/pause-enabled: "true" # 需替換為正確的 Checkpoint ID checkpoint.alibabacloud.com/restore-from: "<CHECKPOINT_ID>" spec: # 複製沙箱的 spec 需與原始 Pod 的 spec 保持一致 automountServiceAccountToken: false containers: - name: my-session image: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6 env: - name: GODEBUG value: multipathtcp=0 resources: requests: cpu: 1 memory: 1Gi ephemeral-storage: "30Gi" #聲明儲存空間為30 GiB ports: - containerPort: 49999 name: interpreter查看 Sandbox 資源及對應的 Pod 狀態。
kubectl get sandbox/code-demo-clone pod/code-demo-clone -o wide預期輸出:
NAME STATUS AGE SHUTDOWN_TIME PAUSE_TIME MESSAGE sandbox.agents.kruise.io/code-demo-clone Running 71m NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/code-demo-clone 1/1 Running 0 71m 172.16.x.xx virtual-kubelet-cn-hangzhou-h <none> <none>