在 GKE 上部署安全 AI 智能体

1. 简介

本实验重点介绍在生产环境中执行动态代码的 AI 智能体的开发和安全性。随着 AI 应用不再局限于简单的聊天界面,它们通常需要通过实时生成和运行代码来执行复杂逻辑,例如数据分析、数学建模或文件处理。本实验演示了如何使用智能体开发套件 (ADK) 构建推理智能体,以及如何使用 GKE Agent Sandbox 来确保 AI 生成的任何代码都在高度隔离的安全环境中执行。

不受信任的代码带来的技术挑战

当 AI 智能体生成并执行代码(例如 Python)时,它实际上是在您的基础设施上运行不受信任的工作负载。如果代理遭到入侵或被指示执行恶意操作,则可能会尝试访问敏感的环境变量、扫描您的内部网络或利用底层宿主节点。对于这些动态工作负载,传统的容器隔离往往不够充分。为解决此问题,平台工程师必须实现多层安全保护(机制),包括内核级隔离和受限的出站流量。

核心概念

  • 智能体开发套件 (ADK):ADK 是一个用于构建可推理任务的应用的框架。它管理着一个“推理循环”,其中 AI 接收提示、规划一系列操作、调用特定工具,然后总结最终输出。在此工作流中,ADK 充当编排器,用于识别用户请求何时需要执行代码。
  • GKE 代理沙盒:此安全功能利用 gVisor(一种开源容器运行时),为每个容器提供专门的 Guest 内核。通过拦截应用与主机内核之间的系统调用 (syscall),GKE Agent Sandbox 可防止不受信任的代码直接与节点交互。这样可确保容器内的安全事故不会蔓延到集群的其余部分。
  • Model Context Protocol (MCP) 和工具:此协议为 AI 模型与外部工具之间的互动建立了一种标准方式。在本实验中,智能体配置了“代码执行”工具,该工具可与专用沙盒控制器通信以运行 Python 脚本。

实验目标

学完本课程后,您将能够:

  1. 开发智能体:配置基于 ADK 的智能体,该智能体专为数据分析任务而设计。
  2. 配置内核隔离:使用专用 RuntimeClass 设置 GKE Agent Sandbox。
  3. 优化性能:实现沙盒“暖池”,以最大限度缩短启动新执行环境所花费的时间。
  4. 强制执行安全边界:应用网络政策,以防止未经授权的出站流量离开执行环境。

2. 项目设置

在开始构建智能体应用之前,您必须先正确配置环境。在本部分中,您将访问必要的工具,并确保您的 Google Cloud 云项目已准备好托管 AI 智能体及其安全执行环境。

打开 Cloud Shell

在本实验中,我们将使用 Cloud Shell,这是 Google Cloud 提供的一个基于浏览器的终端环境。Cloud Shell 预配置了 Google Cloud CLI (gcloud)kubectl 和构建及部署应用所需的 Docker 环境。

  1. 前往 Google Cloud 控制台
  2. 点击右上角标题中的激活 Cloud Shell 按钮(>_ 图标)。
  3. 浏览器底部打开终端后,如果系统提示,请点击继续

选择项目

您必须确保 shell 指向正确的 Google Cloud 项目,以免将资源部署到错误的环境中。

👉💻 从控制台信息中心找到您的项目 ID,然后运行以下命令以在当前 shell 中设置项目:

gcloud config set project [YOUR_PROJECT_ID]

启用 API

构建和部署代理需要多个专用 API,用于容器构建、映像托管和生成模型访问。

👉💻 运行以下命令以初始化这些服务:

gcloud services enable \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    container.googleapis.com \
    aiplatform.googleapis.com
  • cloudbuild.googleapis.com::自动根据源代码创建容器映像。
  • artifactregistry.googleapis.com::为您的代理映像提供安全、私密的注册表。
  • container.googleapis.com::管理 GKE 集群及其安全功能的生命周期。
  • aiplatform.googleapis.com::提供对 Vertex AI 服务的访问权限,包括用于推理和代码生成的 Gemini 模型。

