在开发复杂 AI Agent 需要保存运行状态时,为实现沙箱环境的快速复用,可通过E2B SDK或Checkpoint自定义资源(CR,Custom Resource)方式,对运行中的容器创建快照,确保文件系统的一致性,降低环境初始化成本。
准备工作
升级
acs-virtual-node组件至 v2.17.0 及以上版本。
使用限制
当前仅支持ACS Agent Sandbox算力使用 Checkpoint 功能。
Pod状态为 Running 且 Ready 之后才可提交 Checkpoint。
同一个Pod只能同时存在一个运行中的 Checkpoint。Checkpoint 达到终态(成功或失败)后,可再次提交Checkpoint。
Checkpoint 任务进入 Running 状态后,无法通过删除 Checkpoint 资源来中断任务。
配置 Checkpoint 保留内容
Checkpoint 支持保留以下内容:
文件系统(filesystem):默认保留。
默认情况下,若未通过 Checkpoint 接口(E2B SDK)或 CR 显式指定持久化保留的内容,则以 Sandbox 的spec.persistentContents字段配置为准。
此外,可以通过 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_fs = Sandbox.create("code-interpreter-fs") print(f"fs-sandbox id: {sbx_with_fs.sandbox_id}")初始化状态:在沙箱中写入文件系统数据。
def init_mem_fs(sbx): sbx.files.write("/my-file", "hello") # 写入文件 # 验证数据写入成功 print(sbx.files.read("/my-file")) init_mem_fs(sbx_with_fs)
创建 Checkpoint
将以下<YOUR_SANDBOX_ID>替换成实际沙箱ID,为沙箱创建当前状态的快照。
sbx_with_fs = Sandbox.connect("<YOUR_SANDBOX_ID>")
snapshot_with_fs = sbx_with_fs.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
"x-e2b-kruise-snapshot-wait-success-seconds": "60", # 创建 Checkpoint 时,服务端等待其完成的超时时间。默认为 60
})
print(f"Snapshot ID with file system: {snapshot_with_fs.snapshot_id}")
# Checkpoint 创建完成后,可安全删除原始沙箱
sbx_with_fs.kill()从 Checkpoint 克隆沙箱
将
<YOUR_SNAPSHOT_ID>替换为上一步返回的Snapshot ID,作为 template 参数传入 create 接口进行克隆。标准的timeout、auto_pause及CSI挂载等扩展参数在克隆接口中依然有效。# 使用快照 ID 作为模板创建新沙箱 clone_with_fs = Sandbox.create("<YOUR_SNAPSHOT_ID>") # E2B 客户端会默认配置 300秒的超时清理时间,可按需配置此超时时长检查克隆后的沙箱数据,验证恢复效果。
# 验证开启文件系统保留的克隆沙箱 print(clone_with_fs.files.read("/my-file"))预期输出:克隆沙箱均能正确恢复文件系统中的
/my-file。hello
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"
alibabacloud.com/compute-class: agent-sandbox # Agent Sandbox 实例类型
spec:
automountServiceAccountToken: false
initContainers:
# 以 Sidecar 形式声明 agent-runtime,自动给沙箱容器注入 envd 等运行时组件
- name: runtime
image: registry-cn-zhangjiakou-vpc.ack.aliyuncs.com/acs/agent-runtime:v0.0.5 # 请将 cn-zhangjiakou 替换为实际地域ID
command: [ "sh", "/workspace/entrypoint_inner.sh" ]
volumeMounts:
# 与主容器的共享目录
- name: envd-volume
mountPath: /mnt/envd
env:
- name: ENVD_DIR
value: /mnt/envd
# 这个环境变量使得 Sidecar 共享主容器的资源,不产生额外费用
- name: __IGNORE_RESOURCE__
value: "true"
restartPolicy: Always
containers:
- name: my-session
image: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6
env:
- name: GODEBUG
value: multipathtcp=0
# 指定 runtime 注入的 envd 组件位置
- name: ENVD_DIR
value: /mnt/envd
resources:
requests:
cpu: 1
memory: 1Gi
ephemeral-storage: "30Gi" #声明临时存储空间为30 GiB
ports:
- containerPort: 49999
name: interpreter
volumeMounts:
# 与 runtime 的共享目录
- name: envd-volume
mountPath: /mnt/envd
lifecycle:
postStart:
exec:
command: [ "/bin/bash", "-c", "/mnt/envd/envd-run.sh" ]
terminationGracePeriodSeconds: 1
volumes:
- name: envd-volume
emptyDir: { }创建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 - filesystem查看
checkpointId。kubectl get checkpoint checkpoint-code-demo -n default -o jsonpath='{.status.checkpointId}'
克隆新沙箱
替换以下
<YOUR_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" alibabacloud.com/compute-class: agent-sandbox # Agent Sandbox 实例类型 annotations: # 需替换为正确的 Checkpoint ID checkpoint.alibabacloud.com/restore-from: "<YOUR_CHECKPOINT_ID>" spec: # 克隆沙箱的 spec 需与原始 Pod 的 spec 保持一致 automountServiceAccountToken: false initContainers: # 以 Sidecar 形式声明 agent-runtime,自动给沙箱容器注入 envd 等运行时组件 - name: runtime image: registry-cn-zhangjiakou-vpc.ack.aliyuncs.com/acs/agent-runtime:v0.0.5 # 请将 cn-zhangjiakou 替换为实际地域ID command: [ "sh", "/workspace/entrypoint_inner.sh" ] volumeMounts: # 与主容器的共享目录 - name: envd-volume mountPath: /mnt/envd env: - name: ENVD_DIR value: /mnt/envd # 这个环境变量使得 Sidecar 共享主容器的资源,不产生额外费用 - name: __IGNORE_RESOURCE__ value: "true" restartPolicy: Always containers: - name: my-session image: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6 env: - name: GODEBUG value: multipathtcp=0 # 指定 runtime 注入的 envd 组件位置 - name: ENVD_DIR value: /mnt/envd resources: requests: cpu: 1 memory: 1Gi ephemeral-storage: "30Gi" #声明临时存储空间为30 GiB ports: - containerPort: 49999 name: interpreter volumeMounts: # 与 runtime 的共享目录 - name: envd-volume mountPath: /mnt/envd lifecycle: postStart: exec: command: [ "/bin/bash", "-c", "/mnt/envd/envd-run.sh" ] terminationGracePeriodSeconds: 1 volumes: - name: envd-volume emptyDir: { }查看 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>