将 GKE Pod 放置在特定的可用区中

本页面介绍如何指示 Google Kubernetes Engine (GKE) 使用可用区级拓扑在特定 Google Cloud 可用区内的节点上运行 Pod。此类放置在以下情况下非常有用:

  • Pod 必须访问存储在可用区级 Compute Engine 永久性磁盘中的数据。
  • Pod 必须与其他可用区级资源(例如 Cloud SQL 实例)一起运行。

您还可以将可用区放置与拓扑感知流量路由结合使用,以缩短客户端和工作负载之间的延迟时间。如需详细了解拓扑感知流量路由,请参阅拓扑感知路由

使用可用区拓扑控制 Pod 位置是一种高级 Kubernetes 机制,您应该仅在需要 Pod 在特定可用区运行时才使用这种机制。在大多数生产环境中,我们建议您尽可能使用区域级资源(即 GKE 默认值)。

可用区放置方法

可用区拓扑内置于 Kubernetes 中,带有 topology.kubernetes.io/zone: ZONE 节点标签。如需指示 GKE 将 Pod 放置在特定可用区中,请使用以下任一方法:

  • nodeAffinity:在 Pod 规范中为一个或多个 Google Cloud 可用区指定 nodeAffinity 规则。此方法比 nodeSelector 更灵活,因为它让您可以将 Pod 放置在多个可用区中。
  • nodeSelector:在 Pod 规范中为单个 Google Cloud 可用区指定 nodeSelector。

  • 计算类:配置 Pod 以使用 GKE 计算类。这种方法可让您定义 Google Cloud 可用区集的优先级列表。这样一来,工作负载便可动态迁移到首选的可用区集(如果这些可用区中有节点可用)。如需了解详情,请参阅自定义计算类简介

注意事项

使用可用区拓扑的可用区级 Pod 放置存在以下注意事项:

  • 集群必须与请求的可用区位于同一 Google Cloud 区域中。
  • 在 Standard 集群中,您必须使用节点自动预配功能,或在请求的可用区中创建具有节点的节点池。Autopilot 集群会自动为您管理此过程。
  • Standard 集群必须是区域级集群。

价格

可用区拓扑是一种 Kubernetes 调度功能,在 GKE 中免费提供。

如需详细了解价格,请参阅 GKE 价格

准备工作

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

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如需使用 Google Cloud CLI 执行此任务, 请安装初始化 gcloud CLI。如果您之前安装了 gcloud CLI,请通过运行 gcloud components update 命令来获取最新 版本。较早版本的 gcloud CLI 可能不支持运行本文档中的命令。
  • 确保现有 GKE 集群与要放置 Pod 的可用区位于同一Google Cloud 区域中。如需创建新集群,请参阅创建 Autopilot 集群

使用 nodeAffinity 将 Pod 放置在多个可用区中

Kubernetes nodeAffinity 提供灵活的调度控制机制,支持多个标签选择器和逻辑运算符。若要让 Pod 在一组可用区中的其中一个可用区运行(例如在 us-central1-aus-central1-f 中),请使用 nodeAffinity。

  1. 将以下清单保存为 multi-zone-affinity.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-multi-zone
      template:
        metadata:
          labels:
            app: nginx-multi-zone
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                    - us-central1-a
                    - us-central1-f
    

    此清单会创建一个具有三个副本的 Deployment,并根据节点可用性将 Pod 放置在 us-central1-aus-central1-f 中。

    确保您的集群位于 us-central1 区域。如果您的集群位于其他区域,请将清单值字段中的可用区更改为集群区域中的有效可用区。

    可选:如果您要预配 TPU 虚拟机,请使用 AI 可用区,例如 us-central1-ai1a。AI 可用区是专门用于优化 Google Cloud 区域内 AI/机器学习工作负载的位置。

  2. 创建 Deployment:

    kubectl create -f multi-zone-affinity.yaml
    

    GKE 会在其中一个指定可用区的节点中创建 Pod。多个 Pod 可能在同一节点上运行。您可以选择使用 Pod 反亲和性,指示 GKE 将每个 Pod 放在单独的节点上。