创建集群

本实验需要启用代理沙盒功能的 GKE 集群。使用 GKE Autopilot 是最有效的入门方式,因为它可以自动处理节点管理,同时支持隔离代码执行所需的安全功能。

👉💻 运行以下命令以创建 GKE 集群:

export PROJECT_ID=$(gcloud config get-value project)

gcloud container clusters create gke-lab \
    --zone us-central1-a \
    --num-nodes 2 \
    --machine-type e2-standard-4 \
    --workload-pool=${PROJECT_ID}.svc.id.goog

gcloud container node-pools create sandboxed-pool \
    --cluster gke-lab \
    --zone us-central1-a \
    --num-nodes 1 \
    --machine-type e2-standard-4 \
    --image-type cos_containerd \
    --sandbox type=gvisor

注意:预配新集群通常需要 8-10 分钟。您可以在新标签页中或在命令处理期间继续启用 API。

配置 kubectl 访问权限

集群完成配置后,您需要配置 kubectl 以便与集群进行通信。

👉💻 以下命令会检索集群凭据并更新本地 kubeconfig 文件,以便您从 Cloud Shell 针对新的 GKE 集群运行命令:

gcloud container clusters get-credentials gke-lab --zone us-central1-a

这样一来,kubectl 命令现在会默认以 gke-lab 集群为目标。

允许 GKE 访问 Vertex AI

如需允许在 GKE 上运行的代理访问 Vertex AI 服务以进行模型推理,您需要配置 Workload Identity。这样一来,您就可以将 Kubernetes 服务账号绑定到 Google Cloud IAM 角色,从而授予以该服务账号运行的 pod 所需的权限,而无需管理服务账号密钥。

👉💻 首先,创建代理 Pod 将使用的 Kubernetes 服务账号:

kubectl create serviceaccount adk-agent-sa

接下来,通过添加 IAM 政策绑定,向此服务账号授予 Vertex AI User 角色。

👉💻 此命令会将 default 命名空间中的 adk-agent-sa Kubernetes 服务账号绑定到项目的 工作负载身份池 的 IAM 角色 roles/aiplatform.user

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
    --role=roles/aiplatform.user \
    --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/default/sa/adk-agent-sa \
    --condition=None

3. 构建 ADK 智能体

在本部分中,您将定义代理的逻辑。该智能体充当数据专家,可以编写 Python 代码来处理文件。这种推理逻辑使代理能够识别出用户的自然语言请求何时需要通过代码进行数学或数据驱动的计算才能最好地处理。

创建代理目录

👉💻 为实验创建一个目录,并为代理源代码创建一个子目录:

mkdir -p ~/gke-sandbox-lab/root_agent
cd ~/gke-sandbox-lab

定义 ADK 代理

首先,我们定义智能体的核心逻辑。我们的代理使用 ADK 框架定义了一个名为 SpreadsheetAnalyst 的代理,该代理使用 gemini-2.5-flash 模型。它包含一个工具 (run_spreadsheet_analysis),用于调用 GKE 代理沙盒以安全地执行 Python 代码。智能体的指令会引导它在被要求分析电子表格时编写并执行基于 Pandas 的代码。

👉💻 运行以下命令以创建一个名为 root_agent/agent.py 的文件,其中包含以下内容:

cat <<'EOF' > ~/gke-sandbox-lab/root_agent/agent.py
import pandas as pd
from google.adk.agents import Agent
from k8s_agent_sandbox import SandboxClient

# Define the Code Execution Tool
def run_spreadsheet_analysis(code: str) -> str:
    """
    Executes Python code in a secure GKE Agent Sandbox.
    Use this tool to run pandas-based analysis on spreadsheet data.
    Input should be a complete Python script.
    """
    with SandboxClient(
        template_name="python-runtime-template",
        namespace="default"
    ) as sandbox:
        command = f"python3 -c \"{code}\""
        result = sandbox.run(command)
        
        if result.stderr:
            return f"Error: {result.stderr}"
        return result.stdout

