ComputeClass 方面的最佳实践

平台工程师可以使用自定义 ComputeClasses 以声明方式配置节点设置和回退优先级,供 Google Kubernetes Engine (GKE) 在自动扩缩期间创建节点时使用。您可以根据特定策略和工作负载要求创建 ComputeClass。本文档介绍了在集群中设计和实现 ComputeClass 的最佳实践。您应当已熟悉自定义 ComputeClass。如需查看所有 GKE 最佳实践的综合概览,请参阅 GKE 最佳实践。

ComputeClass 设计

以下部分提供了在集群中设计和实现 ComputeClass 的最佳实践,这些最佳实践基于最大限度地提高计算容量的灵活性、效率、可用性和性能等目标。ComputeClass 既适用于手动创建的节点池,也适用于自动创建的节点池。

根据策略设计每个 ComputeClass

设计每个 ComputeClass,以满足工作负载、团队或组织的特定目标。利用 ComputeClass 的回退行为以及同时选择手动创建和自动创建的节点池的功能,优先实现特定目标,例如减少手动开销或提高调度性能。以下部分介绍了常见策略。

提高资源可用性并减少人工开销

如需将节点池创建委托给 GKE,请仅在 ComputeClass 中使用自动创建的节点池。自动扩缩器会根据硬件可用性、Pod 资源要求和可用区容量来配置节点。此策略无需手动创建和调整节点池,并且可以降低与空闲、未使用的节点容量相关的费用。

提高调度性能并微调节点

如需微调最高优先级节点并缩短调度延迟时间,请在 ComputeClass 中结合使用手动创建和自动创建的节点池。这种混合策略可减少 Pod 等待 GKE 创建新节点池的频率。由于优先级最高的节点池是手动创建的,因此您可以对硬件进行微调,以满足 Pod 的确切要求。

混合策略涉及 ComputeClass 中按优先级顺序排列的以下类型的节点池:

  1. 手动创建的节点池:这些节点池具有您希望大多数 Pod 在其上运行的确切规范。为这些节点池配置特定的节点标签、节点污点、容量预留或特殊配置(例如 kubelet 参数)。创建这些节点池时,请根据您估计 Pod 需要的节点数量来设置节点数。在 ComputeClass 中,为这些节点池分配最高优先级。
  2. 自动创建的节点池:作为后备措施,使用 ComputeClass 请求仍针对 Pod 进行了优化的其他节点池。为这些自动创建的节点池分配比手动创建的节点池更低的优先级。

以下示例 ComputeClass 使用了这种混合策略:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: hybrid-class
spec:
  nodePoolAutoCreation:
    enabled: true
  priorities:
  - nodepools: ['manual-pool1']
  - machineFamily: n4
    minCores: 16
    minMemoryGb: 64
  whenUnsatisfiable: DoNotScaleUp

当您部署使用此 ComputeClass 的工作负载时,GKE 会将 Pod 放置在 manual-pool1 中的可用节点上。仅当手动创建的节点池没有可用容量时,GKE 才会创建新的节点池。当手动创建的节点池中的现有节点数量增加时,调度延迟时间会减少,因为 GKE 不需要频繁创建新节点。

明确定义最后的伸缩行为

whenUnsatisfiable 字段控制如果 GKE 无法满足 ComputeClass 中任何优先级规则的要求,会发生什么情况。为避免版本升级后出现意外行为,请在每个 ComputeClass 中明确指定此字段的值。设置值有助于 ComputeClass 用户了解在工作负载中选择该 ComputeClass 时会发生什么。此字段的推荐值取决于工作负载类型,如下所示:

  • 通用工作负载:如果您的工作负载可以在任何机器系列上运行,请指定值 ScaleUpAnyway。如果与 ComputeClass 中的优先级规则匹配的节点不可用,GKE 会扩容使用集群默认机器系列的节点。
  • 需要专用硬件的工作负载:对于依赖于特定硬件(例如 GPU 或某些 Compute Engine 机器系列)的加速器或高性能计算工作负载,请指定值 DoNotScaleUp。如果与 ComputeClass 中的优先级规则匹配的节点不可用,则 Pod 会保持 Pending 状态,直到资源可用。此方法可防止 Pod 在不兼容的硬件上运行。

如需了解详情,请参阅定义未应用优先级规则时的伸缩行为。

为大多数工作负载设置集群级默认 ComputeClass

如果大多数工作负载具有相同的硬件要求,请为集群配置默认 ComputeClass。GKE 会将默认 ComputeClass 应用于未明确选择 ComputeClass 的所有工作负载。通过设置默认 ComputeClass,应用运维人员无需更改节点选择器,也无需在各个 Pod 中手动请求特定节点池和硬件。如果您设置了集群级默认 ComputeClass,请勿向集群中的现有节点池添加其他 ComputeClass 的节点标签和污点。在为集群级默认 ComputeClass 进行调度期间,GKE 会忽略具有其他 ComputeClass 的节点标签或节点污点的任何节点池。

为命名空间设置默认 ComputeClass,以隔离租户

