全部产品
Search
文档中心

容器计算服务 ACS:使用Checkpoint功能克隆Agent Sandbox

更新时间:Mar 31, 2026

在开发复杂 AI Agent 需要保存运行状态时,为实现沙箱环境的快速复用,可通过 E2B SDK 调用 Checkpoint 功能对运行中容器创建快照并执行克隆,确保文件系统与内存数据一致并降低环境初始化成本。

准备工作

  1. 升级acs-virtual-node组件至 v2.17.0 及以上版本。

  2. 安装相关组件

使用限制

  1. 当前仅支持ACS通用算力使用 Checkpoint 功能。

  2. Pod状态为 Running 且 Ready 之后才可提交 Checkpoint。

  3. 同一个Pod,只能同时存在一个运行中的 Checkpoint。Checkpoint 达到终态(成功或失败)后,可再次提交 Checkpoint。

  4. Checkpoint 任务进入 Running 状态后,无法通过删除 Checkpoint 资源来中断任务。

配置 Checkpoint 保留内容

Checkpoint 支持保留以下内容:

  • 文件系统(filesystem):默认保留。

  • 内存(memory):可选保留。

默认情况下,通过 E2B 接口创建的 Checkpoint 将继承原始 Sandbox 的spec.persistentContents字段配置,并自动忽略ip保留配置。

示例 1:继承文件系统与内存保留配置

# 原始 Sandbox 配置
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
spec:
  persistentContents:
    - filesystem
    - memory
  ...
---
# 最终生成的 Checkpoint 配置
apiVersion: agents.kruise.io/v1alpha1
kind: Checkpoint
spec:
  persistentContents: # 自动继承原始配置
    - filesystem
    - memory
  ...

示例 2:自动过滤 IP 保留配置

# 原始 Sandbox 配置
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
spec:
  persistentContents:
    - ip
    - filesystem
  ...
---
# 最终生成的 Checkpoint 配置
apiVersion: agents.kruise.io/v1alpha1
kind: Checkpoint
spec:
  persistentContents: # 自动去除 ip,仅保留 filesystem
    - filesystem
  ...

此外,可以通过 SandboxSet 批量控制该模板下所有 Sandbox 的保留内容:

apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
  name: code-interpreter-fs
  namespace: default
spec:
  replicas: 2
  persistentContents:
    - filesystem # 仅保留文件系统,不保留内存
  ...

创建沙箱快照并克隆沙箱

E2B SDK方式

创建原始沙箱

以下示例通过两个不同的 SandboxSet 模板(分别配置为“保留内存”和“不保留内存”)演示恢复效果。

  1. 部署 SandboxSet,将以下内容保存为YAML文件,然后执行kubectl apply -f <YAML_FILE>命令。

    code-interpreter-mem.yaml

    apiVersion: agents.kruise.io/v1alpha1
    kind: SandboxSet
    metadata:
      name: code-interpreter-mem
      namespace: default
    spec:
      # 预热池的大小,建议比预估的请求突发量略大
      replicas: 2
      persistentContents: # 内存保留
        - memory
        - filesystem
      template:
        metadata:
          labels:
            # 可选,用于在 ACK 集群中将沙箱 Pod 调度到 ACS
            alibabacloud.com/acs: "true"
        spec:
          initContainers:
            # 以 sidecar 容器形式声明 agent-runtime,实现向沙箱容器自动注入 envd 等运行时组件
            - name: runtime
              image: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/agent-runtime:v0.0.2
              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: sandbox
            # 官方维护的 e2b code-interpreter 镜像,支持全地域、vpc 拉取
            image: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/code-interpreter:v1.6
            imagePullPolicy: IfNotPresent
            # 推荐设置资源需求,否则在 ACS 环境下会被设置成超小规格影响运行
            resources:
              limits:
                cpu: 1
                memory: 1Gi
              requests:
                cpu: 1
                memory: 1Gi
            startupProbe:
              failureThreshold: 10
              httpGet:
                path: /health
                port: 49999
              initialDelaySeconds: 1
              periodSeconds: 2
              timeoutSeconds: 1
            env:
              # 指定 runtime 注入的 envd 组件位置
              - name: ENVD_DIR
                value: /mnt/envd
            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: { }

    code-interpreter-no-mem.yaml

    apiVersion: agents.kruise.io/v1alpha1
    kind: SandboxSet
    metadata:
      name: code-interpreter-no-mem
      namespace: default
    spec:
      # 预热池的大小,建议比预估的请求突发量略大
      replicas: 2
      persistentContents: # 内存不保留
        - filesystem
      template:
        metadata:
          labels:
            # 可选,用于在 ACK 集群中将沙箱 Pod 调度到 ACS
            alibabacloud.com/acs: "true"
        spec:
          initContainers:
            # 以 native-sidecar 形式声明 agent-runtime,自动给沙箱容器注入 envd 等运行时组件
            - name: runtime
              image: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/agent-runtime:v0.0.2
              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: sandbox
            # 官方维护的 e2b code-interpreter 镜像,支持全地域、vpc 拉取
            image: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/code-interpreter:v1.6
            imagePullPolicy: IfNotPresent
            # 推荐设置资源需求,否则在 ACS 环境下会被设置成超小规格影响运行
            resources:
              limits:
                cpu: 1
                memory: 1Gi
              requests:
                cpu: 1
                memory: 1Gi
            startupProbe:
              failureThreshold: 10
              httpGet:
                path: /health
                port: 49999
              initialDelaySeconds: 1
              periodSeconds: 2
              timeoutSeconds: 1
            env:
              # 指定 runtime 注入的 envd 组件位置
              - name: ENVD_DIR
                value: /mnt/envd
            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: { }
  2. 通过 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}")
  3. 初始化状态:在沙箱中写入内存变量和文件系统数据。

    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()

Header参数说明

ack-sandbox-manager 支持通过自定义 Header 扩展 Checkpoint 能力:

Header 参数

说明

默认值

x-e2b-kruise-snapshot-keep-running

Checkpoint 创建后 Sandbox 是否继续运行。若为 false,Pod 状态将变为 Succeeded。

true

x-e2b-kruise-snapshot-ttl

Checkpoint 存活时间,到期自动删除(如 30m)。若不配置则永久存在。

x-e2b-kruise-snapshot-persistent-contents

手动覆盖 Checkpoint 保留内容。支持 filesystem 或 memory,filesystem。

继承 Sandbox 配置

x-e2b-kruise-snapshot-wait-success-seconds

服务端等待 Checkpoint 完成的超时时间(秒)。

60

从 Checkpoint 克隆沙箱

  1. 克隆时,将上一步返回的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>")
  2. 检查克隆后的沙箱数据,验证恢复效果。

    # 验证开启内存保留的克隆
    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

  1. 通过创建 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
  2. 查看checkpointId

    kubectl get checkpoint checkpoint-code-demo -n default -o jsonpath='{.status.checkpointId}'

克隆新沙箱

  1. 替换以下<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
  2. 查看 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>

相关文档

创建Agent Sandbox