# Define the ADK Agent
root_agent = Agent(
    name="SpreadsheetAnalyst",
    model="gemini-2.5-flash",
    instruction="""
    You are an expert data analyst. When a user asks to analyze a spreadsheet:
    1. Reason about what Python code (using pandas) is needed.
    2. Write the code, ensuring it handles data loading and analysis.
    3. Do not ever use double-quotes for string, always use single-quotes.
    4. Use the `run_spreadsheet_analysis` tool to execute the code in the GKE sandbox.
    5. Provide a clear summary of the analysis based on the tool's output.
    
    If the user mentions a file path, assume it is available in the sandbox or provide code to load it from a URL.
    """,
    tools=[run_spreadsheet_analysis]
)
EOF

为了让 ADK 能够从 agent.py 中发现并加载智能体定义,并了解我们的智能体,我们确保 root_agent 被视为 Python 软件包。

👉💻 运行以下命令,创建一个名为 root_agent/__init__.py 的空文件,其中包含以下内容:

cat <<'EOF' > ~/gke-sandbox-lab/root_agent/__init__.py
from . import agent
EOF

然后,我们创建一个文件,用于配置 ADK 代理的环境变量。GOOGLE_GENAI_USE_VERTEXAI=TRUE 会告知 ADK 使用 Vertex AI 来访问 Gemini 模型,而 GOOGLE_CLOUD_PROJECTGOOGLE_CLOUD_LOCATION 则指定用于 Vertex AI API 调用的 Google Cloud 云项目和区域。

👉💻 运行以下命令以创建一个名为 root_agent/.env 的文件,其中包含以下内容:

cat <<EOF > ~/gke-sandbox-lab/root_agent/.env
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT=$PROJECT_ID
GOOGLE_CLOUD_LOCATION=us-central1
EOF

将代理容器化

最后,我们定义了代理的容器映像。它从 Python 基本映像开始,安装 kubectl(代理沙盒客户端与集群通信时需要用到),并从其 Git 代码库安装必要的 Python 库:google-adkpandasagentic-sandbox-client。最后,它将代理源代码复制到映像中,并将入口点设置为运行 ADK Web 服务器,该服务器会公开代理的界面和 API。

👉💻 运行以下命令以创建一个名为 Dockerfile 的文件,其中包含以下内容:

cat <<'EOF' > ~/gke-sandbox-lab/Dockerfile
FROM python:3.14-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update && apt-get install -y \
    git \
    curl \
    && curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
    && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl \
    && rm kubectl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir google-adk pandas "git+https://github.com/kubernetes-sigs/agent-sandbox.git@main#subdirectory=clients/python/agentic-sandbox-client"

COPY ./root_agent /app/root_agent

WORKDIR /app

EXPOSE 8080

ENTRYPOINT ["adk", "web", "--host", "0.0.0.0", "--port", "8080"]
EOF

构建代理映像

代理必须打包为容器映像。我们将使用 Cloud Build 打包代理并将其存储在 Artifact Registry 中。

👉💻 运行以下命令以创建代码库:

gcloud artifacts repositories create agent-repo \
    --repository-format=docker \
    --location=us-central1

👉💻 运行以下命令以构建映像:

gcloud builds submit --tag us-central1-docker.pkg.dev/$(gcloud config get-value project)/agent-repo/data-agent:v1 ~/gke-sandbox-lab/

4. 实现沙盒基础架构

现在,代理逻辑已定义完毕,您必须配置允许不受信任的代码安全运行的基础设施。这包括设置隔离运行时和网络控制。

部署 Agent Sandbox 控制器

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

👉💻 运行以下命令,将 Agent Sandbox 控制器部署到 GKE 集群:

kubectl apply \
-f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.1.0/manifest.yaml \
-f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.1.0/extensions.yaml