除了集群级默认 ComputeClass 之外,您还可以为特定命名空间设置默认 ComputeClass。如果您有多租户环境,或者想要隔离在专用硬件上运行的工作负载,请为这些命名空间配置默认 ComputeClass。为防止系统 Pod 在 GPU 节点等专用硬件上运行,请添加通用 ComputeClass 作为系统命名空间的默认 ComputeClass。

在 Autopilot 模式下运行低交互工作负载

如果您的工作负载不需要手动交互或管理,请使用 ComputeClass 在 Autopilot 模式下运行这些工作负载。即使您使用的是 Standard 集群,也可以在任何 ComputeClass 中启用 Autopilot 模式。GKE 会在全代管式节点上运行选择 Autopilot ComputeClass 的工作负载,这些节点实现了 GKE Autopilot 的安全性、伸缩和结算功能。如需了解详情,请参阅 GKE Standard 中的 Autopilot 模式工作负载简介。

有状态工作负载

以下部分介绍了在依赖永久性数据的有状态工作负载中减少中断或意外行为的最佳实践。

停用主动迁移

主动迁移会自动将 Pod 移至在 ComputeClass 中具有更高优先级或有能力运行未调度 DaemonSet Pod 的新节点。在主动迁移期间,GKE 会终止现有节点上的 Pod,并在优先级较高的节点上创建新 Pod。如果您有依赖于本地永久性存储空间中数据的工作负载,则将 Pod 移至新节点可能会导致中断,因为 Pod 会失去对永久性数据的访问权限。为避免此问题,请为用于有状态工作负载的 ComputeClass 停用主动迁移。

使用 StorageClass 提高调度可靠性

通过以下方式使用 StorageClass 提高有状态工作负载的调度可靠性:

  • 仅在 Pod 创建后创建卷:如果您使用动态卷预配,请在 StorageClass 的 volumeBindingMode 字段中指定值 WaitForFirstConsumer。此卷绑定模式会阻止创建 PersistentVolume,直到 GKE 创建使用相应 PersistentVolumeClaim 的 Pod。GKE 在运行 Pod 的节点所在的可用区中预配 PersistentVolume。
  • 使用拓扑感知型 StorageClass:如果您的 ComputeClass 跨越多代机器系列,请使用启用了自动磁盘类型选择 (parameters.type: dynamic) 且仅在支持指定磁盘类型的节点上进行调度的 StorageClass。例如,在可用区容量受限期间,您的 ComputeClass 会从仅支持 Hyperdisk 的系列(例如 C4、C4D 或 N4)回退到 Persistent Disk 系列(例如 N2 或 N2D)。您可以使用内置 dynamic-rwo StorageClass 或自定义 StorageClass。然后,您的有状态工作负载可以跨多个 Compute Engine 实例代系进行故障切换,因为集群自动扩缩器会为预配的任何回退节点动态选择兼容的磁盘类型(hyperdisk-balanced 或 pd-balanced)。

设计基础设施,以实现计算容量的灵活性、效率和可用性

以下部分提供了提高 ComputeClass 中计算容量的灵活性、效率和可用性的最佳实践,以便您的 Pod 减少处于 Pending 状态的时间。

请求机器系列,而不是机器类型

您可以在 ComputeClass 优先级规则中请求 Compute Engine 机器系列或特定机器类型。除非您对特定机器类型有严格的依赖关系,否则请使用 machineFamily 字段选择机器系列。在伸缩操作期间,GKE 可以创建使用该机器系列中任何可行机器类型的节点,从而提高 Pod 在最优先节点配置上运行的可能性。

为需求量大的硬件使用容量预留

如果您的工作负载依赖于热门硬件(例如 TPU 或高性能 GPU),请为这些硬件创建 Compute Engine 容量预留,并在 ComputeClass 中使用这些预留。容量预留可提高您所在区域或可用区中硬件的可用性,从而帮助您提高计算容量的灵活性、效率和可用性。如需在 ComputeClass 中使用预留而不影响回退行为,请使用 Specific 或 AnyThenFail 预留亲和性。如果您使用 AnyBestEffort 或 Automatic 亲和性,并且没有可用的预留容量,则 Compute Engine 可能会绕过 ComputeClass 优先级规则,并回退到按需硬件。如需了解详情,请参阅使用预留的可用区级资源。

至少一小时内不使用新预留

集群自动扩缩器会将容量预留的相关信息存储在缓存中。创建新的容量预留后,自动扩缩器可能需要长达一小时才能发现该预留。创建预留后,请至少等待一小时,然后再在工作负载中使用该预留。如果您在自动扩缩器将预留存储在缓存中之前部署使用该预留的工作负载,则自动扩缩操作可能会失败。

安全

以下部分介绍了提高集群中 ComputeClass 安全性的最佳实践。这些措施非常重要,因为 ComputeClass 可用于创建和配置使用昂贵或存货有限的硬件的节点。有意或无意的误用可能会导致工作负载中断、意外的资源使用费用和配额耗尽。

限制对 ComputeClass 配置的 API 访问权限

