使用 Pod 快照在 GKE 环境中保存和恢复 Agent Sandbox

本文档介绍了如何使用 GKE Pod 快照保存 GKE 环境中正在运行的 Agent Sandbox 的状态。

GKE 上的 Agent Sandbox 提供了一个隔离的环境,用于执行不受信任的代码(例如由大语言模型 [LLM] 生成的代码),从而提高安全性。直接在集群中运行此类代码会带来安全风险,因为不可信代码可能会访问或干扰其他应用或底层集群节点本身。

借助 GKE Pod 快照,您可以保存和恢复沙盒化环境的状态。此功能非常有用,原因如下:

  • 快速启动:通过从预热快照恢复来缩短沙盒启动时间。
  • 长时间运行的智能体:暂停需要长时间运行的沙盒,稍后再恢复运行,或将其移至其他节点,而不会丢失进度。
  • 有状态工作负载:通过保存和恢复沙盒化环境的状态,持久保存智能体的上下文,例如对话记录或中间计算。
  • 可重现性:捕获特定状态,并将其用作基础,以相同的初始化状态启动多个新沙盒。

快照可以通过以下两种方式触发:

  • 手动触发器:您创建 PodSnapshotManualTrigger 资源来触发快照。
  • 工作负载触发器:沙盒化应用本身会在准备好保存时发出信号。

本文档介绍了如何手动触发快照。

准备工作

  1. 在 Google Cloud 控制台的项目选择器页面上,选择或创建 Google Cloud 项目。

    选择或创建项目所需的角色

    • 选择项目:选择项目不需要特定的 IAM 角色,您可以选择已获授角色的任何项目。
    • 创建项目:如需创建项目,您需要拥有 Project Creator 角色 (roles/resourcemanager.projectCreator),该角色包含 resourcemanager.projects.create 权限。了解如何授予角色。

    转到“项目选择器”

  2. 验证是否已为您的 Google Cloud 项目启用结算功能。

  3. 启用 Google Kubernetes Engine、Cloud Storage、Identity and Access Management (IAM) API(如果尚未启用)。

    启用 API 所需的角色

    如需启用 API,您需要拥有 serviceusage.services.enable 权限。如果您创建了项目,则可能已经通过 Owner 角色 (roles/owner) 拥有此权限。否则,您可以通过 Service Usage Admin 角色 (roles/serviceusage.serviceUsageAdmin) 获得此权限。了解如何授予角色。

    启用 API

  4. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

要求

GKE Pod 快照需要 GKE 1.35.3-gke.1234000 版或更高版本。Autopilot 和 Standard 模式均受支持。

Pod 快照需要 gVisor,不适用于 microVM 沙盒。

由于 Pod 快照需要 GKE Sandbox,因此您的环境会受到某些限制。例如,Pod 快照不支持 E2 机器类型。因此,本教程会创建一个由 N2 机器组成的节点池。

如需查看限制的完整列表(包括有关使用基于 GPU 的机器类型的信息),请参阅限制和要求。

定义环境变量

为了简化您在本文档中运行的命令,您可以在 Cloud Shell 中设置环境变量。这些变量用于存储 Google Cloud 项目的 ID、将存储快照的 Cloud Storage 存储桶的名称以及 GKE 集群的位置等值。

定义这些变量后,您可以通过引用变量名称(例如 $CLUSTER_NAME)在多个命令中重复使用它们,而无需每次都重新输入或替换值。这种方法可让流程更易于理解,并降低出错风险。

如需在 Cloud Shell 中定义以下有用的环境变量,请运行以下命令:

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export GKE_LOCATION="us-central1"
export ZONE="us-central1-a"
export AGENT_SANDBOX_VERSION="v1.0.6"
export NODE_POOL_NAME="agent-sandbox-node-pool"
export MACHINE_TYPE="n2-standard-2"
export SNAPSHOTS_BUCKET_NAME="agent-sandbox-snapshots-${PROJECT_ID}"
export SNAPSHOT_NAMESPACE="pod-snapshots-ns"
export SNAPSHOT_KSA_NAME="pod-snapshot-sa"
export SNAPSHOT_FOLDER="my-snapshots"
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

