利用 GKE Sandbox 强化工作负载隔离


本页面介绍如何在 Pod 中的容器执行未知代码或不可信代码,或者在需要与节点的额外隔离时,使用 GKE Sandbox 保护节点上的主机内核。

GKE Sandbox 可用性

GKE Sandbox 可在运行 GKE 1.27.4-gke.800 及更高版本的 Autopilot 集群中使用。如需开始在沙盒中部署 Autopilot 工作负载,请跳转至使用 GKE Sandbox

如需在新的或现有的 GKE Standard 集群中使用 GKE Sandbox,您必须在集群上手动启用 GKE Sandbox。

1.29.2-gke.11080000 及更高版本的 GKE Sandbox 支持 GPU 工作负载。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

在新的标准集群上启用 GKE Sandbox

默认节点池是在您创建新集群时创建的,如果它是集群中唯一的节点池,则不能使用 GKE Sandbox,因为 GKE 管理的系统工作负载必须与不受信任的沙盒工作负载分开运行。要在集群创建期间启用 GKE Sandbox,您必须向集群添加至少一个额外的节点池。

控制台

要查看集群,请访问 Google Cloud 控制台中的 Google Kubernetes Engine 菜单。

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. 可选但建议执行的操作:在导航菜单中的集群下,点击功能,然后选中以下复选框,以便系统记录 gVisor 消息:

    • Cloud Logging
    • Cloud Monitoring
    • Managed Service for Prometheus
  4. 点击 添加节点池

  5. 在导航菜单中的节点池下,展开新的节点池,然后点击节点

  6. 为节点池配置以下设置:

    1. 映像类型下拉列表中,选择包含 Containerd 的 Container-Optimized OS (cos_containerd)。 这是 GKE Sandbox 唯一支持的映像类型。
    2. 机器配置下,选择系列机器类型
    3. (可选)如果您运行的是支持的 GKE 版本,请选择 GPU 类型。此项必须是以下类型之一:
      • nvidia-tesla-t4
      • nvidia-tesla-a100
      • nvidia-a100-80gb
      • nvidia-l4
      • nvidia-h100-80gb
    4. 如果在 GKE Sandbox 上使用 GPU,请选择或安装 latest 驱动程序变体。
  7. 在导航菜单中您要配置的节点池的名称下,点击安全,然后选中启用 gVisor 沙盒复选框。

  8. 根据需要继续配置集群和节点池。

  9. 点击创建

gcloud

无法为默认节点池启用 GKE Sandbox,而且无法在使用 gcloud 命令创建新集群时创建其他节点池。但是,您可按照通常的方式创建集群。虽然并非必需,但建议您启用 Logging 和 Monitoring,以便记录 gVisor 消息。

然后使用 gcloud container node-pools create 命令,并将 -- sandbox 标志设置为 type=gvisor。GKE Sandbox 的节点映像类型必须为 cos_containerd

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --node-version=NODE_VERSION \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

执行以下变量替换操作:

  • NODE_POOL_NAME:新节点池的名称。
  • CLUSTER_NAME:您的集群的名称。
  • NODE_VERSION:用于节点池的版本。
  • MACHINE_TYPE:用于节点的机器类型

如需创建使用 GKE Sandbox 的 GPU 节点池,请运行以下命令:

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --node-version=NODE_VERSION \
  --machine-type=MACHINE_TYPE \
  --accelerator=type=GPU_TYPE,gpu-driver-version=latest \
  --image-type=cos_containerd \
  --sandbox type=gvisor

替换以下内容:

在现有 Standard 集群上启用 GKE Sandbox

您可以通过添加新节点池并为其启用该功能,在现有 Standard 集群上启用 GKE Sandbox。

控制台

如需创建已启用 GKE Sandbox 的新节点池,请执行以下操作:

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击要修改的集群的名称。

  3. 点击 添加节点池

  4. 根据选择配置节点池详情页面。

  5. 在导航菜单中,点击节点并配置以下设置:

    1. 映像类型下拉列表中,选择包含 Containerd 的 Container-Optimized OS (cos_containerd)。 这是 GKE Sandbox 唯一支持的映像类型。
    2. 机器配置下,选择系列机器类型
    3. (可选)如果您运行的是支持的 GKE 版本,请选择 GPU 类型。此项必须是以下类型之一:
      • nvidia-tesla-t4
      • nvidia-tesla-a100
      • nvidia-a100-80gb
      • nvidia-l4
      • nvidia-h100-80gb
    4. 如果在 GKE Sandbox 上使用 GPU,请选择或安装 latest 驱动程序变体。
  6. 在导航菜单中,点击安全,然后选中启用 gVisor 沙盒复选框。

  7. 点击创建