使用 nodeSelector 将 Pod 放置在单个可用区中

如需将 Pod 放在单个可用区中,请在 Pod 规范中使用 nodeSelector。nodeSelector 等效于指定了单个可用区的 requiredDuringSchedulingIgnoredDuringExecution nodeAffinity 规则。

  1. 将以下清单保存为 single-zone-selector.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-singlezone
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-singlezone
      template:
        metadata:
          labels:
            app: nginx-singlezone
        spec:
          nodeSelector:
            topology.kubernetes.io/zone: "us-central1-a"
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    

    此清单指示 GKE 将 Deployment 中的所有副本放在 us-central1-a 可用区中。

  2. 创建 Deployment:

    kubectl create -f single-zone-selector.yaml
    

使用计算类优先在所选可用区中放置 Pod

GKE 计算类提供了一种控制机制,可让您定义节点配置优先级列表。通过可用区偏好设置,您可以定义希望 GKE 将 Pod 放置在哪些可用区中。

使用位置可用区优先级

如要在计算类中使用位置可用区优先级定义可用区偏好设置,需要使用 GKE 1.33.1-gke.1545000 版或更高版本。

以下示例创建了一个计算类,用于指定 Pod 的首选可用区列表。

这些步骤假定您的集群位于 us-central1 区域。如果您的集群位于其他区域,请将清单中的可用区值更改为集群区域中的有效可用区。

  1. 将以下清单保存为 zones-custom-compute-class.yaml

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: zones-custom-compute-class
    spec:
      priorities:
      - location:
        zones: [us-central1-a, us-central1-b]
      - location:
        zones: [us-central1-c]
      activeMigration:
        optimizeRulePriority: true
      nodePoolAutoCreation:
        enabled: true
      whenUnsatisfiable: ScaleUpAnyway
    

    此计算类清单会按如下方式更改扩缩行为:

    1. GKE 会尝试将 Pod 放置在 us-central1-aus-central1-b 中。
    2. 如果 us-central1-aus-central1-b 没有可用容量,GKE 会尝试将 Pod 放置在 us-central1-c 中。
    3. 如果 us-central1-c 没有可用容量,whenUnsatisfiable: ScaleUpAnyway 字段会使 GKE 将 Pod 放置在该区域内的任何可用的可用区中。
    4. 如果计算类中优先级较高的某个可用区稍后变为可用,activeMigration.optimizeRulePriority: true 字段会使 GKE 将 Pod 从任何优先级较低的可用区移至该可用区。此迁移使用 Pod 中断预算来帮助确保服务可用性。
  2. 创建自定义计算类:

    kubectl create -f zones-custom-compute-class.yaml
    

    GKE 会创建一个自定义计算类,供您的工作负载引用。

  3. 将以下清单保存为 custom-compute-class-deployment.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-zonal-preferences
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-zonal-preferences
      template:
        metadata:
          labels:
            app: nginx-zonal-preferences
        spec:
          nodeSelector:
            cloud.google.com/compute-class: "zones-custom-compute-class"
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    
  4. 创建 Deployment:

    kubectl create -f custom-compute-class-deployment.yaml
    

使用位置可用区类型优先级

如要在计算类中使用位置可用区类型优先级定义可用区偏好设置,需要使用 GKE 1.35.2-gke.1842000 版或更高版本。为 Pod 选择可用区类型后,系统会根据您的设置使用或创建一个跨越给定类型的所有可用区的新节点池。

您可以在计算类中指定以下可用区类型:

  • STANDARD:区域中的通用可用区。 Google Cloud 建议用于非机器学习工作负载。
  • AI:针对 AI/加速器容量进行了优化的专用可用区。建议用于 AI/机器学习工作负载。
  • CLUSTER_DEFAULT:集群的 autoprovisioning-locations (如果为空,则为集群的位置)中指定的可用区。

