在 GKE 上启用 Agent Sandbox

本文档介绍了如何在 Google Kubernetes Engine (GKE) 集群中启用 Agent Sandbox 功能。还介绍了如何在集群上创建沙盒环境,以便安全地执行不受信任的代码。

如需大致了解 Agent Sandbox 功能如何隔离不受信任的 AI 生成的代码,请参阅 GKE Agent Sandbox 简介

费用

在 GKE 中,使用 Agent Sandbox 无需额外付费。 GKE 定价适用于您创建的资源。

为避免产生不必要的费用,请务必在完成本文档后停用 GKE 或删除项目。

准备工作

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

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

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

    转到“项目选择器”

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

  3. 启用 Artifact Registry API 和 Google Kubernetes Engine API。

    启用 API 所需的角色

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

    启用 API

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

    激活 Cloud Shell

  5. 确保您的集群运行的是 GKE 1.36.3-gke.1767000 版或更高版本(支持 v1beta1 API)。

定义环境变量

为了简化您在本文档中运行的命令,您可以在 Cloud Shell 中设置环境变量。在 Cloud Shell 中,运行以下命令来定义以下有用的环境变量:

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export LOCATION="us-central1"
export CLUSTER_VERSION="1.36.3-gke.1767000"
export NODE_POOL_NAME="agent-sandbox-pool"
export MACHINE_TYPE="e2-standard-2"

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

  • PROJECT_ID:当前 Google Cloud 项目的 ID。定义此变量有助于确保所有资源(例如 GKE 集群)都在正确的项目中创建。
  • CLUSTER_NAME:GKE 集群的名称,例如 agent-sandbox-cluster
  • LOCATION:创建 GKE 集群的 Google Cloud 区域或可用区。如果您创建的是 Autopilot 集群,请将此值设置为区域(例如 us-central1);如果您创建的是 Standard 集群,请将此值设置为可用区(例如 us-central1-a)。
  • CLUSTER_VERSION:集群将运行的 GKE 版本(1.36.3-gke.1767000 或更高版本)。
  • NODE_POOL_NAME:将运行沙盒化工作负载的节点池的名称,例如 agent-sandbox-pool。只有在创建 GKE Standard 集群时,才需要此变量。
  • MACHINE_TYPE:节点池中节点的机器类型,例如 e2-standard-2。如需详细了解不同的机器系列以及如何在不同选项之间进行选择,请参阅机器家族资源和比较指南。 只有在创建 GKE Standard 集群时,才需要此变量。

启用 Agent Sandbox

您可以在创建新集群或更新现有集群时启用 Agent 沙盒功能。

在创建新的 GKE 集群时启用 Agent Sandbox

我们建议您使用 Autopilot 集群获得全代管式 Kubernetes 体验。如需选择最适合您的工作负载的 GKE 操作模式,请参阅选择 GKE 操作模式

Autopilot

如需创建已启用 Agent Sandbox 的新 GKE Autopilot 集群,请添加 --enable-agent-sandbox 标志:

gcloud beta container clusters create-auto ${CLUSTER_NAME} \
    --location=${LOCATION} \
    --cluster-version=${CLUSTER_VERSION} \
    --enable-agent-sandbox

对于 Autopilot 集群,请确保 LOCATION 环境变量设置为某个区域(例如 us-central1)。

标准

如需创建已启用 Agent Sandbox 的新 GKE Standard 集群,您必须先创建集群,然后添加已启用 gVisor 的节点池,最后启用 Agent Sandbox 功能。为了节省费用,我们建议您创建一个可用区级集群,每个节点池中包含一个节点:

  1. 创建集群:

    gcloud beta container clusters create ${CLUSTER_NAME} \
        --location=${LOCATION} \
        --num-nodes=1 \
        --cluster-version=${CLUSTER_VERSION}
    

    对于此标准集群,请确保 LOCATION 环境变量设置为某个可用区(例如 us-central1-a)。

  2. 创建单独的节点池并启用 gVisor:

    gcloud container node-pools create ${NODE_POOL_NAME} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=${MACHINE_TYPE} \
        --location=${LOCATION} \
        --num-nodes=1 \
        --image-type=cos_containerd \
        --sandbox=type=gvisor
    

    LOCATION 必须与您创建集群时使用的可用区相同。

  3. 更新集群以启用 Agent Sandbox 功能:

    gcloud beta container clusters update ${CLUSTER_NAME} \
        --location=${LOCATION} \
        --enable-agent-sandbox
    

在更新现有 GKE 集群时启用 Agent Sandbox

如需在现有集群上启用 Agent Sandbox,集群必须运行 1.36.3-gke.1767000 版或更高版本,该版本支持 v1beta1 API。

确保将 LOCATION 环境变量设置为现有集群所在的区域或可用区。

  1. 如果您使用的是 GKE Standard 集群,则 Agent Sandbox 依赖于 gVisor。如果您的 Standard 集群没有启用 gVisor 的节点池,您必须先创建一个:

    gcloud container node-pools create ${NODE_POOL_NAME} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=${MACHINE_TYPE} \
        --location=${LOCATION} \
        --image-type=cos_containerd \
        --sandbox=type=gvisor
    
  2. 更新集群以启用 Agent Sandbox 功能:

    gcloud beta container clusters update ${CLUSTER_NAME} \
        --location=${LOCATION} \
        --enable-agent-sandbox
    

验证配置

您可以通过检查集群说明来验证 Agent Sandbox 功能是否已启用。

gcloud beta container clusters describe ${CLUSTER_NAME} \
    --location=${LOCATION} \
    --format="value(addonsConfig.agentSandboxConfig.enabled)"

如果您创建的是 Autopilot 集群,则位置是区域(例如 us-central1)。如果您创建的是 Standard 集群,则位置是可用区(例如 us-central1-a)。

如果成功启用该功能,该命令会返回 True

Agent Sandbox 部署要求

如需成功部署工作负载(例如 SandboxSandboxTemplate),您的 YAML 清单必须包含特定的安全和配置设置。GKE 使用验证准入政策 (VAP) 来强制执行这些要求。如果不满足这些要求,准入控制器会拒绝部署。

所需的配置

您的部署清单必须包含以下设置:

  • runtimeClassName: gvisor:确保 Pod 在 gVisor 沙盒中运行。
  • automountServiceAccountToken: false:防止 Pod 自动装载默认服务账号令牌。
  • securityContext.runAsNonRoot: true:确保容器不会以根用户身份运行。
  • securityContext.capabilities.drop: ["ALL"]:从容器中舍弃所有 Linux 功能。
  • resources.limits:您必须指定 CPU 和内存限制,以防出现潜在的拒绝服务 (DoS) 场景。
  • nodeSelector:必须以 sandbox.gke.io/runtime: gvisor 为目标平台。
  • tolerations:必须包含对 sandbox.gke.io/runtime=gvisor:NoSchedule 污点的容忍。

禁止的配置

您的部署清单不得包含以下任何内容:

  • hostNetwork: truehostPID: truehostIPC: true
  • privileged: true 在容器安全上下文中使用。
  • HostPath 卷。
  • 添加了功能 (capabilities.add)。
  • hostPort 设置。
  • 自定义 sysctl。
  • 服务账号令牌或证书的预计数量。

部署沙盒环境

我们建议您通过定义 SandboxTemplate 并使用 SandboxWarmPool 保持预热实例就绪来部署沙盒环境。然后,您可以使用 SandboxClaim 从此暖节点池请求实例。或者,您也可以直接创建沙盒,但此方法不支持暖池。

SandboxTemplate、SandboxWarmPool、SandboxClaim 和 Sandbox 是 Kubernetes 自定义资源

SandboxTemplate 充当可重用的蓝图。SandboxWarmPool 可帮助确保指定数量的预热 Pod 始终处于运行状态,并随时可供声明。使用此自定义资源可最大限度地缩短启动延迟时间。

如需通过创建 SandboxTemplate 和 SandboxWarmPool 来部署沙盒环境,请完成以下步骤:

  1. 在 Cloud Shell 中,创建一个名为 sandbox-template.yaml 的文件,其中包含以下内容:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: default
    spec:
      podTemplate:
        metadata:
          labels:
            sandbox-type: python-runtime
        spec:
          runtimeClassName: gvisor # Required
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: runtime
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            resources:
              requests:
                cpu: "250m"
                memory: "512Mi"
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          restartPolicy: OnFailure
    
  2. 应用 SandboxTemplate 清单:

    kubectl apply -f sandbox-template.yaml
    
  3. 创建一个名为 sandbox-warmpool.yaml 的文件,其中包含以下内容:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: python-runtime-warmpool
      namespace: default
      labels:
        app: python-runtime-warmpool
    spec:
      replicas: 2
      sandboxTemplateRef:
        # This must match the name of the SandboxTemplate.
        name: python-runtime-template
    
  4. 应用 SandboxWarmPool 清单:

    kubectl apply -f sandbox-warmpool.yaml
    

创建 SandboxClaim

SandboxClaim 从暖池请求沙盒。由于您创建了暖池,因此创建的沙盒会采用池中的正在运行的 Pod,而不是启动全新的 Pod。