以下是这些环境变量的说明:

  • PROJECT_ID:当前 Google Cloud 项目的 ID。本文档中的命令使用此 ID 来命名资源和授予 IAM 权限。
  • CLUSTER_NAME:GKE 集群的名称(例如 agent-sandbox-cluster)。
  • GKE_LOCATION:Cloud Storage 存储桶的 Google Cloud 区域(例如 us-central1)。如果您创建 Autopilot 集群,该集群也会使用此区域。
  • ZONE:GKE 集群的可用区。如果您创建 Standard 集群,请将其设置为 GKE_LOCATION 区域中的可用区(例如 us-central1-a)。为降低费用,本文档会创建一个可用区级 Standard 集群。
  • AGENT_SANDBOX_VERSION:要安装的开源 Agent Sandbox 控制器的版本。本文档使用 1.0.6 版。
  • NODE_POOL_NAME:将运行沙盒化工作负载的节点池的名称(例如 agent-sandbox-node-pool)。
  • MACHINE_TYPE:节点池中节点的机器类型(例如 n2-standard-2)。Pod 快照不支持 E2 机器类型。如果您想为节点池中的节点使用基于 GPU 的机器类型,请参阅限制和要求。如需详细了解不同的机器系列以及如何在不同选项之间进行选择,请参阅机器家族资源和比较指南。
  • SNAPSHOTS_BUCKET_NAME:您将创建的用于存储快照的 Cloud Storage 存储桶的名称。
  • SNAPSHOT_NAMESPACE:快照工作负载和服务账号所在的 Kubernetes 命名空间。
  • SNAPSHOT_KSA_NAME:工作负载将用于进行身份验证的 Kubernetes 服务账号的名称。
  • SNAPSHOT_FOLDER:Cloud Storage 存储桶中用于整理快照的目录。
  • PROJECT_NUMBER:项目的唯一数字标识符,用于 IAM 权限绑定。

配置步骤概览

如需在 GKE 环境中为 Agent Sandbox 启用 Pod 快照,您需要执行一些配置步骤。为了理解这些步骤,最好先了解一些关键概念,然后再了解快照流程:

主要概念

  • 环境:沙盒化应用在 GKE 集群节点上的 Kubernetes Pod 中运行。
  • 身份:Pod 与 Kubernetes 服务账号相关联,并在您创建的特殊命名空间中运行。Kubernetes 服务账号和命名空间共同构成一个唯一身份,用于向 Pod 授予对 Google Cloud 资源的安全访问权限。
  • 权限:如需允许将快照保存到 Cloud Storage,必须向 Pod 的身份授予特定 IAM 权限,以允许其写入 Cloud Storage 存储桶。

快照流程

  1. 触发器:手动(外部)或由沙盒化工作负载本身启动快照。本文档演示了您通过创建 PodSnapshotManualTrigger 资源启动的手动触发器。
  2. 捕获:GKE 会捕获 Pod 的运行状态,例如 Pod 的内存状态及其文件系统。
  3. 上传:GKE 使用授予 Pod 的 Kubernetes 服务账号的权限,将捕获的状态作为快照文件上传到指定的 Cloud Storage 存储桶。

如需详细了解 GKE 如何使用 Kubernetes 服务账号和 IAM 角色访问 Google Cloud 资源,请参阅从 GKE 工作负载向Google Cloud API 进行身份验证。

如需在 GKE 环境中为 Agent Sandbox 启用 Pod 快照,请执行以下配置。首先,您需要创建一个启用了 Workload Identity Federation for GKE 和 Pod 快照功能的 GKE 集群,以准备集群环境。接下来,您将配置 Cloud Storage 和 IAM 政策,以确保快照安全存储,并确保沙盒拥有必要的权限。最后,您需要创建快照资源,为沙盒指定存储位置和政策。

下表总结了您需要执行的配置步骤,后续部分将对每个步骤进行说明:

主题 任务
集群设置 1. 创建一个 GKE 集群,并启用 Pod 快照和 Workload Identity Federation for GKE 功能。
2. 部署 Agent Sandbox。
配置存储空间和权限 1. 创建 Cloud Storage 存储桶和托管文件夹。
2. 创建自定义 IAM 角色。
3. 创建 Kubernetes 命名空间和 Kubernetes 服务账号 (KSA)。
4. 将 IAM 角色绑定到 Kubernetes 服务账号。
5. 向快照控制器授予权限。
配置快照资源 1. 创建 PodSnapshotStorageConfig 资源
2. 创建 PodSnapshotPolicy 资源
3. 创建 SandboxTemplate、SandboxWarmPool 和 SandboxClaim 资源

集群设置

沙盒化应用在 GKE 集群节点上的 Pod 内运行,因此您需要设置集群环境。本部分介绍了如何创建 GKE 集群并部署 Agent Sandbox 控制器。

创建符合要求的新 GKE 集群

创建启用了 Pod 快照的新 GKE 集群。Pod 快照需要 GKE 1.35.3-gke.1234000 或更高版本。以下命令会将集群注册到快速发布渠道,其默认版本满足此要求:

Autopilot

创建具有所需功能的 Autopilot 集群:

gcloud container clusters create-auto ${CLUSTER_NAME} \
   --release-channel=rapid \
   --enable-pod-snapshots \
   --location=${GKE_LOCATION}

标准

创建具有所需功能的 Standard 集群。为降低费用,以下命令会创建一个可用区级集群,该集群在一个可用区中运行其控制平面和节点:

gcloud container clusters create ${CLUSTER_NAME} \
   --release-channel=rapid \
   --enable-pod-snapshots \
   --machine-type=${MACHINE_TYPE} \
   --workload-pool=${PROJECT_ID}. \
   --workload-metadata=GKE_METADATA \
   --num-nodes=1 \
   --location=${ZONE}

创建已启用 GKE Sandbox 的节点池。GKE Sandbox 是一项基于开源 gVisor 项目的容器安全功能,可在运行中的应用与主机操作系统之间提供额外的隔离层:

gcloud container node-pools create ${NODE_POOL_NAME} \
   --cluster ${CLUSTER_NAME} \
   --num-nodes=1 \
   --location=${ZONE} \
   --project=${PROJECT_ID} \
   --machine-type=${MACHINE_TYPE} \
   --sandbox type=gvisor

检索凭证

检索集群的凭证,以便 kubectl CLI 可以连接到集群:

Autopilot

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${GKE_LOCATION}

标准

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${ZONE}

将 Agent Sandbox 控制器部署到您的集群

您可以将正式版清单应用于集群,以部署 Agent Sandbox 控制器及其所需的组件。此清单是配置文件,用于指示 Kubernetes 下载在集群上部署和运行 Agent Sandbox 控制器所需的所有必要组件。

如需将 Agent Sandbox 部署到 GKE 集群,请运行以下命令:

# Apply the release manifest for the controller and its CustomResourceDefinitions
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml

如需详细了解如何安装 Agent Sandbox,请参阅在 GKE 上安装 Agent Sandbox。

验证控制器

应用清单后,检查 Agent Sandbox 控制器 Pod 是否在 agent-sandbox-system 命名空间中正常运行。当您在上一步中应用清单时,清单会自动创建 agent-sandbox-system 命名空间。

kubectl get pods -n agent-sandbox-system

等待 Pod 在状态列中显示“正在运行”,在就绪列中显示“1/1”。当 Pod 正常运行时,输出类似于以下内容:

NAME                                        READY   STATUS    RESTARTS   AGE
agent-sandbox-controller-7d5c9b8f6d-x2k9p   1/1     Running   0          2m

现在,Agent Sandbox 控制器正在运行,它可以自动为您在集群中创建的任何 Sandbox 资源创建和管理沙盒化环境。

配置存储空间和权限

本部分介绍如何配置 Pod 快照所需的存储空间和权限。您需要创建一个 Cloud Storage 存储桶和一个托管文件夹来存储快照数据。然后,您向沙盒和快照控制器授予访问该存储空间所需的权限。

创建 Cloud Storage 存储桶