gcloud

如需创建已启用 GKE Sandbox 的新节点池,请使用如下命令:

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

GKE Sandbox 的节点映像类型必须为 cos_containerd

如需创建使用 GKE Sandbox 的 GPU 节点池,请运行以下命令:

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --node-version=NODE_VERSION \
  --machine-type=MACHINE_TYPE \
  --accelerator=type=GPU_TYPE,gpu-driver-version=latest \
  --image-type=cos_containerd \
  --sandbox type=gvisor

替换以下内容:

可选:启用监控和日志记录功能

建议在集群上启用 Cloud Logging 和 Cloud Monitoring,以便系统记录 gVisor 消息,此操作可选。对于新集群,这些服务默认处于启用状态。

您可以使用 Google Cloud 控制台在现有集群上启用这些功能。

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击要修改的集群的名称。

  3. 功能下的 Cloud Logging 字段中,点击 修改 Cloud Logging

  4. 选中启用 Cloud Logging 复选框。

  5. 点击保存更改

  6. Cloud MonitoringManaged Service for Prometheus 字段重复相同的步骤,以启用这些功能。

在 Autopilot 和 Standard 中使用 GKE Sandbox

在启用了 GKE Sandbox 的 Autopilot 集群和 Standard 集群中,您可以通过在 Pod 规范中指定 gvisor RuntimeClass 来为 Pod 请求沙盒环境。

对于 Autopilot 集群,请确保您运行的是 GKE 1.27.4-gke.800 版或更高版本。

在沙盒中运行应用

如需让 Deployment 在启用了 GKE Sandbox 的节点上运行,请将其 spec.template.spec.runtimeClassName 设置为 gvisor,如以下示例所示:

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

创建 Deployment:

kubectl apply -f httpd.yaml

Pod 已部署到启用了 GKE Sandbox 的节点。如需验证部署,请找到部署了 Pod 的节点:

kubectl get pods

输出类似于以下内容:

NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

在输出结果中找到 Pod 的名称,然后检查 RuntimeClass 的值:

kubectl get pods POD_NAME -o jsonpath='{.spec.runtimeClassName}'

输出为 gvisor

或者,您可以列出每个 Pod 的 RuntimeClass,然后查找 RuntimeClass 设置为 gvisor 的 Pod:

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

输出如下所示:

POD_NAME: gvisor

使用这种方法来验证 Pod 是否在沙盒中运行是非常可靠的做法,因为它不依赖于沙盒本身内的任何数据。从沙盒内报告的任何内容都可能存在缺陷或是恶意的,因此不可信。

在 GKE Sandbox 上使用 GPU 运行 Pod

如需在 GKE Sandbox 上运行 GPU 工作负载,请将 runtimeClassName: gvisor 字段添加到清单中,如以下示例所示:

  • Standard 模式 GPU Pod 的示例清单:

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-gpu-pod
    spec:
      runtimeClassName: gvisor
      containers:
      - name: my-gpu-container
        image: nvidia/samples:vectoradd-cuda10.2
        resources:
          limits:
          nvidia.com/gpu: 1
    
  • Autopilot 模式 GPU Pod 的示例清单:

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-gpu-pod
    spec:
      runtimeClassName: gvisor
      nodeSelector:
        cloud.google.com/compute-class: "Accelerator"
        cloud.google.com/gke-accelerator: nvidia-tesla-t4
      - name: my-gpu-container
        image: nvidia/samples:vectoradd-cuda10.2
        resources:
          limits:
            nvidia.com/gpu: 1
    

您可以通过将 runtimeClassName: gvisor 字段添加到清单中,在 GKE Sandbox 上运行满足版本和 GPU 类型要求的任何 Autopilot 或 Standard 模式 GPU Pod。如需了解如何在 GKE 中运行 GPU Pod,请参阅以下资源:

运行常规 Pod 和沙盒化的 Pod

本部分中的步骤适用于 Standard 模式工作负载。不需要在 Autopilot 模式下同时运行常规 Pod 和沙盒 Pod,因为 Autopilot 价格模式消除了手动优化节点上调度的 Pod 数量的需求。

在节点池上启用 GKE Sandbox 后,您无需使用沙盒,即可通过使用节点污点和容忍设置,在这些节点上运行受信任的应用。这些 Pod 称为“常规 Pod”,以将它们与沙盒化的 Pod 区分开来。

与沙盒化的 Pod 一样,常规 Pod 也无法访问其他 Google Cloud 服务或集群元数据。此防护措施是节点配置的一部分。如果您的常规 Pod 或沙盒化的 Pod 需要访问 Google Cloud 服务,请使用适用于 GKE 的工作负载身份联合

GKE Sandbox 会向可运行沙盒化 Pod 的节点添加以下标签和污点:

labels:
  sandbox.gke.io/runtime: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io/runtime
  value: gvisor

除了 Pod 清单中的任何节点亲和性和容忍设置外,GKE Sandbox 还会对 RuntimeClass 设置为 gvisor 的所有 Pod 应用以下节点亲和性和容忍设置:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

如需在启用了 GKE Sandbox 的节点上安排常规 Pod,请在 Pod 清单中手动应用上述节点亲和性和容忍设置。

  • 如果您的 Pod 能够在启用了 GKE Sandbox 的节点上运行,请添加容忍设置。
  • 如果您的 Pod 必须在启用了 GKE Sandbox 的节点上运行,请同时添加节点亲和性和容忍设置。

例如,以下清单会修改在沙盒中运行应用时使用的清单,以便通过移除 runtimeClass 并添加上述污点和容忍设置,在具有沙盒化 Pod 的节点上作为常规 Pod 运行。

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

首先,验证 Deployment 未在沙盒中运行:

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

输出类似于以下内容:

httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

之前创建的 httpd Deployment 正在沙盒中运行,因为其 runtimeClass 为 gvisorhttpd-no-sandbox Deployment 没有对应的 runtimeClass 值,因此未在沙盒中运行。

接下来,通过运行以下命令,验证未沙盒化的 Deployment 正在具有 GKE Sandbox 的节点上运行:

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

在值 nodeName 中嵌入节点池的名称。验证 Pod 是否在节点池中启用了 GKE Sandbox 的节点上运行。

验证元数据保护

如需验证元数据免受可运行沙盒化 Pod 的节点影响的断言,您可以运行以下测试:

  1. 使用 kubectl apply -f 从以下清单创建沙盒化 Deployment。它使用 fedora 映像,其中包含 curl 命令。Pod 会运行 /bin/sleep 命令,以确保 Deployment 运行 10000 秒。

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. 使用 kubectl get pods 获取 Pod 的名称,然后使用 kubectl exec 以交互方式连接到 Pod。

    kubectl exec -it POD_NAME /bin/sh
    

    您在 /bin/sh 会话中连接到 Pod 中运行的容器。

  3. 在交互式会话中,尝试访问返回集群元数据的网址:

    curl -s "http://169.254.169.254/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    由于丢弃数据包时不显示提示,因此命令会挂起并最终超时。

  4. Ctrl+C 终止 curl 命令,然后键入 exit 取消与 Pod 的连接。

  5. 从 YAML 清单中移除 RuntimeClass 行,然后使用 kubectl apply -f FILENAME 重新部署 Pod。在没有 GKE Sandbox 的节点上终止沙盒化的 Pod,然后重新创建它。

  6. 获取新的 Pod 名称,使用 kubectl exec 连接到它,然后再次运行 curl 命令。这次会返回结果。此示例输出被截断。

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    键入 exit 取消与 Pod 的连接。

  7. 移除该 Deployment:

    kubectl delete deployment fedora
    

停用 GKE Sandbox

无法在 GKE Autopilot 集群或 GKE Standard 节点池中停用 GKE Sandbox。如果要停止使用 GKE Sandbox,请删除节点池

后续步骤