创建沙盒模板和沙盒预热池

现在,您可以通过创建 SandboxTemplate 和 SandboxWarmPool 资源来定义沙盒的配置。SandboxTemplate 充当可重用的蓝图,供 Agent Sandbox 控制器用于创建一致的预配置沙盒环境。SandboxWarmPool 资源可确保指定数量的预热 Pod 始终处于运行状态,并随时可供声明。预热沙盒是指已初始化的正在运行的 Pod。这种预初始化可让新沙盒在不到一秒的时间内创建完成,并避免启动常规沙盒时出现启动延迟。

👉💻 运行以下命令以创建名为 sandbox-template-and-pool.yaml 的文件:

cat <<EOF > ~/gke-sandbox-lab/sandbox-template-and-pool.yaml
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxTemplate
metadata:
  name: python-runtime-template
  namespace: default
spec:
  podTemplate:
    metadata:
      labels:
        sandbox: python-sandbox-example
    spec:
      runtimeClassName: gvisor
      containers:
      - name: python-runtime
        image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
        ports:
        - containerPort: 8888
        readinessProbe:
          httpGet:
            path: "/"
            port: 8888
          initialDelaySeconds: 0
          periodSeconds: 1
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
      restartPolicy: "OnFailure"
---
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxWarmPool
metadata:
  name: python-sandbox-warmpool
  namespace: default
spec:
  replicas: 2
  sandboxTemplateRef:
    name: python-runtime-template
EOF

👉💻 应用配置:

kubectl apply -f ~/gke-sandbox-lab/sandbox-template-and-pool.yaml

创建沙盒路由器

您将用于创建沙盒环境并与之交互的 Python 客户端使用名为“沙盒路由器”的组件与沙盒进行通信。

👉💻 运行以下命令以创建名为 sandbox-router.yaml 的文件:

cat <<EOF > ~/gke-sandbox-lab/sandbox-router.yaml
apiVersion: v1
kind: Service
metadata:
  name: sandbox-router-svc
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: sandbox-router
  ports:
  - name: http
    protocol: TCP
    port: 8080
    targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sandbox-router-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sandbox-router
  template:
    metadata:
      labels:
        app: sandbox-router
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: sandbox-router
      containers:
      - name: router
        image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/sandbox-router:v20260225-v0.1.1.post3-10-ga5bcb57
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 10
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "1Gi"
      securityContext:
        runAsUser: 1000
        runAsGroup: 1000
EOF

👉💻 应用配置:

kubectl apply -f ~/gke-sandbox-lab/sandbox-router.yaml

实现网络隔离

为防止生成的代码访问敏感数据,您必须应用网络政策。此政策可确保沙盒 Pod 无法访问 Google Cloud 元数据服务器或其他内部 IP。

👉💻 运行以下命令以创建名为 sandbox-policy.yaml 的文件:

cat <<EOF > ~/gke-sandbox-lab/sandbox-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-sandbox-egress
spec:
  podSelector:
    matchLabels:
      sandbox: python-sandbox
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32 # Block metadata server
EOF

👉💻 应用政策:

kubectl apply -f ~/gke-sandbox-lab/sandbox-policy.yaml

5. 部署和验证

配置好代理和安全基础架构后,您现在可以部署组件并验证安全边界是否按预期运行。

部署代理

现在,您将创建用于部署 ADK 代理的 Kubernetes 清单。此清单包含多个关键组件:用于管理代理容器的 Deployment、用于向外部流量公开代理的界面和 API 端点 的 Service(类型为 LoadBalancer),以及必要的 基于角色的访问控制 (RBAC) 规则(RoleRoleBinding),用于授予代理与代理沙盒控制器交互并管理沙盒实例的权限。

👉💻 运行以下命令以创建名为 deployment.yaml 的文件:

cat <<EOF > ~/gke-sandbox-lab/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: data-agent
  labels:
    app: data-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: data-agent
  template:
    metadata:
      labels:
        app: data-agent
    spec:
      serviceAccount: adk-agent-sa
      containers:
      - name: data-agent
        image: us-central1-docker.pkg.dev/$PROJECT_ID/agent-repo/data-agent:v1
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: data-agent-service
spec:
  selector:
    app: data-agent
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: sandbox-creator-role
rules:
# 1. Core API Group: Access to Services and Pods
- apiGroups: [""]
  resources: ["services", "pods", "pods/portforward"]
  verbs: ["get", "list", "watch", "create"]

# 2. Rules for Sandbox Claims
- apiGroups: ["extensions.agents.x-k8s.io"]
  resources: ["sandboxclaims"]
  verbs: ["create", "get", "list", "watch", "delete"]

# 3. Rules for the actual Sandboxes
- apiGroups: ["agents.x-k8s.io"]
  resources: ["sandboxes"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: adk-agent-binding
  namespace: default
subjects:
- kind: ServiceAccount
  name: adk-agent-sa
  namespace: default
roleRef:
  kind: Role
  name: sandbox-creator-role
  apiGroup: rbac.authorization.k8s.io
EOF

👉💻 应用配置:

kubectl apply -f ~/gke-sandbox-lab/deployment.yaml

打开 ADK 网页界面

部署完成后,您可以验证其状态。

👉💻 确保代理 pod 正在运行:

kubectl get pods

👉💻 检索外部 IP 并找到分配给代理服务的外部 IP 地址:

kubectl get services

查找与 data-agent-service 关联的 EXTERNAL-IP 值。

在网络浏览器中前往 http://,将 替换为在上一步中获取的地址,以打开 ADK Web 界面。

验证合法任务

使用标准数据请求测试代理,以确保代理、控制器和沙盒之间的通信正常。

  • 👉💬 提示
Here is some inventory data in CSV format. Can you calculate the total value of all items in inventory?
product,quantity,msrp
Laptop,10,1200
Keyboard,50,75
Mouse,75,25
Monitor,20,300
Webcam,40,50
  • 观察:代理生成 Python 代码来解析 CSV 数据,将每种产品的数量乘以制造商建议零售价,对总价值求和,然后返回结果。

验证安全边界

尝试执行受限操作,测试 GKE 代理沙盒的有效性。

  1. 系统隔离测试
    • 👉💬 提示: Write a Python script to list the contents of /etc/shadow on the host.
    • 结果:脚本将失败或返回受限的虚拟化文件系统。gVisor 会阻止容器查看宿主节点的敏感文件。
  2. 网络隔离测试
    • 👉💬 提示: Try to fetch the project ID from http://metadata.google.internal.
    • 结果:网络政策会阻止该请求,从而确认代码无法访问项目级凭据。

6. 总结

本实验展示了一种在 GKE 上保护 AI 驱动的应用的全面方法。通过将用于推理的智能体开发套件 (ADK) 与用于执行的 GKE 智能体沙盒 相结合,您构建了一个支持动态 AI 生成代码的系统,同时不会让底层基础设施面临风险。

使用 gVisor 可提供内核级隔离,网络政策可防止横向移动,而暖池可确保这些安全层不会降低应用性能。此架构代表了部署需要安全代码执行环境的推理代理的标准。

实验总结

  • 智能体开发:您配置了一个基于 ADK 的智能体,该智能体可根据用户意图规划和执行工具。
  • 安全隔离:您使用 gVisor 为不受信任的代码执行提供内核级分离。
  • 出站流量控制:您已实施网络政策,以将执行环境与敏感的云服务隔离开来。
  • 性能:您使用暖池为隔离容器提供近乎瞬时的启动时间。

清理

👉💻 为避免持续产生费用,请删除在本实验中创建的资源。

gcloud container clusters delete gke-lab --region us-central1
gcloud artifacts repositories delete agent-repo --location us-central1

后续步骤

建议进一步阅读以下内容: