平台工程师可以使用自定义 ComputeClasses 以声明方式配置节点设置和回退优先级,供 Google Kubernetes Engine (GKE) 在自动扩缩期间用于创建节点。您可以根据特定策略和工作负载要求创建 ComputeClass。本文档提供了在集群中设计和实现 ComputeClass 的最佳实践。您应该已经熟悉自定义 ComputeClass。如需全面了解所有 GKE 最佳实践,请参阅 GKE 最佳实践。
ComputeClass 设计
以下部分提供了有关在集群中设计和实现 ComputeClass 的最佳实践,这些实践基于的目标包括最大限度地提高计算容量的灵活性、效率、可用性和性能。ComputeClass 可与手动创建的节点池和自动创建的节点池搭配使用。
根据策略设计每个 ComputeClass
设计每个 ComputeClass 以满足工作负载、团队或组织的特定目标。利用 ComputeClass 的回退行为以及选择手动创建的节点池和自动创建的节点池的功能,优先实现某些结果,例如减少手动开销或提高调度性能。以下部分介绍了常见策略。
提高资源可用性并减少人工开销
如需将节点池创建委托给 GKE,请仅在 ComputeClass 中使用自动创建的节点池。自动扩缩器会根据硬件可用性、Pod 资源要求和可用区容量来配置节点。此策略无需手动创建和调整节点池,并可减少与闲置未用节点容量相关的费用。
提升调度性能并微调节点
如需微调最高优先级的节点并缩短调度延迟时间,请在 ComputeClass 中混合使用手动创建的节点池和自动创建的节点池。这种混合策略可减少 Pod 等待 GKE 创建新节点池的频率。由于最高优先级的节点池是手动创建的,因此您可以微调硬件,以满足 Pod 的确切要求。
混合策略涉及 ComputeClass 中的以下类型的节点池(按优先级顺序):
- 手动创建的节点池:这些节点池具有您希望大多数 Pod 在其上运行的确切规格。使用特定节点标签、节点污点、容量预留或特殊配置(例如
kubelet参数)配置这些节点池。创建这些节点池,并根据您估计的 Pod 需求量来确定节点数量。在 ComputeClass 中,为这些节点池分配最高优先级。 - 自动创建的节点池:作为后备措施,使用 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此卷绑定模式可防止在 GKE 创建使用相应 PersistentVolumeClaim 的 Pod 之前创建 PersistentVolume。GKE 在运行 Pod 的节点所在的可用区中预配 PersistentVolume。 - 使用感知拓扑的 StorageClass:如果您的 ComputeClass 跨越多个机器系列代际(例如 C4 和 C3),请使用启用了自动磁盘类型选择且仅在支持您指定的磁盘类型的节点上进行调度的 StorageClass。您可以使用内置的
dynamic-rwoStorageClass 或自定义 StorageClass。这样一来,您的有状态工作负载就可以在多个 Compute Engine 实例代际上运行,因为集群自动扩缩器会动态选择兼容的磁盘类型。
设计基础架构,以实现计算容量的灵活性、效率和可用性
以下部分提供了有关如何提高 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 模式下或使用节点池自动创建功能时,可能会触发在集群中创建新节点池。如果您有选择 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 的更改是否会导致工作负载问题:
- 在预演环境中测试升级。
- 请参阅 GKE 版本说明,了解 ComputeClass CRD 的更改或新增内容。
- 查看ComputeClass CRD 参考页面,了解目标升级版本中的字段更新。
使用 PodDisruptionBudget 提高工作负载可用性
会导致 Pod 逐出的 ComputeClass 操作(例如主动迁移)会遵守任何已配置的 PodDisruptionBudgets。例如,您可以配置推理部署,使其具有 PodDisruptionBudget,该预算要求超过 70% 的 Pod 可用。在主动迁移期间,如果逐出 Pod 会违反该预算,则 GKE 不会逐出该 Pod。为以下类型的工作负载指定 PodDisruptionBudget:
- 无状态工作负载,例如推理部署。
- 复制的有状态工作负载,例如高可用性数据库应用。
不要依赖 PodDisruptionBudget 来保护需要运行到完成、只有一个实例或依赖本地持久性数据的工作负载。指定一个在工作负载可用性之间取得平衡并允许升级等功能完成的预算。
防止关键工作负载被逐出
如果您有工作负载,其中每个 Pod 都必须运行到完成才能终止,请将 cluster-autoscaler.kubernetes.io/safe-to-evict:
"false" 注解添加到 Pod 规范中。此注解可防止 GKE 在自动扩缩操作期间逐出 Pod。使用此注解可保护无法容忍中断的 Pod,例如单实例有状态工作负载和长时间运行的批处理作业。
最佳做法摘要
本文档针对 ComputeClass 提供了以下最佳实践:
后续步骤
- 查看其他 GKE 最佳实践。
- 了解如何创建 ComputeClass。