本文档提供了在 GKE 上管理 Agent Sandbox 存储空间的参考实现,这些实现根据智能体的生命周期需求量身定制。
根据代理的数据生命周期需求,选择以下配置之一:
如需详细了解如何选择存储解决方案,请参阅为 AI 智能体工作负载选择存储。
以下文档使用 dynamic-rwo StorageClass 进行自动磁盘类型选择,以预配与调度 GKE Pod 上的 Agent Sandbox 的节点机器类型兼容的磁盘。为确保 GKE 为智能体的存储空间预配 Hyperdisk Balanced 卷,您必须在兼容机器系列(例如 N4)的节点上,将 Agent Sandbox 调度到 GKE Pod 上;否则,GKE 会回退到 pd-balanced。
本文档使用 ReadWriteOnce (RWO) 访问权限实现私有隔离工作区数据访问模式。在此模式下,代理启动时会有一个私有隔离存储目录,该目录只有该代理拥有读写权限。
除非另有说明,否则本文档中的参考实现均使用直接沙盒创建,这适用于可容忍数秒启动延迟时间的代理。如需为有状态或时间点恢复工作区实现亚秒级启动延迟时间,您必须使用 GKE 暖池上的 Agent Sandbox。将存储空间绑定到已认领的暖池 Pod 需要自定义脚本和特权 DaemonSet。如需查看参考实现,请参阅此 GitHub 示例。
替代访问模式
如需支持其他访问模式,您可以修改配置中的卷和快照定义:
- 协作工作区:将
accessModes更改为ReadWriteMany,并使用支持 RWX 的 StorageClass,例如 Filestore 多共享(企业版)(enterprise-multishare-rwx)。 - 探索分支工作区:将模板文件夹装载为只读,并提供单独的可写暂存器。对于基本模板,您必须使用支持多个只读挂接的存储,例如采用
ReadOnlyMany(ROX) 访问模式的 Hyperdisk ML 或采用 RWX 访问模式的 Filestore Multishares。
准备工作
确保您有一个已安装 Agent Sandbox 控制器的 GKE 集群。如果没有,请仅完成在 GKE 上安装 Agent Sandbox 的以下部分,然后返回本文档:
如果您已完成该文档的部署沙盒化环境部分,请删除其创建的示例资源,以便您的节点有足够的容量来容纳本文档中的沙盒:
kubectl delete sandboxclaim sandbox-claim --ignore-not-found
kubectl delete sandboxwarmpool python-runtime-warmpool --ignore-not-found
kubectl delete sandbox sandbox-example-2 --ignore-not-found
配置有状态工作区
使用此模式可保留智能体的最新文件状态。当智能体必须在智能体会话暂停或终止(Agent Sandbox 被删除)时保留状态,并在智能体会话激活(Agent Sandbox 重新创建)时从最新状态恢复数据时,此功能非常有用。
本部分中的参考实现使用直接沙盒创建,适用于可容忍多秒启动延迟时间的代理。
此方法使用标准 GKE PersistentVolumeClaim (PVC) 资源将沙盒关联到包含用户数据的预先存在的 PVC。
有状态工作区模式遵循以下事件序列:
- 预配:管理员或编排器使用确定性标识符(例如
pvc-agent-1)为每个智能体对话手动预配一个专用 PVC。 - 引用:在
Sandbox资源中,您可以使用volumes块中的persistentVolumeClaim字段来指定现有卷的确切claimName。 - 延迟时间:创建沙盒后,GKE 必须将 Compute Engine 磁盘动态挂接到节点虚拟机,这会产生标准的几秒延迟。
- 持久性:在会话终止(删除
Sandbox资源)时,GKE 会分离磁盘,但不会销毁 PVC,这有助于确保为下一个会话保留最新状态。
如需配置在会话之间保留数据的有状态工作区,请完成以下小节中的步骤。
预配永久性工作区 (PVC)
创建使用确定性标识符(例如 pvc-agent-1)的专用 PersistentVolumeClaim (PVC)。
将以下清单保存为
pvc-agent-1.yaml:apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-agent-1 # Derived directly from the deterministic assignment ID namespace: default spec: accessModes: - ReadWriteOnce storageClassName: dynamic-rwo # Selects disk type compatible with the node machine family resources: requests: storage: 10Gi应用清单:
kubectl apply -f pvc-agent-1.yaml
由于存储类别使用动态卷绑定,因此磁盘尚未挂接到任何节点。它会一直处于 Pending 状态,直到请求它的 Pod 被调度。
部署 Agent Sandbox
部署 Sandbox 自定义资源,引用确定性 PVC。
将以下清单保存为
sandbox-agent-1.yaml:apiVersion: agents.x-k8s.io/v1beta1 kind: Sandbox metadata: name: sandbox-agent-1 # Traceable sandbox name namespace: default spec: podTemplate: spec: runtimeClassName: gvisor # Required automountServiceAccountToken: false # Required securityContext: runAsNonRoot: true # Required runAsUser: 1000 fsGroup: 1000 # Grant group access to the volume nodeSelector: sandbox.gke.io/runtime: gvisor # Required tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" # Required containers: - name: agent image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 ports: - containerPort: 8888 volumeMounts: - name: workspace-disk mountPath: /workspace # Mounts the private disk into the container resources: limits: cpu: "500m" memory: "1Gi" # Required securityContext: capabilities: drop: ["ALL"] # Required volumes: - name: workspace-disk persistentVolumeClaim: claimName: pvc-agent-1 # Binds this specific Sandbox to Agent 1's PVC restartPolicy: OnFailure应用清单:
kubectl apply -f sandbox-agent-1.yaml等待沙盒准备就绪:
kubectl wait sandbox sandbox-agent-1 \ --for=condition=Ready \ --timeout=300sGKE 会验证节点容量并挂接磁盘,这需要几秒钟的时间。容器在用户空间 gVisor 内核中初始化。在 Autopilot 集群中,沙盒可能需要几分钟才能准备就绪,因为 GKE 可能需要为其创建节点。
从智能体写入数据
通过将文本文件写入装载的磁盘,模拟活跃的 AI 智能体在其工作区内执行文件修改。
# Set the active Pod name
POD_NAME=sandbox-agent-1
# Write a state file to the persistent directory
kubectl exec ${POD_NAME} -- sh -c "echo 'Workspace State Saved - Agent 1' > /workspace/modified_data.txt"
# Confirm the file exists on the disk
kubectl exec ${POD_NAME} -- cat /workspace/modified_data.txt
结束代理会话
如需模拟在代理空闲时缩容或终止会话,请删除 Sandbox 资源,但保留底层存储。
kubectl delete sandbox sandbox-agent-1
GKE 会卸载并分离磁盘。pvc-agent-1 PVC 仍会保留,从而保留数据。
重新激活代理会话
如需重新激活会话,请重新部署引用同一 PVC 的新 Sandbox 资源,然后等待沙盒准备就绪:
kubectl apply -f sandbox-agent-1.yaml
kubectl wait sandbox sandbox-agent-1 \
--for=condition=Ready \
--timeout=300s
磁盘会重新挂接(产生挂接延迟),并且容器会启动。
验证数据保留
检查新创建的沙盒容器,验证之前的会话数据是否已保留。
# Set the active Pod name of the new session
NEW_POD_NAME=sandbox-agent-1
# Read the file from the newly booted sandbox
kubectl exec ${NEW_POD_NAME} -- cat /workspace/modified_data.txt
输出应显示 Workspace State Saved - Agent 1。
清理资源
删除 Agent Sandbox 和关联的永久性卷声明:
kubectl delete sandbox sandbox-agent-1
kubectl delete pvc pvc-agent-1
配置时间点恢复和所有权转移
使用此模式克隆数据集,以运行并行实验、调试或独立工作。智能体的 Workspace 会从历史数据集(或共享状态)进行初始化,并将后续修改保存到单独的私有可写层,而不会修改基本模板。
本部分中的参考实现使用直接沙盒创建,适用于可容忍多秒启动延迟时间的代理。此方法依赖于编排器在启动新的沙盒会话之前,从历史 VolumeSnapshot 动态预配新的 PersistentVolumeClaim (PVC)。
创建 VolumeSnapshotClass
创建 VolumeSnapshotClass,用于指定 CSI 驱动程序和删除政策。对于 Hyperdisk,请使用 pd.csi.storage.gke.io 驱动程序。
将以下清单保存为
1-snapshot-class.yaml:apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata: name: standard-rwo-snapshot driver: pd.csi.storage.gke.io deletionPolicy: Delete应用清单:
kubectl apply -f 1-snapshot-class.yaml
预配初始工作区
创建一个卷,供智能体执行初始工作。
将以下清单保存为
2-source-pvc.yaml:apiVersion: v1 kind: PersistentVolumeClaim metadata: name: agent-source-pvc spec: accessModes: ["ReadWriteOnce"] storageClassName: dynamic-rwo resources: requests: storage: 10Gi应用清单:
kubectl apply -f 2-source-pvc.yaml
生成状态数据
部署沙盒 Pod 以将数据写入卷。
将以下清单保存为
3-source-sandbox.yaml:apiVersion: agents.x-k8s.io/v1beta1 kind: Sandbox metadata: name: agent-session-v1 namespace: default spec: podTemplate: spec: runtimeClassName: gvisor automountServiceAccountToken: false # Required securityContext: runAsNonRoot: true # Required runAsUser: 1000 fsGroup: 1000 # Grant group access to the volume nodeSelector: sandbox.gke.io/runtime: gvisor # Required tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" # Required containers: - name: agent image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 ports: - containerPort: 8888 volumeMounts: - name: workspace mountPath: /workspace resources: limits: cpu: "500m" memory: "1Gi" # Required securityContext: capabilities: drop: ["ALL"] # Required volumes: - name: workspace persistentVolumeClaim: claimName: agent-source-pvc restartPolicy: OnFailure应用清单:
kubectl apply -f 3-source-sandbox.yaml等待沙盒准备就绪,然后写入状态文件。
sync命令会将写入内容刷新到磁盘,以便下一部分中的快照包含该文件的内容:kubectl wait sandbox agent-session-v1 \ --for=condition=Ready \ --timeout=300s POD_NAME=agent-session-v1 kubectl exec ${POD_NAME} -- sh -c "echo 'Point-in-Time Snapshot - v1' > /workspace/state.txt && sync"
归档历史状态 (CSI VolumeSnapshot)
触发 CSI VolumeSnapshot 以冻结当前状态。创建快照时,请遵循磁盘快照的最佳实践。
将以下清单保存为
4-volume-snapshot.yaml:apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: agent-session-v1-snapshot spec: volumeSnapshotClassName: standard-rwo-snapshot source: persistentVolumeClaimName: agent-source-pvc应用清单:
kubectl apply -f 4-volume-snapshot.yaml等待快照准备就绪,可供使用:
kubectl wait volumesnapshot agent-session-v1-snapshot \ --for=jsonpath='{.status.readyToUse}'=true \ --timeout=600s
从快照恢复卷
部署一个新的 PVC,其 dataSource 指向 CSI VolumeSnapshot。
将以下清单保存为
5-restored-pvc.yaml:apiVersion: v1 kind: PersistentVolumeClaim metadata: name: agent-restored-pvc spec: accessModes: ["ReadWriteOnce"] storageClassName: dynamic-rwo dataSource: name: agent-session-v1-snapshot kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io resources: requests: storage: 10Gi应用清单:
kubectl apply -f 5-restored-pvc.yaml
启动已恢复的 Agent Sandbox 会话
预配引用新恢复的 PVC 的全新 Sandbox 资源。
将以下清单保存为
6-restored-sandbox.yaml:apiVersion: agents.x-k8s.io/v1beta1 kind: Sandbox metadata: name: agent-session-v2-restored namespace: default spec: podTemplate: spec: runtimeClassName: gvisor automountServiceAccountToken: false # Required securityContext: runAsNonRoot: true # Required runAsUser: 1000 fsGroup: 1000 # Grant group access to the volume nodeSelector: sandbox.gke.io/runtime: gvisor # Required tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" # Required containers: - name: agent image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 ports: - containerPort: 8888 volumeMounts: - name: workspace mountPath: /workspace resources: limits: cpu: "500m" memory: "1Gi" # Required securityContext: capabilities: drop: ["ALL"] # Required volumes: - name: workspace persistentVolumeClaim: claimName: agent-restored-pvc restartPolicy: OnFailure应用清单:
kubectl apply -f 6-restored-sandbox.yaml等待沙盒准备就绪:
kubectl wait sandbox agent-session-v2-restored \ --for=condition=Ready \ --timeout=600s此沙盒可能需要比源沙盒更长的时间才能准备就绪,因为 GKE 会在快照准备就绪后根据快照创建其磁盘。
验证持久性和恢复
验证代理能否读取历史数据。
NEW_POD_NAME=agent-session-v2-restored
kubectl exec ${NEW_POD_NAME} -- cat /workspace/state.txt
预期输出:Point-in-Time Snapshot - v1
清理资源
删除 Agent Sandbox、PVC 和 VolumeSnapshot:
kubectl delete sandbox agent-session-v1
kubectl delete sandbox agent-session-v2-restored
kubectl delete pvc agent-source-pvc
kubectl delete pvc agent-restored-pvc
kubectl delete volumesnapshot agent-session-v1-snapshot
kubectl delete volumesnapshotclass standard-rwo-snapshot
配置临时工作区
当智能体在活跃状态下需要存储卷来存储临时文件时,请使用临时工作区模式。删除 Agent Sandbox 时无需保留任何数据。
配置为在 1 秒内启动
在 GKE 暖池上使用 Agent Sandbox,在后台预先预配空卷。
定义 SandboxTemplate 资源
在 volumeClaimTemplate 块中定义临时存储后备。
将以下清单保存为
stateless-template.yaml:apiVersion: extensions.agents.x-k8s.io/v1beta1 kind: SandboxTemplate metadata: name: stateless-sandbox-template namespace: default spec: podTemplate: spec: runtimeClassName: gvisor automountServiceAccountToken: false securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 # Grant group access to the volume nodeSelector: sandbox.gke.io/runtime: gvisor tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" containers: - name: agent image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 ports: - containerPort: 8888 volumeMounts: - name: ephemeral-disk mountPath: /workspace resources: limits: cpu: "500m" memory: "1Gi" # Required securityContext: capabilities: drop: ["ALL"] # Required volumeClaimTemplates: - metadata: name: ephemeral-disk spec: accessModes: ["ReadWriteOnce"] storageClassName: dynamic-rwo # Selects disk type compatible with node machine family resources: requests: storage: 10Gi
启动 SandboxWarmPool 资源
将以下清单保存为
stateless-warmpool.yaml:apiVersion: extensions.agents.x-k8s.io/v1beta1 kind: SandboxWarmPool metadata: name: stateless-warmpool namespace: default spec: replicas: 2 # Keep two standby Pods with pre-attached empty disks sandboxTemplateRef: name: stateless-sandbox-template应用这两个清单:
kubectl apply -f stateless-template.yaml kubectl apply -f stateless-warmpool.yaml等待预热池的沙盒准备就绪:
kubectl wait sandboxwarmpool stateless-warmpool \ --for=jsonpath='{.status.readyReplicas}'=2 \ --timeout=600s如果您在池的沙盒准备就绪之前创建
SandboxClaim资源,则控制器可能会为声明创建新沙盒,而不是从池中分配一个沙盒。在 Autopilot 集群中,沙盒可能需要几分钟才能准备就绪,因为 GKE 可能需要为其创建节点。
创建 SandboxClaim 资源
定义一个在用户开始会话时触发的 SandboxClaim 资源。
将以下清单保存为
stateless-sandbox-claim.yaml:apiVersion: extensions.agents.x-k8s.io/v1beta1 kind: SandboxClaim metadata: name: agent-1-claim spec: warmPoolRef: name: stateless-warmpool应用清单:
kubectl apply -f stateless-sandbox-claim.yaml
验证亚秒级执行
等待声明准备就绪,捕获 Agent Sandbox Pod 名称,然后验证 /workspace 目录是否已装载并可立即使用:
kubectl wait sandboxclaim agent-1-claim --for=condition=Ready --timeout=300s
export POD_NAME=$(kubectl get sandboxclaim agent-1-claim -o jsonpath='{.status.sandbox.name}')
kubectl exec ${POD_NAME} -- ls -la /workspace
终止代理会话
如需结束代理会话,请删除 SandboxClaim 资源。删除声明也会删除声明的沙盒及其卷:
kubectl delete sandboxclaim agent-1-claim
清理资源
删除 SandboxWarmPool 和 SandboxTemplate 资源:
kubectl delete sandboxwarmpool stateless-warmpool
kubectl delete sandboxtemplate stateless-sandbox-template
配置为启动时间为数秒
如需实现可容忍多秒延迟时间的临时工作区,请直接创建 Agent Sandbox,不使用温池。
定义无状态 Agent Sandbox
将以下清单保存为
sandbox-direct-stateless.yaml:apiVersion: agents.x-k8s.io/v1beta1 kind: Sandbox metadata: name: sandbox-direct-stateless namespace: default spec: podTemplate: spec: runtimeClassName: gvisor automountServiceAccountToken: false securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 # Grant group access to the volume nodeSelector: sandbox.gke.io/runtime: gvisor tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" containers: - name: agent image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 ports: - containerPort: 8888 volumeMounts: - name: ephemeral-disk mountPath: /workspace resources: limits: cpu: "500m" memory: "1Gi" # Required securityContext: capabilities: drop: ["ALL"] # Required restartPolicy: OnFailure volumeClaimTemplates: - metadata: name: ephemeral-disk spec: accessModes: ["ReadWriteOnce"] storageClassName: dynamic-rwo resources: requests: storage: 10Gi
部署 Agent Sandbox
如需动态预配磁盘并将其挂接到预定节点,请应用清单:
kubectl apply -f sandbox-direct-stateless.yaml
验证启动延迟时间和执行情况
监控 Pod 状态,观察 Pod 转换为 Running 状态之前的挂接延迟时间:
kubectl get pods -w
当 Pod 处于运行状态时,按 Control+C 停止监控。
捕获 Pod 名称并验证 /workspace 目录是否可用:
POD_NAME=sandbox-direct-stateless
kubectl exec ${POD_NAME} -- ls -la /workspace
终止代理会话
删除 Sandbox 资源以自动终止 Pod 并销毁其临时存储空间:
kubectl delete sandbox sandbox-direct-stateless
后续步骤
- 详细了解 GKE 上的 Agent Sandbox。
- 详细了解如何在 GKE 上使用 Agent Sandbox 隔离 AI 代码执行。
- 了解如何使用 Pod 快照在 GKE 环境中保存和恢复 Agent Sandbox。