如需通过创建 SandboxClaim 从温池请求沙盒,请完成以下步骤:

  1. 创建一个名为 sandbox-claim.yaml 的文件,其中包含以下内容:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxClaim
    metadata:
      name: sandbox-claim
      namespace: default
    spec:
      warmPoolRef:
        # This must match the name of the SandboxWarmPool.
        name: python-runtime-warmpool
    
  2. 应用 SandboxClaim 清单:

    kubectl apply -f sandbox-claim.yaml
    
  3. 验证沙盒、声明和预热池是否已准备就绪:

    kubectl get sandboxwarmpool,sandboxclaim,sandbox,pod
    

替代方案:直接创建沙盒

如果您不需要暖池提供的快速启动时间,可以直接部署沙盒,而无需使用模板。

如需通过直接创建 Sandbox 来部署沙盒环境,请完成以下步骤:

  1. 创建一个名为 sandbox.yaml 的文件,其中包含以下内容:

    apiVersion: agents.x-k8s.io/v1beta1
    kind: Sandbox
    metadata:
      name: sandbox-example-2
    spec:
      replicas: 1
      podTemplate:
        metadata:
          labels:
            sandbox: sandbox-example
        spec:
          runtimeClassName: gvisor
          restartPolicy: OnFailure
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
            runAsUser: 1000 # Required if image defaults to root (e.g. busybox)
          nodeSelector:
            sandbox.gke.io/runtime: gvisor
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: my-container
            image: busybox
            command: ["/bin/sh", "-c"]
            args: ["sleep 3600000; echo 'Container finished successfully'; exit 0"]
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
              allowPrivilegeEscalation: false
            resources:
              limits:
                cpu: "100m"
                memory: "128Mi" # Required
    
  2. 应用 Sandbox 清单:

    kubectl apply -f sandbox.yaml
    
  3. 验证沙盒是否正在运行:

    kubectl get sandbox
    

将 Agent Sandbox 从 v1alpha1 迁移到 v1beta1

如果您的集群是使用 v1alpha1 自定义资源部署的早期版本的 Agent Sandbox,则可以升级到 GKE 版本 1.36.3-gke.1767000 或更高版本,并实现近乎零的工作负载停机时间

注意:此迁移程序适用于使用受管理的 GKE Agent Sandbox 功能 (--enable-agent-sandbox) 的集群。如果您使用开源清单部署了 Agent Sandbox,请参阅上游迁移指南

v1alpha1v1beta1 之间的主要 API 差异

概念 v1alpha1 行为 v1beta1 行为 迁移影响
SandboxClaim 目标 允许直接引用 SandboxTemplate,而无需预热池(冷启动)。 需要SandboxWarmPool (spec.warmPoolRef.name) 的引用。 冷启动声明必须映射到影子暖池 (replicas: 0)。
沙盒运行模式 从副本或状态字段推断得出。 spec.operatingMode 字段的显式值(例如 RunningSuspended)。 转化 Webhook 会自动映射并设置此字段。
CustomResourceDefinition 存储版本 v1alpha1 存储在 etcd 中 (storage: true)。 v1beta1 存储在 etcd 中 (storage: true)。 Webhook 动态转换;升级后步骤会重新持久化 etcd 对象。
转化 webhook 无。 /convert 上激活(端口 9447)。 v1alpha1v1beta1 之间的双向转换。

使用迁移工具进行迁移

如需自动创建影子暖池并重新保留存储空间,请使用 Agent Sandbox 代码库中的规范迁移脚本。

下载并准备脚本:

curl -LO https://raw.githubusercontent.com/kubernetes-sigs/agent-sandbox/v0.5.6/helm/files/migrate.sh
chmod +x migrate.sh

分步迁移运行手册

如需迁移现有集群,同时尽可能减少工作负载停机时间,请按顺序完成以下三个阶段:

阶段 1:升级前引导阶段

  1. 备份现有资源:保存声明式代理沙盒资源(sandboxtemplatessandboxwarmpoolssandboxclaims)的 YAML 备份:

    kubectl get sandboxtemplates,sandboxwarmpools,sandboxclaims \
        --all-namespaces -o yaml > agent-sandbox-v1alpha1-backup.yaml
    
  2. 验证模板安全合规性:确保现有 SandboxTemplate 资源符合 Agent 沙盒部署要求。在第 3 阶段的存储迁移期间,准入控制器会拒绝更新任何不符合这些安全政策的模板。

  3. 预览将创建的影子池:

    ./migrate.sh --phase=bootstrap --dry-run
    
  4. 执行引导阶段:

    ./migrate.sh --phase=bootstrap
    
  5. 验证创建的影子池:

    kubectl get sandboxwarmpools --all-namespaces \
        -o custom-columns="NAMESPACE:.metadata.namespace,NAME:.metadata.name,REPLICAS:.spec.replicas,SHADOW:.metadata.annotations.agents\.x-k8s\.io/migration-shadow"
    

第 2 阶段:升级 GKE 控制平面

将 GKE 控制平面升级到 1.36.3-gke.1767000 或更高版本:

gcloud container clusters upgrade ${CLUSTER_NAME} \
    --location=${LOCATION} \
    --master \
    --cluster-version=1.36.3-gke.1767000

在控制平面推出期间,请注意以下事项:

  • Pod 不会重启或停机
  • 新的控制器和 /convert webhook 端点部署在控制平面上。

第 3 阶段:升级后存储空间迁移

控制平面升级完成后,请刷新凭据,并通过运行存储迁移阶段来重写存储的 etcd 对象:

./migrate.sh --phase=migrate

迁移后验证核对清单

划掉商品 命令 预期结果
CustomResourceDefinition 存储版本 kubectl get crd sandboxes.agents.x-k8s.io sandboxclaims.extensions.agents.x-k8s.io sandboxtemplates.extensions.agents.x-k8s.io sandboxwarmpools.extensions.agents.x-k8s.io -o jsonpath='{range .items[*]}{.metadata.name}{": storedVersions="}{.status.storedVersions}{"\n"}{end}' 所有 4 个 CustomResourceDefinition 显示:
storedVersions=["v1beta1"]
广告连播连续性 kubectl get pods -n default -o wide Status: 1/1 Running
Restarts: 0
(适用于有正在运行的活跃沙盒的集群)
声明绑定 kubectl get sandboxclaims -n default -o yaml spec.warmPoolRef.name: shadow-pool-...
status.conditions: Ready=True(要求模板符合入学要求)
v1alpha1 兼容性 kubectl get sandboxes.v1alpha1.agents.x-k8s.io 显示弃用警告并返回资源
v1beta1 原生 CRUD kubectl apply -f sandbox-claim.yaml 应用,但未收到警告

如果 CustomResourceDefinition 在迁移阶段完成后继续在 .status.storedVersions 中列出 ["v1alpha1", "v1beta1"],这是预期的 Kubernetes 行为。迁移脚本会将所有现有记录重写为 etcd 中的 v1beta1,但 Kubernetes 不会自动从 status.storedVersions 列表中移除已弃用的版本。

确认所有资源均已迁移后,您可以选择从存储的版本中剪除 v1alpha1

for crd in \
    sandboxes.agents.x-k8s.io \
    sandboxclaims.extensions.agents.x-k8s.io \
    sandboxtemplates.extensions.agents.x-k8s.io \
    sandboxwarmpools.extensions.agents.x-k8s.io; do
  kubectl patch crd "${crd}" --subresource=status --type=merge \
    -p '{"status":{"storedVersions":["v1beta1"]}}'
done

排查迁移问题

如果您在升级控制平面或运行存储迁移后遇到问题,请向前解决这些问题,而不是尝试降级控制平面:

  • 声明卡在 WarmPoolNotFound

    • 如果冷启动 v1alpha1 声明在未运行 ./migrate.sh --phase=bootstrap 的情况下升级,请手动创建缺少的影子温池:

      apiVersion: extensions.agents.x-k8s.io/v1beta1
      kind: SandboxWarmPool
      metadata:
        name: shadow-pool-TEMPLATE_NAME
        namespace: NAMESPACE
        annotations:
          agents.x-k8s.io/migration-shadow: "true"
      spec:
        replicas: 0
        sandboxTemplateRef:
          name: TEMPLATE_NAME
      
    • 如果声明指定了不再存在的特定暖池,请创建具有该名称的缺失 SandboxWarmPool 资源,或更新声明中的 spec.warmPoolRef.name 以引用现有暖池。

  • 声明条件 Ready=False:运行 kubectl describe sandboxclaim 以检查声明中的事件。确保所引用的 SandboxTemplate 满足所有 Agent Sandbox 部署要求,并根据需要重新应用模板。

  • 转化或控制器错误:运行 kubectl get leases -n gke-managed-agentsandbox,验证控制平面领导者选举租约是否处于有效状态。如果问题仍然存在,请与 Cloud Customer Care 联系。

停用 Agent Sandbox

如需停用代理沙盒功能,请将 gcloud beta container clusters update 命令与 --no-enable-agent-sandbox 标志结合使用。

gcloud beta container clusters update ${CLUSTER_NAME} \
    --location=${LOCATION} \
    --no-enable-agent-sandbox

如果您创建的是 Autopilot 集群,则位置是区域(例如 us-central1)。如果您创建的是 Standard 集群,则位置是可用区(例如 us-central1-a)。

清理资源

为避免系统向您的 Google Cloud 账号收取费用,请删除您创建的 GKE 集群。

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

如果您创建的是 Autopilot 集群,则位置是区域(例如 us-central1)。如果您创建的是 Standard 集群,则位置是可用区(例如 us-central1-a)。

后续步骤