创建一个存储桶来存储快照。为确保快照过程快速且经济实惠,请使用以下设置创建存储桶:

  • 启用分层命名空间:分层命名空间功能可将存储桶整理为文件系统层次结构,而不是平面命名空间。此配置可实现更高的读写吞吐量,从而加快保存和恢复快照的速度。
  • 停用软删除:软删除功能通过将已删除的文件保留一段时间来保护数据。不过,快照过程会在上传期间创建和删除许多临时文件。停用软删除功能,以免因存储这些临时文件而产生不必要的费用。

如需使用这些设置创建存储桶,请运行以下命令:

gcloud storage buckets create "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --uniform-bucket-level-access \
    --enable-hierarchical-namespace \
    --soft-delete-duration=0d \
    --location="${GKE_LOCATION}"

创建托管文件夹

创建一个托管文件夹,用于整理存储桶中的快照。通过托管文件夹,您可以将 IAM 权限应用于特定文件夹,而不是整个存储桶。这种文件夹级访问权限可将沙盒的访问权限限制为仅访问其自己的快照,并将这些快照与存储桶中的其他数据隔离开来。

如需创建托管文件夹,请运行以下命令:

gcloud storage managed-folders create "gs://${SNAPSHOTS_BUCKET_NAME}/${SNAPSHOT_FOLDER}/"

配置服务账号和 IAM 角色

为了允许 GKE 安全地保存快照,运行沙盒化工作负载的 Pod 使用的 Kubernetes 服务账号需要具有对存储桶的写入权限。您可以通过将 Google CloudIAM 角色绑定到 Pod 使用的 Kubernetes 服务账号来授予此权限。本部分介绍如何创建自定义 IAM 角色、创建 Kubernetes 服务账号以及配置必要的权限。

  1. 创建一个名为 podSnapshotGcsReadWriter 的自定义 IAM 角色,其中包含写入快照数据所需的权限。如果您的项目中已存在此角色(例如,由于之前运行过本文档),请跳过此步骤。否则,请运行以下命令:

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="${PROJECT_ID}" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    

    成功创建角色后,输出如下所示:

    Created role [podSnapshotGcsReadWriter].
    etag: BwZJUfjNbew=
    includedPermissions:
    - storage.folders.create
    - storage.objects.create
    - storage.objects.delete
    - storage.objects.get
    name: projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter
    stage: ALPHA
    title: podSnapshotGcsReadWriter
    

    如果该命令失败并显示 FAILED_PRECONDITION 错误,指出角色 ID 已标记为删除,则表示您最近删除了具有此 ID 的角色,例如在之前运行本文档的清理步骤中。IAM 最多 37 天内不允许您重复使用该 ID。使用其他角色 ID(例如 podSnapshotGcsReadWriter2)再次运行该命令,并在本文档的其余部分中使用该 ID,而不是 podSnapshotGcsReadWriter。

  2. 创建沙盒及其服务账号所在的命名空间:

    kubectl create namespace "${SNAPSHOT_NAMESPACE}"
    
  3. 在您刚刚创建的命名空间中创建 Kubernetes 服务账号。Kubernetes 服务账号和命名空间共同构成一个唯一身份,用于向沙盒授予对 Google Cloud资源的访问权限:

    kubectl create serviceaccount "${SNAPSHOT_KSA_NAME}" \
        --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. 将 roles/storage.bucketViewer 角色授予命名空间中的所有服务账号。此角色允许账号查看存储桶的元数据,但不能读取或写入数据本身:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}./namespace/${SNAPSHOT_NAMESPACE}" \
        --role="roles/storage.bucketViewer"
    
  5. 将自定义 podSnapshotGcsReadWriter 角色授予沙盒的 Kubernetes 服务账号。此绑定仅允许此特定账号将数据写入托管式文件夹。新的自定义角色可能需要几分钟才能生效,因此,如果此命令因角色不存在而失败,请稍等片刻,然后再次运行该命令:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}./subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter"
    
  6. 将 roles/storage.objectUser 角色授予 Kubernetes 服务账号。 Pod 快照代理需要此角色才能对托管文件夹执行操作:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}./subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="roles/storage.objectUser"
    

向快照控制器授予权限

将 objectUser 角色授予 GKE 系统的快照控制器。此权限允许控制器管理快照生命周期,例如在您删除 PodSnapshot 资源时删除快照对象:

gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot." \
    --role="roles/storage.objectUser"

配置快照资源

本部分介绍了如何为 Agent Sandbox on GKE 工作负载配置快照资源。

定义快照存储和规则

如需指定 GKE 保存快照的位置以及管理快照流程的规则,您需要创建两个自定义资源:

  • PodSnapshotStorageConfig:此资源指定 GKE 保存快照文件的 Cloud Storage 存储桶和文件夹位置。
  • PodSnapshotPolicy:此资源根据 Pod 的 Kubernetes 标签定义哪些 Pod 符合快照条件。它还指定了触发规则,例如快照是手动触发还是由沙盒工作负载启动。此示例按 agents.x-k8s.io/sandbox-name-hash 标签对快照进行分组,Agent Sandbox 控制器会将该标签添加到每个沙盒的 Pod 中。这种分组意味着 GKE 仅从每个沙盒自己的快照中恢复该沙盒。

如需一步应用这两个资源,请在 Cloud Shell 中运行以下命令。此方法有助于确保正确注入环境变量:

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotStorageConfig
metadata:
  name: cpu-pssc-gcs
spec:
  snapshotStorageConfig:
    gcs:
      bucket: "${SNAPSHOTS_BUCKET_NAME}"
      path: "${SNAPSHOT_FOLDER}"
EOF

sleep 5

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotPolicy
metadata:
  name: cpu-psp
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  storageConfigName: cpu-pssc-gcs
  selector:
    matchLabels:
      app: agent-sandbox-workload
  triggerConfig:
    type: manual
    postCheckpoint: resume
  snapshotGroupingRules:
    groupByLabelValue:
      labels:
      - agents.x-k8s.io/sandbox-name-hash
EOF

验证配置

应用快照存储配置和政策后,请验证资源是否已准备就绪,可供使用。本部分介绍了如何检查这些自定义资源的状态。

  1. 检查 PodSnapshotStorageConfig 资源的状态:

    kubectl get podsnapshotstorageconfigs.podsnapshot.gke.io cpu-pssc-gcs -o yaml
    

    输出应包含一个具有 type: Ready 和 status: "True" 的条件:

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:18:02Z"
        message: Valid PodSnapshotStorageConfig
        reason: StorageConfigValid
        status: "True"
        type: Ready
    
  2. 检查 PodSnapshotPolicy 资源的状态:

    kubectl get podsnapshotpolicies.podsnapshot.gke.io cpu-psp \
      --namespace "${SNAPSHOT_NAMESPACE}" -o yaml
    

    输出应包含具有 type: Ready 和 status: "True" 的条件。它还应指明已找到引用的 PodSnapshotStorageConfig 资源:

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:19:47Z"
        message: The referenced PodSnapshotStorageConfig "cpu-pssc-gcs" was found
        reason: StorageConfigValid
        status: "True"
        type: Ready
    

创建沙盒模板

现在,存储政策和权限已就绪,您可以创建 SandboxTemplate、SandboxWarmPool 和 SandboxClaim 资源。SandboxWarmPool 资源会使预热的沙盒保持运行状态,而 SandboxClaim 资源会从池中声明该沙盒。为使快照流程正常运行,沙盒必须使用您在本文档前面创建的 Kubernetes 服务账号运行。沙盒还必须具有您之前在 PodSnapshotPolicy 资源中指定的标签。

此示例使用一个 Python 应用,该应用会将递增计数器输出到日志。通过此计数器,您可以验证状态是否已成功保存并在稍后恢复。

Autopilot

Pod 快照不支持 E2 机器类型。在 Autopilot 中,GKE 可能会默认使用不支持 Pod 快照的机器类型。为确保工作负载在兼容的硬件上运行,您应使用自定义 ComputeClass 优先选择兼容的机器家族。

  1. 将以下清单保存为 non-e2-class.yaml:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: non-e2-class
    spec:
      priorities:
      - machineFamily: n2
      - machineFamily: c3
      activeMigration:
        optimizeRulePriority: false
      whenUnsatisfiable: DoNotScaleUp
    
  2. 应用清单:

    kubectl apply -f non-e2-class.yaml
    
  3. 如需创建 SandboxTemplate 和 SandboxWarmPool 资源,请应用以下清单。请注意,SandboxTemplate 资源使用 cloud.google.com/compute-class: non-e2-class 节点选择器引用您刚刚创建的 ComputeClass。

    kubectl apply -f - <<EOF
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      podTemplate:
        metadata:
          labels:
            app: agent-sandbox-workload
        spec:
          serviceAccountName: ${SNAPSHOT_KSA_NAME}
          runtimeClassName: gvisor
          nodeSelector:
            cloud.google.com/compute-class: non-e2-class
          containers:
          - name: my-container
            image: python:3.10-slim
            command: ["python3", "-c"]
            args:
              - |
                import time
                i = 0
                while True:
                  print(f"Count: {i}", flush=True)
                  i += 1
                  time.sleep(1)
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: python-sandbox-warmpool
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      replicas: 1
      sandboxTemplateRef:
        name: python-runtime-template
    EOF
    

标准

如需创建 SandboxTemplate 和 SandboxWarmPool 资源,请应用以下清单:

kubectl apply -f - <<EOF
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxTemplate
metadata:
  name: python-runtime-template
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  podTemplate:
    metadata:
      labels:
        app: agent-sandbox-workload
    spec:
      serviceAccountName: ${SNAPSHOT_KSA_NAME}
      runtimeClassName: gvisor
      containers:
      - name: my-container
        image: python:3.10-slim
        command: ["python3", "-c"]
        args:
          - |
            import time
            i = 0
            while True:
              print(f"Count: {i}", flush=True)
              i += 1
              time.sleep(1)
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxWarmPool
metadata:
  name: python-sandbox-warmpool
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  replicas: 1
  sandboxTemplateRef:
    name: python-runtime-template
EOF

创建资源后,从温池中申领沙盒:

  1. 等待预热池的沙盒准备就绪:

    kubectl wait sandboxwarmpool python-sandbox-warmpool \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=jsonpath='{.status.readyReplicas}'=1 \
      --timeout=600s
    
  2. 创建一个 SandboxClaim 资源,用于从预热池中认领沙盒:

    kubectl apply -f - <<EOF
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxClaim
    metadata:
      name: python-sandbox-example
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      warmPoolRef:
        name: python-sandbox-warmpool
    EOF
    
  3. 等待声明准备就绪,然后保存声明使用的沙盒的名称。沙盒的 Pod 与沙盒同名:

    kubectl wait sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
    export SANDBOX_NAME=$(kubectl get sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.sandbox.name}')
    echo "${SANDBOX_NAME}"
    

您的沙盒现在使用正确的身份运行,并已准备好创建快照。

创建快照

本部分介绍了如何手动触发正在运行的沙盒的快照。您需要创建一个以沙盒 Pod 为目标的触发器资源,然后验证快照流程是否成功完成。

  1. 查看初始计数器日志:在触发快照之前,查看正在运行的沙盒的日志,以了解当前计数器值。查看日志可建立一个基准,以便在恢复后进行比较。

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}" --tail=5
    

    输出会显示计数器的最后几行,例如:

    Count: 15
    Count: 16
    Count: 17
    

    请注意最后输出的几个“Count”值。

  2. 创建 PodSnapshotManualTrigger 资源:启动快照:

    kubectl apply -f - <<EOF
    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotManualTrigger
    metadata:
      name: cpu-snapshot-trigger
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      targetPod: ${SANDBOX_NAME}
    EOF
    
  3. 验证手动触发是否成功:

    kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    输出应显示状态为 Complete,表示 GKE 已成功触发目标 Pod 的快照:

    NAME                   TARGET POD                      STATUS     AGE
    cpu-snapshot-trigger   python-sandbox-warmpool-x7k2p   Complete   XXs
    
  4. 通过描述触发器查看有关捕获状态的更多详细信息:

    kubectl describe podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    输出包含一个 Snapshot Created 部分,其中包含存储在存储桶中的快照文件的唯一名称:

    Status:
      Conditions:
        Last Transition Time:  2026-01-30T19:11:04Z
        Message:               checkpoint completed successfully
        Reason:                Complete
        Status:                True
        Type:                  Triggered
      Observed Generation:     1
      Snapshot Created:
        Name:  <UNIQUE_SNAPSHOT_NAME>
    

使用快照进行恢复

截取快照后,您可以暂停沙盒以释放其计算资源,稍后可以从保存的状态恢复沙盒。当您暂停沙盒时,Agent Sandbox 控制器会删除沙盒的 Pod,但会保留 Sandbox 资源。当您恢复沙盒时,控制器会重新创建 Pod,并且 Pod 快照控制器会自动从该沙盒的最新快照中恢复 Pod。

  1. 等待快照准备就绪。GKE 仅从已准备就绪的快照恢复 Pod。如果您在快照准备就绪之前暂停沙盒,则沙盒在恢复时会启动,但不会加载已保存的状态。

    export SNAPSHOT_NAME=$(kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.snapshotCreated.name}')
    
    kubectl wait podsnapshots.podsnapshot.gke.io "${SNAPSHOT_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=600s
    
  2. 如需暂停沙盒,请将其 operatingMode 字段设置为 Suspended,然后等待控制器删除沙盒的 Pod:

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Suspended"}}'
    
    kubectl wait pod "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=delete \
      --timeout=120s
    
  3. 如需恢复沙盒,请将其 operatingMode 字段设置为 Running,然后等待沙盒准备就绪:

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Running"}}'
    
    kubectl wait sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
  4. 通过查看日志来验证恢复是否已完成。请注意,计数器会从拍摄快照的时间点继续计数:

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}"
    

    输出应显示计数器恢复,例如:

    Count: 18
    Count: 19
    Count: 20
    Count: 21
    

    如果计数器从 0 开始,则 Pod 在启动时未从快照恢复。

清理资源

为避免因本文档中使用的资源导致您的 Google Cloud 账号产生费用,请执行以下步骤来删除您创建的资源:

  1. 删除沙盒声明和温池,以停止所有正在运行的 Pod,并允许 Agent Sandbox 控制器正常终止容器。

    kubectl delete sandboxclaims --all --namespace "${SNAPSHOT_NAMESPACE}"
    kubectl delete sandboxwarmpools --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  2. 删除用于创建沙盒和启动快照的沙盒模板和手动触发器。

    # Delete the blueprints
    kubectl delete sandboxtemplates --all --namespace "${SNAPSHOT_NAMESPACE}"
    
    # Delete the snapshot initiation objects
    kubectl delete podsnapshotmanualtriggers --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  3. 删除快照政策,这些政策定义了命名空间中哪些 Pod 符合快照条件。

    kubectl delete podsnapshotpolicy cpu-psp --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. 删除快照存储配置,即快照存储后端的全局定义。由于此资源属于集群级范围,因此请勿使用命名空间标志。

    kubectl delete podsnapshotstorageconfig cpu-pssc-gcs
    
  5. 如果您为 Autopilot 创建了 ComputeClass,请将其删除。

    kubectl delete computeclass non-e2-class
    
  6. 删除 Kubernetes 命名空间,以自动移除 Kubernetes 服务账号和任何剩余的命名空间元数据。

    kubectl delete namespace "${SNAPSHOT_NAMESPACE}"
    
  7. 删除 GKE 集群,以移除底层基础架构以及与本教程关联的所有节点。

    Autopilot

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${GKE_LOCATION}" --quiet
    

    标准

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${ZONE}" --quiet
    
  8. 如果您想完全重置存储空间,请使用递归移除命令删除 Cloud Storage 存储桶(可选)。请注意,如果您打算在未来的测试中重复使用已正确配置的存储桶,则可以跳过此步骤。

    gcloud storage rm --recursive "gs://${SNAPSHOTS_BUCKET_NAME:?Error: SNAPSHOTS_BUCKET_NAME is not set. Please re-define the environment variables you defined earlier.}"
    
  9. 如果您想将项目恢复到完全干净的状态,请删除自定义 IAM 角色(可选)。由于 IAM 角色即使在集群被删除后也会保留,因此您必须单独删除它们。

    gcloud iam roles delete podSnapshotGcsReadWriter --project="${PROJECT_ID}"
    

后续步骤