如需详细了解标准可用区和 AI 可用区,请参阅 AI 可用区简介

组合字段的限制

您无法在同一优先级条目中将 zoneTypes 字段与 location.zones 字段或 reservations.specific 字段组合使用。您可以在同一计算类中使用 zoneTypes 字段和 location.zones 字段,前提是将它们放在单独的优先级条目中。

此外,priorityDefaults 字段适用于计算类中的每个优先级。此规则的一个结果是,在 priorityDefaults 字段中设置 zoneTypes 字段会阻止您在任何优先级中使用 location.zones 字段或 reservations.specific 字段。

有效示例:单独的优先级

以下示例有效,因为 zoneszoneTypes 是在单独的优先级条目中指定的:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: valid-zonal-preferences
spec:
  priorities:
  - location:
      zones: [us-central1-a]
  - location:
      zoneTypes: [AI]

无效示例:相同的优先级

以下示例无效,因为 zoneszoneTypes 是在同一优先级条目中指定的:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: invalid-same-priority
spec:
  priorities:
  - location:
      zones: [us-central1-a]
      zoneTypes: [AI] # Error: mutually exclusive

无效示例:与默认值冲突

以下示例无效,因为在 priorityDefaults 部分中设置 zoneTypes 字段与优先级条目中的 zones 字段冲突:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: invalid-defaults-conflict
spec:
  priorityDefaults:
    location:
      zoneTypes: [AI]
  priorities:
  - location:
      zones: [us-central1-a] # Error: merges with defaults

用法示例

以下示例创建了一个计算类,用于指定 Pod 的首选可用区类型列表。

  1. 将以下清单保存为 zone-types-custom-compute-class.yaml

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: zone-types-custom-compute-class
    spec:
      priorities:
      - location:
        zones: [us-central1-c]
      - location:
        zoneTypes:
        - AI
      - location:
        zoneTypes:
        - CLUSTER_DEFAULT
      activeMigration:
        optimizeRulePriority: true
      nodePoolAutoCreation:
        enabled: true
      whenUnsatisfiable: ScaleUpAnyway
    

    此计算类清单会按如下方式更改伸缩行为:

    1. GKE 会尝试将 Pod 放置在 us-central1-c 可用区中。
    2. 如果 us-central1-c 没有可用容量,GKE 会尝试将 Pod 放置在该区域内的任何 AI 可用区中。
    3. 如果没有任何 AI 可用区具有可用容量,GKE 会尝试将 Pod 放置在任何 CLUSTER_DEFAULT 可用区中。
    4. 如果没有任何 CLUSTER_DEFAULT 可用区具有可用容量,whenUnsatisfiable: ScaleUpAnyway 字段会使 GKE 将 Pod 放置在该区域内的任何可用的可用区中。
    5. 如果计算类中优先级较高的某个可用区稍后变为可用,activeMigration.optimizeRulePriority: true 字段会使 GKE 将 Pod 从任何优先级较低的可用区移至该可用区。此迁移使用 Pod 中断预算来帮助确保服务可用性。
  2. 创建自定义计算类:

    kubectl create -f zone-types-custom-compute-class.yaml
    

    GKE 会创建一个自定义计算类,供您的工作负载引用。

  3. 将以下清单保存为 custom-compute-class-deployment.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-zonal-preferences
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-zonal-preferences
      template:
        metadata:
          labels:
            app: nginx-zonal-preferences
        spec:
          nodeSelector: cloud.google.com/compute-class: "zone-types-custom-compute-class"
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    
  4. 创建 Deployment:

    kubectl create -f custom-compute-class-deployment.yaml
    

NAP 如何评估 zoneTypes