工作负载可以使用 ComputeClass 创建运行专用硬件(包括 GPU 和 TPU)的节点。将创建、修改和删除 ComputeClass 的权限限制为可在集群中创建、修改和删除节点的相同主账号。如需控制对 ComputeClass 的访问权限,请使用 RBAC 政策。

按命名空间限制 ComputeClass 可用性

GKE 客户通常会按 Kubernetes 命名空间来区分不同的团队或工作负载类型。ComputeClass 是集群范围的资源,这意味着默认情况下,任何命名空间中的任何工作负载都可以选择任何 ComputeClass。为避免有意或无意的误用,请使用 ValidatingAdmissionPolicies 控制每个命名空间中的工作负载可以选择的 ComputeClass 集。例如,您可以阻止 Web 前端命名空间中的 Pod 选择创建加速器的 ComputeClass。验证您的 ValidatingAdmissionPolicies 是否检查以下常见配置:

  • 检查所有选择字段:工作负载可以使用 Pod 规范中的 nodeSelector、nodeAffinity 或 tolerations 字段来选择 ComputeClass。为避免意外选择 ComputeClass,请在 ValidatingAdmissionPolicy 表达式中检查所有这些字段。
  • 检查通配符容忍度绕过:明确阻止或验证通配符容忍度(例如,没有键的 operator: Exists 容忍度)。这些通配符选择器可以涵盖大多数节点污点,包括 ComputeClass 污点。
  • 检查所有工作负载控制器:配置政策的 matchConstraints,以涵盖所有工作负载控制器资源(例如 Deployment、StatefulSet、DaemonSet、Job 和 CronJob)。请勿将检查范围仅限定为 Pod 资源。

如需了解详情,请参阅限制对修改和选择 ComputeClass 的访问权限。

可靠性

以下部分介绍了提高 ComputeClass 的自动扩缩和 Pod 迁移可靠性的最佳实践,这可降低中断或 Pod 卡住的风险。

防止使用冲突的节点选择器

Pod 中的节点选择器会影响 GKE 放置这些 Pod 的位置,并且在 Autopilot 模式下或使用节点池自动创建功能时,可能会触发在集群中创建新节点池。如果您的 Pod 选择 ComputeClass 并使用节点选择器请求与 ComputeClass 配置冲突的节点,则 GKE 可能根本不会调度这些 Pod。

例如,假设某个 ComputeClass 仅请求按需实例。如果 Pod 选择该 ComputeClass 并在节点选择器中选择 Spot 虚拟机,则 GKE 无法调度该 Pod,因为 ComputeClass 和节点选择器相互冲突。为避免此问题,请使用 ValidatingAdmissionPolicies 等方法,防止选择 ComputeClass 的 Pod 也选择系统节点标签。如需了解详情,请参阅用于系统节点标签的节点选择器。

测试对有效迁移和自动扩缩设置的所有更改

ComputeClass 中的主动迁移和自动扩缩设置会直接影响 GKE 终止 Pod 以执行任务(例如将 Pod 迁移到更优先的硬件以及整合未充分利用的节点)的频率。 在现有 ComputeClass 中修改这些设置可能会导致意外的工作负载中断。在对现有 ComputeClass 中的这些设置进行任何修改之前,请先在预演环境中测试这些更改。 您还可以使用注解来防止关键工作负载在伸缩期间被逐出。

在集群升级之前测试 ComputeClass CRD 更新

GKE 会定期更新 ComputeClass CustomResourceDefinition (CRD),以添加字段、修改字段行为和修复问题。字段添加和修改通常在特定 GKE 版本中生效。在将生产集群升级到新的次要版本或补丁版本之前,请使用以下准则检查对 CRD 的更改是否会导致工作负载问题:

使用 PodDisruptionBudget 提高工作负载可用性

导致 Pod 逐出的 ComputeClass 操作(例如主动迁移)会遵循任何已配置的 PodDisruptionBudgets。例如,您可以将推理 Deployment 配置为具有 PodDisruptionBudget,该 PodDisruptionBudget 要求超过 70% 的 Pod 可用。在主动迁移期间,如果 Pod 逐出违反了该预算,则 GKE 不会逐出该 Pod。为以下工作负载指定 PodDisruptionBudget:

  • 无状态工作负载,例如推理 Deployment。
  • 复制的有状态工作负载,例如高可用性数据库应用。

请勿依赖 PodDisruptionBudget 来保护需要运行到完成、只有一个实例或依赖于本地永久性数据的工作负载。指定一个预算,在工作负载可用性与允许升级等功能完成之间取得平衡。

保护关键工作负载免遭逐出

如果您的工作负载中的每个 Pod 都必须运行到完成才能终止,请将 cluster-autoscaler.kubernetes.io/safe-to-evict: "false" 注解添加到 Pod 规范中。此注解可防止 GKE 在自动扩缩操作期间逐出 Pod。使用此注解可保护无法容忍中断的 Pod,例如单实例有状态工作负载和长时间运行的批量作业。

最佳做法摘要

本文档介绍了 ComputeClass 的以下最佳实践:

后续步骤