在确定是重复使用现有节点池还是创建新节点池时,节点自动预配 (NAP) 通常要求节点池的现有可用区与您请求的 zoneTypes 完全匹配。如果您更新优先级以包含更广泛的可用区类型(例如,从 [AI] 更改为 [AI, STANDARD]),NAP 将预配新的节点池以匹配新的确切形状。

机器类型感知修剪

如果机器类型(例如 h3-standard-88)仅在类型定义的可用区子集中可用(例如,仅在 us-central1-a 中可用),则 GKE 会自动修剪节点池位置列表,使其仅包含实际存在该硬件的可用区。

目标 AI 可用区

AI 可用区是专门用于 AI/机器学习训练和推理工作负载的可用区。这些可用区提供大量的机器学习加速器容量。如需了解详情,请参阅 AI 可用区文档。

在本文档和 GKE 文档中,“标准 可用区”或“可用区”是指区域内的非 AI 可用区。 Google Cloud

在 GKE 中使用 AI 可用区之前,请考虑以下特征:

  • AI 可用区在物理上与标准可用区分开,以提供额外的存储空间和电源。这种分离可能会导致延迟时间增加,但对于 AI/机器学习工作负载来说,这种延迟通常是可以接受的。
  • AI 可用区具有带有 ai 表示法的后缀。例如, us-central1 区域中的 AI 可用区名为 us-central1-ai1a
  • 目前,仅支持 TPU 虚拟机。
  • 集群的控制平面在与 AI 可用区位于同一区域的一个或多个标准可用区中运行。
  • 只有满足以下要求,您才能在 AI 可用区中运行没有挂接 TPU 的虚拟机:

    • 您已在同一可用区中运行使用 TPU 虚拟机的其他工作负载。
    • 非 TPU 虚拟机是 Spot 虚拟机、与预留绑定,或属于具有特定加速器与通用虚拟机比率的节点池。
  • AI 可用区与同一区域内具有相同后缀的标准可用区共享组件,例如网络连接和软件发布。对于高可用性工作负载,我们建议您使用不同的可用区。例如,避免同时使用 us-central1-ai1aus-central1-a 来实现高 可用性。

默认情况下,GKE 不会在 AI 可用区中部署工作负载。如需使用 AI 可用区,您必须配置以下选项之一:

  • (推荐)ComputeClass:将最高优先级设置为在 AI 可用区中请求 按需 TPU。ComputeClass 可帮助您为工作负载定义硬件配置的优先级列表。如需查看示例,请参阅 ComputeClass 简介
  • 节点自动预配:在 Pod 规范中使用nodeSelectornodeAffinity,指示节点自动预配在 AI 可用区中创建节点池。如果您的工作负载未明确以 AI 可用区为目标,则节点 自动预配在创建新节点池时仅考虑标准可用区或来自 --autoprovisioning-locations 的可用区。此配置有助于确保不运行 AI/机器学习模型的工作负载保留在标准可用区中,除非您明确配置其他设置。如需查看使用 nodeSelector 的清单示例, 请参阅 设置自动创建的节点的默认可用区
  • GKE Standard:如果您直接管理节点 池,请在创建节点 池时使用 --node-locations 标志中的 AI 可用区。如需查看示例,请参阅 在 GKE Standard 中部署 TPU 工作负载

验证 Pod 位置

如需验证 Pod 位置,请列出 Pod 并检查节点标签。多个 Pod 可能会在单个节点中运行,因此,如果您使用 nodeAffinity,可能看不到分布在多个可用区中的 Pod。

  1. 列出 Pod:

    kubectl get pods -o wide
    

    输出是正在运行的 Pod 和相应的 GKE 节点的列表。

  2. 描述节点:

    kubectl describe node NODE_NAME | grep "topology.kubernetes.io/zone"
    

    NODE_NAME 替换为该节点的名称。

    输出类似于以下内容:

    topology.kubernetes.io/zone: us-central1-a
    

如果您希望 GKE 在多个可用区中均匀分布 Pod,以改善多个故障域的故障切换,请使用 topologySpreadConstraints

后续步骤