在 GKE 上运行费用经过优化的 Kubernetes 应用的最佳做法

本文档将讨论 Google Kubernetes Engine (GKE) 功能和选项,以及在 GKE 上运行经过费用优化的应用的最佳做法,以充分利用 Google Cloud 提供的弹性。本文档假定您熟悉 Kubernetes、Google Cloud、GKE 和自动扩缩。

简介

随着 Kubernetes 的广泛采用,越来越多的企业和平台即服务 (PaaS) 和软件即服务 (SaaS) 提供商开始为自身的工作负载使用多租户 Kubernetes 集群。也就是说,单个集群可能会运行属于不同团队、部门、客户或环境的应用。Kubernetes 提供的多租户让公司管理少数大型集群,而不是多个较小集群,并且具有适当的资源利用率、简化管理控制和减少碎片化等优势。

随着时间的推移,Kubernetes 集群使用数量快速增长的部分公司开始出现费用不成比例增长这一现象。出现这种情况是因为使用 Kubernetes 等云端解决方案的传统公司没有云领域专业知识的开发者和操作员。云准备情况不足会导致应用出现自动扩缩不稳定(例如一天中某个时段的流量波动)、流量激增或高峰(例如黑色星期五和网购星期一等电视广告或峰值事件)现象。为了尝试“修复”该问题,这些公司往往会采用在非弹性环境中的操作方式,即过度预配其集群。与应用在一天中大部分时间的使用量相比,过度预配会导致明显过高的 CPU 和内存分配。

本文档提供了有关在 GKE 上运行经过费用优化的 Kubernetes 工作负载的最佳做法。下图概述了此方法。

优化 Kubernetes 应用所耗费用的方法。

构建经过费用优化的应用的基础是在各团队之间宣传节省费用的文化。除了将有关费用的讨论移到开发过程的开始阶段,此方法还会迫使您更好地了解应用的运行环境,在此上下文中便是指 GKE 环境。

为了实现费用低廉且应用稳定,您必须正确设置或调整某些功能和配置(例如自动扩缩、机器类型和地区选择)。您的工作负载类型也是一个重要的考虑因素,因为根据工作负载类型和应用的要求,您必须应用不同的配置,以进一步降低费用。最后,您必须监控您的支出并创建保护措施,以便在开发周期早期执行最佳做法。

下表汇总了 GKE 可以帮助您解决的挑战。虽然我们建议您阅读整篇文档,但此表可以向您展示文档内容所在的具体章节。

挑战 操作
我想查看如何在 GKE 上轻松节省费用。 选择适当的地区注册承诺使用折扣,然后使用 E2 机器类型
我需要了解我的 GKE 费用。 观察您的 GKE 集群并注意建议,然后启用 GKE 用量计量
我希望充分利用现有工作负载的 GKE 弹性。 阅读 Pod 横向自动扩缩器集群自动扩缩器,并了解自动扩缩器和过度预配的最佳做法。
我想使用最高效的机器类型。 为您的工作负载选择合适的机器类型
我的集群中的许多节点都处于空闲状态。 阅读集群自动扩缩器的最佳做法。
我需要在批量作业方面节约更多费用。 阅读批处理工作负载的最佳做法。
我需要在服务工作负载方面节约更多费用。 阅读服务工作负载的最佳做法。
我不知道如何调整 Pod 资源请求的大小。 使用 Pod 纵向自动扩缩器 (VPA),但请参考混用 Pod 横向自动扩缩器 (HPA) 和 VPA 的最佳做法。
我的应用在自动扩缩和维护活动期间状态不稳定。 为 Kubernetes 准备云端应用,并了解 Metrics Server 的工作原理以及如何对其进行监控
如何让我的开发者注意应用的资源使用情况? 宣传节省费用文化考虑使用 GKE Enterprise Policy Controller设计 CI/CD 流水线以实施节省费用的做法,以及使用 Kubernetes 资源配额
要进一步降低生态系统成本,我还要考虑哪些因素? 查看小型开发集群查看您的日志记录和监控策略,并查看地区级集群和多区域集群中的地区间出站流量

GKE 费用优化功能和选项

经过费用优化的 Kubernetes 应用高度依赖 GKE 自动扩缩。要在 GKE 上平衡费用、可靠性和扩缩性能,您必须了解自动扩缩的工作原理以及您有哪些选择。本节将讨论 GKE 自动扩缩,以及其他针对服务工作负载和批处理工作负载的实用的费用优化配置。

微调 GKE 自动扩缩

自动扩缩是 GKE 的一项策略,通过最大限度地减少基础架构正常运行时间,从而让 Google Cloud 客户仅为其需求付费。换句话说,自动扩缩可通过以下方式节省成本:1) 在需求增加之前启动工作负载及其底层基础架构,以及 2) 在需求减少时关闭它们。

下图展示了这一概念。在 Kubernetes 中,您的工作负载是在 Pod 中运行的容器化应用,而由一组节点组成的底层基础架构必须提供足够的计算能力来运行工作负载。

自动扩缩可通过以下方式节省成本:1) 在需求增加之前启动工作负载及其底层基础架构,以及 2) 在需求减少时关闭它们。

如下图所示,此环境具有四个可扩容维度。工作负载和基础架构可以通过添加和移除 Pod 或节点进行横向扩缩,也可以通过增加或减小 Pod 或节点的大小进行纵向扩缩。

费用优化环境的四个可扩容维度。

GKE 使用如下功能来处理这些自动扩缩场景:

下图展示了这些场景。

使用 HPA、VPA、CA 和节点自动预配的场景。

本部分的其余内容将更详细地讨论这些 GKE 自动扩缩功能,并介绍其他针对服务工作负载和批处理工作负载的实用的费用优化配置。

水平 Pod 自动扩缩器

Pod 横向自动扩缩器 (HPA),用于根据表示负载的指标扩缩在 Pod 中运行的应用。您可以配置 CPU 利用率或其他自定义指标(例如每秒请求数)。简而言之,HPA 可以添加和删除 Pod 副本,它最适合可以快速启动来应对使用峰值且可以正常关停来避免工作负载不稳定的无状态工作器。

借助 HPA 目标利用率阈值,您可以自定义自动触发扩缩的时间。

如上图所示,HPA 需要一个目标利用率阈值(以百分比表示),该值可以让您自定义自动触发扩缩的时间。在此示例中,目标 CPU 利用率为 70%。这意味着您的工作负载具有 30% 的 CPU 缓冲区,可以在启动新副本时处理请求。小缓冲区可避免过早纵向扩容,但也可能在高峰期使您的应用负载过重。而大缓冲区会造成资源浪费,从而增加您的费用。确切的目标值因应用而异,但是您必须考虑的一点是缓冲区大小应足以在高峰期处理两到三分钟的请求。即使您保证应用可以在几秒钟内启动,但是集群自动扩缩器向集群添加新节点时,或者 Pod 因缺少资源而受到限制时,仍需要额外的时间。

在应用中启用 HPA 时,请遵循以下最佳做法:

如需了解详情,请参阅配置 Pod 横向自动扩缩器

Pod 纵向自动扩缩器

与添加和删除 Pod 副本以快速响应使用峰值的 HPA 不同,Pod 纵向自动扩缩器 (VPA) 会随着时间的推移观察 Pod 并逐渐找到 Pod 需要的最佳 CPU 和内存资源。设置合适的资源对于稳定性和费用效益至关重要。如果 Pod 资源太小,则应用可能会受到限制,或者由于内存不足错误而故障。如果资源过大,则会浪费资源,进而产生高额账单。VPA 适用于不由 HPA 处理的无状态工作负载和有状态工作负载,或您不确定恰当的 Pod 资源请求时。

VPA 检测到 Pod 一直在极限状态下运行,并使用更大的资源重新创建了 Pod。

如上图所示,VPA 检测到 Pod 一直在极限状态下运行,并使用更大的资源重新创建了 Pod。当 Pod 始终未被充分利用时,会发生相反的情况,即触发缩减。

VPA 可在三种不同的模式下工作:

  • Off。在此模式(也称为建议模式)下,VPA 不会对您的 Pod 进行任何更改。系统会计算建议,并在 VPA 对象中对其进行检查。
  • Initial:VPA 仅在创建 Pod 时分配资源请求,之后不再加以更改。
  • Auto:VPA 会在 Pod 的生命周期内更新 CPU 和内存请求。这意味着删除 Pod、调整 CPU 和内存,然后启动新的 Pod。

如果您计划使用 VPA,最佳做法是从 Off 模式开始拉取 VPA 建议。确保在拉取建议之前先运行 24 小时(最好运行一周或更长时间)。然后,仅当您对操作充满信心时,再考虑切换至 Initial 模式或 Auto 模式。

在您的应用中启用 VPA(无论采用 Initial 模式还是 Auto 模式)时,请遵循以下最佳做法:

无论您是否考虑使用 Auto 模式,都要确保遵循以下做法:

  • 确保您的应用可以在接收流量时重启。
  • 添加 Pod 中断预算 (PDB) 以控制可以同时移除的 Pod 数量。

如需了解详情,请参阅配置 Pod 纵向自动扩缩

将 HPA 和 VPA 混用

官方建议是不要在 CPU 或内存上混用 VPA 和 HPA。不过,在使用 VPA 的推荐模式或 HPA 的自定义指标(例如每秒请求数)时,您可以安全地混用两者。在混用 VPA 和 HPA 时,请确保您的部署接收了足够的流量,也就是说您的部署始终要高于 HPA 最小副本数运行。这可以让 VPA 了解 Pod 的资源需求。

如需详细了解 VPA 限制,请参阅 Pod 纵向自动扩缩的限制

集群自动扩缩器

集群自动扩缩器 (CA) 会自动调整底层计算机基础架构的大小。CA 为集群中没有运行位置的 Pod 提供节点,并移除利用率过低的节点。CA 针对基础架构的费用进行了优化。换句话说,如果集群中有两个或更多节点类型,则 CA 会选择能满足给定需求的费用最低的类型。

与 HPA 和 VPA 不同,CA 不依赖于加载指标。相反,它基于调度模拟和已声明的 Pod 请求。最佳做法是每次使用 HPA 或 VPA 时都启用 CA。这种做法可确保 Pod 自动扩缩器确定您需要更多容量时,底层基础架构可以相应地增加。

CA 会自动添加和移除计算容量,以应对流量高峰。

如图所示,CA 会自动添加和移除计算容量来应对流量高峰,并在客户处于休眠状态时节省费用。最佳做法是为所有应用定义 Pod 中断预算 (PDB)。在 PDB 控制可以同时关闭的副本数的 CA 纵向缩容阶段,这一做法显得尤为重要。

由于自身造成的暂时性中断,某些 Pod 无法被任一自动扩缩器重启,因此,这些 Pod 上运行的节点无法删除。例如,系统 Pod(例如 metrics-serverkube-dns)和使用本地存储空间的 Pod 不会重启。但是,您可以通过为系统 Pod 定义 PDB 和为使用本地存储空间的 Pod 设置 "cluster-autoscaler.kubernetes.io/safe-to-evict": "true" 注释来更改此行为,这些方式可以让自动扩缩器安全重启。此外,考虑运行无法在单独的节点池中重启的长期 Pod,这样它们便不会阻止其他节点的缩减。最后,学习如何分析日志中的 CA 事件 以了解特定扩缩活动未按预期发生的原因。

如果您的工作负载可以应对意外重启的节点和容量损失,则您可以通过创建具有抢占式虚拟机的集群或节点池,节省更多资金。为确保 CA 按预期运行,Pod 资源请求必须足够大,以便 Pod 正常运行。如果资源请求太小,节点可能没有足够的资源,进而可能导致 Pod 在运行时崩溃或出现问题。

下面简要介绍了在您的集群中启用集群自动扩缩器的最佳做法:

  • 使用 HPA 或 VPA 自动扩缩您的工作负载。
  • 确保遵循所选 Pod 自动扩缩器中描述的最佳做法。
  • 通过设置适当的资源请求和限制正确调整应用大小,或者使用 VPA。
  • 为您的应用定义 PDB。
  • 为可能阻止纵向缩容的系统 Pod 定义 PDB。例如:kube-dns为了避免集群临时性中断,请不要为仅具有 1 个副本的系统 Pod(例如 metrics-server)设置 PDB。
  • 运行短期 Pod 和可以在单独的节点池中重启的 Pod,这样长期 Pod 就不会阻止其纵向缩容。
  • 通过在集群中预配空闲节点来避免过度预配。为此,您必须了解您的最小容量(对于许多公司来说夜间容量最小),并在节点池中设置最小节点数来支持该容量。
  • 如果您在高峰期需要额外的容量来应对请求,请使用暂停 Pod,自动扩缩器和过度预配将对此类型进行介绍。

如需了解详情,请参阅自动扩缩集群

节点自动预配

节点自动预配 (NAP) 是集群自动扩缩器的一种机制,除了代表用户管理节点池大小之外,还可以自动添加新的节点池。如果没有节点自动预配功能,则 GKE 只会考虑启动一组用户创建的节点池中的新节点。有了节点自动预配功能,GKE 便可以自动创建和删除新节点池。

节点自动预配功能往往通过动态创建最契合计划工作负载的节点池,以减少资源浪费。但是,如果需要创建新节点池,自动扩缩延迟时间可能会略有增加。如果您的工作负载可以应对意外重启的节点和容量损失,则您可以通过在 Pod 中配置抢占式虚拟机的容忍设置,进一步降低费用。

以下是启用节点自动预配功能的最佳做法:

  • 遵循集群自动扩缩器的所有最佳做法。
  • 设置最小和最大资源大小,以避免在应用未接收流量时,NAP 在集群中做出重大更改。
  • 为服务工作负载使用 Pod 横向自动扩缩器时,请考虑预留一个稍大的目标利用率缓冲区,因为在某些情况下,NAP 可能会提高自动扩缩延迟时间。

如需了解详情,请参阅使用节点自动预配不支持的功能

自动扩缩器和过度预配

为了控制费用,我们强烈建议您根据上一部分的说明启用自动扩缩器。由于没有一种配置适用于所有可能的场景,因此您必须为您的工作负载微调设置,以确保自动扩缩器能够正确应对流量增加的情况。

不过,正如 Pod 横向自动扩缩器部分所述,由于基础架构预配,纵向扩容可能需要一些时间才能完成。要直观呈现这种时间差和可能的纵向扩容场景,请参考下图。

直观呈现时间差和可能的纵向扩容场景。

当您的集群有足够的空间来部署新 Pod 时,便会触发一种工作负载纵向扩容场景。这意味着,如果现有节点从未部署过应用,则必须在启动 Pod 之前先下载其容器映像(场景 1)。但是,如果同一节点必须启动应用的新 Pod 副本,则纵向扩容时间便会减少,因为不需要下载映像(场景 2)。

当您的集群没有足够的空间来部署新 Pod 时,便会触发一种基础架构和工作负载纵向扩容场景。这意味着,集群自动扩缩器必须先预配新节点并启动所需软件,然后才能处理应用(场景 1)。如果您使用了节点自动预配功能,则根据计划的工作负载,可能需要新的节点池。在这种情况下,纵向扩容时间会增加,因为集群自动扩缩器必须预配节点和节点池(场景 2)。

在需要新基础架构的场景中,不要过度压缩集群,也就是说您必须过度预配,但这只是为了预留必要的缓冲区,以在纵向扩容期间应对预期的峰值请求。

这种过度预配有两种主要策略:

  • 微调 HPA 利用率目标。以下公式是找到理想 CPU 目标的简单且安全的方法:

    (1 - buff)/(1 + perc)

    • buff 是一个安全缓冲区,您可以对其进行设置以避免 CPU 达到 100%。此变量非常有用,因为 CPU 达到 100% 意味着请求处理的延迟时间远远高于正常值。
    • perc 是您期望在两分钟或三分钟内增长的流量增长百分比。

    例如,如果您期望在请求中获得 30% 的增长,并且想要通过定义 10% 的安全缓冲区来避免 CPU 达到 100%,那么您的公式可能如下所示:

    (1 - 0.1)/(1 + 0.3) = 0.69

  • 配置暂停 Pod。无法将集群自动扩缩器配置为提前启动节点。相反,您可以改为设置 HPA 利用率目标来提供可帮助应对负载高峰的缓冲区。但是,如果您预计会发生流量剧烈激增,则设置小 HPA 利用率目标可能不足以应对,或者可能成本过高。

    此问题的替代解决方案是使用暂停 Pod。暂停 Pod 是低优先级部署,除了在集群中预留空间之外不执行任何操作。每当安排高优先级 Pod 时,暂停 Pod 便会被逐出,而高优先级 Pod 会立即取代其位置。然后,系统会重新安排被逐出的暂停 Pod,如果集群中没有空间,那么集群自动扩缩器会启动新节点来存放这些 Pod。最佳做法是每个节点只设置一个暂停 Pod。例如,如果您使用 4 个 CPU 节点,请将暂停 Pod 的 CPU 请求配置为大约 3200m。

选择合适的机器类型

除自动扩缩外,其他配置可帮助您在 GKE 上运行经过费用优化的 kubernetes 应用。本部分将介绍如何选择合适的机器类型。

抢占式虚拟机

抢占式虚拟机 (PVM) 是 Compute Engine 虚拟机实例,最多可存在 24 小时并且不提供任何可用性方面的保证。与标准 Compute Engine 虚拟机相比,PVM 价格最高可便宜 80%,但我们建议您在 GKE 集群上使用它们时要十分谨慎。GKE 上的 PVM 最适合运行对此类虚拟机的临时性和无保证性不太敏感的批处理或容错作业。除非您准备好系统和架构来应对 PVM 的限制条件,否则有状态工作负载和服务工作负载不得使用 PVM。

无论工作负载类型如何,都必须注意以下限制条件:

  • 因为可抢占性节点可能会意外关停,所以可能不会考虑 Pod 中断预算。
  • 无法保证 Pod 会在节点抢占忽略 Pod 宽限期正常关停
  • GKE 可能需要几分钟时间才能检测到节点已被抢占且 Pod 不再运行,这会延迟将 Pod 重新安排到新节点的时间。

为了缓解这些限制,您可以在集群中部署一个社区节点终止事件处理脚本项目(重要说明:这不是 Google 官方项目),该项目提供一个可将 Compute Engine 节点终止事件转换为 Kubernetes 中 Pod 安全终止的适配器。一旦确定仍旧无法采用 Pod 中断预算,此社区项目便无法可靠地解决 PVM 的所有限制条件。因此,可能需要更长时间才能重新安排 pod。

最后,PVM 无法保证其可用性,这意味着某些地区很容易出现机器缺货的情况。如需克服此限制,我们建议您设置一个不需要 PVM 的备用节点池。由于集群自动扩缩器已针对基础架构费用进行优化,因此会优先使用 PVM。

如需了解详情,请参阅在 GKE 上运行抢占式虚拟机使用费用优化的 Spot 虚拟机在 GKE 上运行 Web 应用

E2 机器类型

E2 机器类型(E2 虚拟机)是费用优化型虚拟机,与 N1 机器类型相比,这种类型可以让您节省 31% 的费用。E2 虚拟机适用于多种工作负载,包括 Web 服务器、微服务、业务关键型应用、中小型数据库和开发环境。

如需详细了解 E2 虚拟机及其与其他 Google Cloud 机器类型的对比情况,请参阅 E2 虚拟机中的性能驱动型动态资源管理机器类型

选择适当的地区

在费用受限的情况下,运行 GKE 集群的位置便十分重要。由于诸多因素,费用因计算地区而异。因此,请确保以价格最低廉的方案运行工作负载,但也要确保延迟时间不会影响您的客户。如果您的工作负载需要将数据从一个地区复制到另一个地区(例如,运行批量作业),还必须考虑移动此数据的费用。

如需详细了解如何选择合适的地区,请参阅选择 Compute Engine 地区的最佳做法

注册承诺使用折扣

如果您打算使用 Google Cloud 的时间长达几年,我们强烈建议您购买承诺使用折扣,以获得大幅度的虚拟机使用费折扣。签署承诺使用合约以后,作为承诺为计算资源付费 1 年或 3 年的回报,您可以按折扣价(最高可享受 70% 的折扣)购买这些资源。如果您不确定要提交的资源数量,请查看您的最低计算使用量(例如,夜间使用的数量),然后按该使用量提交付款。

如需详细了解不同机器类型的承诺使用价格,请参阅虚拟机实例价格

查看小型开发集群

对于需要最大限度地降低费用的小型开发集群,请考虑使用 Autopilot 集群。采用这种操作模式的集群时,您无需为系统 Pod、操作系统费用或未调度的工作负载付费。

查看您的日志记录和监控策略

如果您使用 Cloud LoggingCloud Monitoring 来观察应用和基础架构,则只需为所用资源付费即可。但是,您的基础架构和应用记录的内容越多且您保留这些日志的时间越长,您需要为它们支付的费用就越多。同样,您拥有的外部指标和自定义指标越多,费用就越高。根据 Cloud Logging、Cloud Monitoring 和应用性能管理的费用优化中的说明,查看您的日志记录和监控策略。

查看地区级集群和多区域集群中的地区间出站流量

可用的 GKE 集群类型包括:单区域多区域、和地区级。由于跨区域的节点具有高可用性,因此地区级集群和多区域集群非常适合生产环境。不过,您需要按照区域之间的出站流量付费。对于生产环境,我们建议您监控跨区域的流量负载,并改进 API 以尽量减少该负载。此外,还应考虑使用 Pod 之间的亲和性和反亲和性配置,将来自同一节点或同一可用性区域中不同服务的从属 Pod 共置,以最大限度地减少它们之间的费用和网络延迟时间。建议监控此流量的方法是启用 GKE 用量计量及其网络出站流量代理(默认处于停用状态)。

对于非生产环境,节约费用的最佳做法是部署单区域集群。

准备适应工作负载类型的环境

企业有不同的费用和可用性要求。企业的工作负载可以分为服务工作负载(这类工作负载必须快速响应流量激增或高峰)和批处理工作负载(这类工作负载与最终要完成的工作有关)。服务工作负载需要较短的纵向扩容延迟时间;而批处理工作负载可以容忍更长的延迟时间。对这些工作负载类型的不同期望让用户可以更灵活地选择不同的节省费用的方法。

批处理工作负载

由于批处理工作负载与最终工作有关,并且在作业启动时通常可以容忍一段延迟时间,因此这类工作负载允许在 GKE 上节省费用。这种容忍度为集群自动扩缩器提供了空间,可以仅在安排作业时启动新节点,并在完成作业时关停这些节点。

第一种推荐做法是使用标签和选择器,以及使用污点和容忍设置区分不同节点池中的批处理工作负载。理由如下:

  • 集群自动扩缩器可以在不需要重启 pod 时更快地删除空节点。批量作业完成后,如果工作负载在当前为空的专用节点上运行,则集群会加快纵向缩容过程。要进一步提高纵向缩容速度,请考虑配置 CA 的优化利用率配置文件
  • 某些 Pod 无法重启,因此它们会永久阻止其节点的纵向缩容。这些 Pod(包括系统 Pod)必须在不同的节点池上运行,这样才不会影响纵向缩容。

第二个建议做法是使用节点自动预配功能,为具有匹配污点或容忍设置的作业自动创建专用节点池。这样,您无需对所有不同节点池进行设置,就可以区分许多不同的工作负载。

我们建议您仅在运行对抢占式虚拟机的临时性和无保证性不太敏感的容错作业时,才使用抢占式虚拟机。

如需详细了解如何设置遵循这些做法的环境,请参阅在使用节点自动预配功能的多租户 GKE 集群中优化资源用量教程。

服务工作负载

与批处理工作负载不同,服务工作负载必须尽快响应流量激增或高峰。流量突然增加可能是由多种因素造成的,例如电视广告、黑色星期五之类的峰值事件或重大新闻。您的应用必须准备好应对它们。

应对这种流量高峰时出现的问题通常与以下一种或多种原因有关:

  • 应用尚未准备好在 Kubernetes 上运行,例如,应用映像大小较大、启动时间过长或 Kubernetes 配置不够优化。
  • 应用依赖预配耗时的基础架构(例如 GPU)。
  • 未正确设置自动扩缩器和过度预配

准备云端 Kubernetes 应用

本部分介绍的部分最佳做法本身就可以节省资金。但是,由于大多数做法旨在让您的应用可靠地使用自动扩缩器,因此我们强烈建议您实施它们。

了解您的应用容量

在规划应用容量时,请了解应用可以应对的并发请求数量、需要的 CPU 和内存数量,以及高负载状态下的应用响应方式。大多数团队都不了解这些容量,因此我们建议您测试应用在压力下的行为方式。尝试在关闭自动扩缩功能的情况下隔离单个应用 Pod 副本,然后执行模拟实际用量负载的测试。这有助于您了解每个 Pod 的容量。随后,我们建议您配置集群自动扩缩器、资源请求和限制,以及 HPA 或 VPA。然后,再次给应用施压,但要用更大的强度来模拟突然的流量激增或高峰。

理想情况下,这些测试的运行位置必须是应用在 Google Cloud 上运行的同一地区或区域,以消除延迟问题。您可以使用自己选择的工具进行测试,无论工具是自制脚本还是更高级的性能工具(如 Apache BenchmarkJMeterLocust)。

如需查看如何执行测试的示例,请参阅使用 Google Kubernetes Engine 执行分布式负载测试

确保您的应用能够纵向增长和横向增长

确保您的应用能够增长和缩减。这意味着您可以选择通过添加更多 CPU 和内存,或添加更多 Pod 副本来应对流量增加。无论是不同的自动扩缩器设置还是不同的节点大小,这让您可以灵活地实验哪种方式更适合您的应用。遗憾的是,一些应用是单线程的,或受固定数量的工作器或子进程的限制,这些工作器和子进程在没有完全重构其架构的情况下无法进行此实验。

设置适当的资源请求和限制

通过了解应用容量,您可以确定要在容器资源中配置的内容。Kubernetes 中的资源主要定义为 CPU 和内存 (RAM)。您可以通过使用 spec.containers[].resources.requests.<cpu|memory> 请求将 CPU 和内存配置为运行应用所需的容量,并使用 spec.containers[].resources.limits.<cpu|memory> 请求来配置上限。

正确设置资源请求后,Kubernetes 调度器可以使用它们来确定将 Pod 放置在哪个节点上。这可确保 Pod 被放置在能够其正常运行的节点中,让您提升稳定性并减少资源浪费。此外,定义资源限制有助于确保这些应用绝对不会使用由计算节点提供的所有可用的底层基础架构。

设置容器资源的一个良好做法是为请求和限制使用相同数量的内存,并使用更大或无界限的 CPU 限制。以下面所示部署为例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wp
  template:
    metadata:
      labels:
        app: wp
    spec:
      containers:
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "128Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"

上面模式的推理基于应对 Kubernetes 资源不足的工作原理。简而言之,当计算机资源耗尽时,节点开始不稳定。为避免这种情况,kubelet 通过对资源短缺的 Pod 进行排名,从而对其进行监控并防止资源完全耗尽。当 CPU 被争用时,可以将这些 Pod 调低到其请求的值。但是,由于内存是无法压缩的资源,因此当内存耗尽时,需要移除 Pod。为避免 Pod 被移除(进而使您的环境变得不稳定),您必须将所请求的内存设置为内存限制。

您还可以在建议模式下使用 VPA 来助您确定给定应用的 CPU 和内存用量。由于 VPA 会根据应用的使用情况提供此类建议,因此我们建议您在类似生产的环境中启用它,以应对实际流量。然后,VPA 状态将生成包含建议的资源请求和限制的报告,您可以在部署清单中静态指定该报告。如果您的应用已定义了 HPA,请参阅将 HPA 和 VPA 混用

确保您的容器尽可能精简

在容器中运行应用时,请务必遵循构建这些容器的部分做法。在 Kubernetes 上运行这些容器时,其中一些做法更为重要,因为您的应用可以随时启动和停止。本部分重点介绍以下两种做法:

  • 尽可能缩小映像。最佳做法是使用小映像,因为每次集群自动扩缩器预配集群的新节点时,节点都必须下载要在该节点中运行的映像。映像越小,节点下载速度越快。

  • 尽快启动应用。由于类加载、缓存等过程,某些应用可能需要几分钟才能启动。如果 Pod 需要长时间启动,那么客户的请求可能会在启动应用时失败。

在设计系统时,特别是您预计会经历流量激增或高峰时,请考虑采用这两种做法。使用小映像和快速启动有助于减少纵向扩容延迟时间。因此,您可以更好地应对流量增加的情况,而无需过多担心稳定性。这些做法与 GKE 自动扩缩中介绍的自动扩缩最佳做法搭配使用,效果更出众。

如需详细了解如何构建容器,请参阅构建容器的最佳做法

将 Pod 中断预算添加到您的应用

Pod 中断预算 (PDB) 限制可同时从自愿中断删除的 Pod 数量。这意味着在系统在发布、节点升级以及任何自动扩缩活动时都会考虑定义的中断预算。但是,如果发生意外情况(例如硬件故障、内核故障或某人误删虚拟机),则可能无法保证此预算。

在集群自动扩缩器压缩阶段考虑 PDB 时,最佳做法是为每个应用都定义 Pod 中断预算。这样,您就可以在任何给定时间(包括 CA 纵向缩容您的集群时)控制支持负载所需的最低副本数。

如需了解详情,请参阅为应用指定中断预算

为您的应用设置有意义的就绪性和活跃性探测

设置有意义的探测可确保您的应用仅在启动、运行并且准备好接受流量时才接收流量。GKE 使用就绪性探测来确定何时将 Pod 添加到负载平衡器或何时从负载平衡器中移除 Pod。GKE 使用活动性探测来确定何时重启 Pod。

活跃性探测有助于告知 Kubernetes 特定 Pod 无法取得进展(例如检测到死锁状态时)。就绪性探测有助于告知 Kubernetes 您的应用尚未准备好接收流量(例如启动时加载大型缓存数据)。

为确保纵向扩容活动期间应用的正确生命周期,请务必执行以下操作:

  • 为所有容器定义就绪性探测。
  • 如果您的应用依赖于启动时加载的缓存,则就绪性探测必须且只能在缓存完全加载后才发出已就绪信号。
  • 如果您的应用可以立即开始工作,那么可以尽可能简单地实施良好的默认探测,例如,返回 200 状态代码的 HTTP 端点。
  • 如果您实施更高级的探测(例如检查连接池是否具有可用资源),那么请确保与较为简单的探测实施相比,错误率不会增加
  • 切勿让任何探测逻辑访问其他服务。如果这些服务没有及时响应,则探测逻辑可能会破坏 Pod 的生命周期。

如需了解详情,请参阅配置活跃性、就绪性和启动探测

确保按照 Kubernetes 的预期关闭您的应用

自动扩缩器通过启动新的 Pod 和节点并在高峰结束时将其删除,来帮助您响应流量高峰。这意味着,为了避免在工作时出现错误,您的 Pod 必须做好快速启动或安全关停的准备。

由于 Kubernetes 异步更新端点和负载平衡器,因此为了确保无中断关停,请务必遵循以下最佳做法:

  • 请勿在 SIGTERM 之后立即停止接受新请求。您的应用不能立即停止,而是要完成所有正在处理的请求,并且仍要监听 Pod 终止开始之后到达的传入连接。Kubernetes 可能需要一段时间才能更新所有 kube-proxies 和负载平衡器。如果您的应用在上述更新之前终止,某些请求可能会导致客户端出错。
  • 如果您的应用没有遵循上述做法,请使用 preStop 钩子。大多数程序都不会立即停止接受请求。但是,如果您使用的是第三方代码或者正在管理您无法控制的系统(例如 nginx),则在不修改应用的情况下,preStop 钩子是触发安全关停的不错选择。一种常用的策略是在 preStop 中执行几秒钟休眠以推迟 SIGTERM。这不仅可以为 Kubernetes 提供额外的时间,以完成 Pod 删除过程,还可以减少客户端的连接错误。
  • 处理 SIGTERM 以执行清理。如果您的应用必须执行清理或具有在进程终止之前必须保留的内存中状态,现在便是执行此操作的时候。不同的编程语言有不同的方法来捕获此信号,因此请根据您的语言找到合适的方法。
  • 配置 terminationGracePeriodSeconds 以满足您的应用需求。一些应用需要超过默认值 30 秒才能完成。在这种情况下,您必须指定 terminationGracePeriodSeconds。例如,较高的值可能会增加节点升级或发布的时间。较低的值可能无法为 Kubernetes 提供足够的时间来完成 Pod 终止过程。无论采用哪种方式,我们都建议您将应用的终止期设置为 10 分钟以内,因为集群自动扩缩器的执行时长仅有 10 分钟
  • 如果您的应用使用容器原生负载平衡,请在接收到 SIGTERM 时着手停止就绪性探测。此操作会直接指示负载平衡器停止将新请求转发到后端 Pod。根据健康检查配置与端点编程之间的争用情况,后端 Pod 可能会提前停用流量。

如需了解详情,请参阅 Kubernetes 最佳做法:安全终止

设置 NodeLocal DNSCache

由 GKE 管理的 DNS 通过 kube-dns(部署在所有 GKE 集群中的插件)实现。当您运行 DNS 短缺的应用时,根据集群中的节点数和核心数调整 kube-dns 副本数量的默认 kube-dns-autoscaler 配置可能不足以提供支持。在这种情况下,DNS 查询可能会减慢或超时。为了缓解此问题,公司习惯调整 kube-dns-autoscaler ConfigMap 以增加集群中的 kube-dns 副本数量。虽然此策略可能会按预期运行,但会增加资源用量和 GKE 总费用。

另一种可优化费用且扩缩能力更强的替代方案是在集群中配置 NodeLocal DNSCache。NodeLocal DNSCache 是可选的 GKE 插件,通过在每个集群节点上运行 DNS 缓存缩短 DNS 查找的延迟时间、使 DNS 查找时间更加一致,并将 DNS 查询的数量减少至 kube-dns

如需了解详情,请参阅设置 NodeLocal DNSCache

通过 Ingress 使用容器原生负载平衡

容器原生负载平衡让负载平衡器直接定位 Kubernetes Pod,并使用名为网络端点组 (NEG) 的数据模型将流量均匀分布到 Pod 上。此方法可改善网络性能、提高可见性,实现高级负载平衡功能,并且支持使用 Traffic Director(Google Cloud 专为服务网格打造的全代管式流量控制层面)。

由于具备这些优势,因此容器原生负载平衡是通过 Ingress 实现负载平衡的建议解决方案。将 NEG 与 GKE Ingress 搭配使用时,Ingress 控制器会协助创建 L7 负载平衡器的所有方面。这包括创建虚拟 IP 地址、转发规则、健康检查、防火墙规则等等。

当使用集群自动扩缩器时,容器原生负载平衡变得更加重要。对于非 NEG 负载平衡器来说,在纵向缩容期间,如果集群自动扩缩器没有终止节点实例,则可能无法完全完成负载平衡编程和连接排空。即使后端 Pod 不在节点上,这也可能中断流经节点的正在进行的连接。

当满足下述所有条件时,系统将默认为 Service 启用容器原生负载平衡:

  • Services 是在 GKE 集群 1.17.6-gke.7 及更高版本中创建的。
  • 您使用的是 VPC 原生集群。
  • 您未使用共享 VPC。
  • 您未使用 GKE 网络政策。

如需了解详情,请参阅 Ingress GKE 文档使用容器原生负载平衡

考虑使用指数退避算法重试

在 Kubernetes 上运行的微服务架构中,可能会由于各种原因而发生暂时性故障,例如:

这些问题是暂时的,您可以在延迟后再次调用服务以缓解这些问题。但是,为了避免请求让目标服务不堪重负,请务必使用指数退避算法执行这些调用。

为方便此类重试模式,许多现有库都实施了指数级重新试验逻辑。您可以使用自己选择的库或编写自己的代码。如果您使用 IstioAnthos Service Mesh (ASM),则可以选择代理级别的重试机制,该机制将以透明的方式代表您执行重试。

请务必为您的应用制定计划以支持服务调用重试,例如,避免插入已插入的信息。请注意,重试链可能会影响最终用户的延迟时间,如果未正确规划,可能会超时。

监控您的环境并实施费用优化的配置和做法

在许多大中型企业中,集中式平台和基础架构团队通常负责为整个公司创建、维护和监控 Kubernetes 集群。这表明公司对于资源使用问责制以及确保所有团队都遵守公司政策有着强烈的需求。本部分将介绍用于监控和实施费用相关做法的方案。

观察您的 GKE 集群并注意建议

您可以通过检查容器、Pod 和服务以及整个集群的特性来查看 Kubernetes 集群中的资源利用率。您可以通过多种方式来执行此任务,但我们建议您从通过 Monitoring 信息中心观察 GKE 集群入手。该方法将为您提供集群使用情况的时间序列数据,可以让您从基础架构、工作负载和服务各层级结构逐一汇总集群信息。

尽管这是一种良好的入手方法,但 Google Cloud 还提供了其他选项,例如:

  • 在 Google Cloud 控制台的 GKE 集群页面上,查看通知列。如果集群中的资源浪费过多,界面会提示您总体分配的信息与请求的信息。

    转到 GKE 集群列表

  • 在 Google Cloud 控制台的建议页面上,找到节省的费用建议卡片。

    转到 Recommendation Hub

如需了解详情,请参阅观察 GKE 集群Recommendation Hub 使用入门

启用 GKE 用量计量

如需一个更灵活的方法来了解大致的费用明细,请尝试使用 GKE 用量计量。GKE 用量计量功能可让您查看按命名空间和标签细分的 GKE 集群用量概况。它会跟踪集群工作负载的资源请求和资源消耗量信息,例如 CPU、GPU、TPU、内存、存储空间以及可选的网络出站流量。

GKE 用量计量有助于您了解 GKE 集群的整体费用结构、哪些团队或应用支出最多,哪些环境或组件导致使用量或费用突然激增,以及哪个团队正在造成浪费资源。通过对比资源请求与实际利用率,您可以了解哪些工作负载预配不足或过度预配。

您可以利用默认 Looker 数据洞察模板,也可以根据自己的组织需求进一步自定义信息中心。如需详细了解 GKE 用量计量及其前提条件,请参阅了解集群资源用量

了解 Metrics Server 的工作原理并对其进行监控

Metrics Server 是 GKE 内置自动扩缩流水线的容器资源指标的来源。Metrics Server 会从 kubelet 检索指标,并通过 Kubernetes Metrics API 公开这些指标。然后,HPA 和 VPA 将使用这些指标来确定何时触发自动扩缩。

为了确保 GKE 自动扩缩的运行状况,您必须具有运行状况良好的 Metrics Server。使用 GKE metrics-server 部署时,系统会安装调整器 nanny,从而根据集群的节点数添加或移除 CPU 和内存,让 Metrics Server 容器纵向增长。Kubernetes 仍然不支持 Pod 就地更新,这也是 nanny 必须重启 metrics-server Pod 才能应用全新所需资源的原因。

虽然重启会速度很快,但在调整 metrics-server 大小后,自动扩缩器意识到自身必须执行操作的总延迟时间可能会略有增加。为避免 Metrics Server 在快速变化的集群(从 GKE 1.15.11-gke.9 版本开始)中频繁重启,nanny 支持调整大小延迟

使用 Metrics Server 时,请遵循以下最佳做法:

  • 选择支持 metrics-server 调整大小延迟的 GKE 版本。如需确认版本,您可以在 metrics-server-nanny 容器中检查 metrics-server 部署 YAML 文件是否具有 scale-down-delay 配置。
  • 监控 metrics-server 部署。如果 Metrics Server 关闭,则意味着不存在任何正在工作的自动扩缩。您希望使用优先级最高的监控服务来监控此部署。
  • 遵循 GKE 自动扩缩中讨论的最佳做法。

使用 Kubernetes 资源配额

在多租户集群中,不同的团队通常负责在不同命名空间中部署的应用。对于集中式平台和基础架构小组,需要关注的问题是团队可能使用超出需求的资源。消耗所有集群的计算资源,甚至连触发次数过多的纵向扩容都会增加您的费用。

为解决此问题,您必须使用资源配额。资源配额用于管理命名空间中对象使用的资源量。您可以按计算(CPU 和内存)和存储资源或对象数量来设置配额。通过资源配额,您可以确保租户不会使用超过其分配份额的集群资源。

如需了解详情,请参阅为命名空间配置内存和 CPU 配额

考虑使用 GKE Enterprise Policy Controller

GKE Enterprise Policy Controller (APC) 是 Kubernetes 动态准入控制器,这种控制器会根据与安全、法规或任意业务规则相关的政策检查、审核和实施集群的合规性。Policy Controller 使用限制条件来实施集群的合规性。例如,您可以将其安装在适用于准备云端 Kubernetes 应用部分讨论的多种最佳做法的集群限制条件中。这样一来,如果部署没有严格遵循您的 Kubernetes 做法,便会被拒绝。实施此类规则有助于避免异常的费用激增,并降低在自动扩缩期间工作负载不稳定的可能性。

如需详细了解如何实施和编写自己的规则,请参阅创建限制条件编写限制条件模板。如果您不是 GKE Enterprise 客户,则可以考虑使用开源软件 Gatekeeper,它是 APC 的构建基础。

设计 CI/CD 流水线以实施节省费用的做法

GKE Enterprise Policy Controller 可帮助您避免在 GKE 集群中部署不合规的软件。但是,我们建议您在开发周期早期(无论是在预提交检查、拉取请求检查、交付工作流程还是在环境中起作用的任何步骤)实施此类政策限制。这种做法可以帮助您快速找到和修复错误配置,并通过创建保护措施来帮助您了解需要注意的事项。

此外,请考虑在 CI/CD 流水线中使用 kpt 函数来验证您的 Kubernetes 配置文件是否遵守了 GKE Enterprise Policy Controller 实施的限制条件,并估算资源利用率或部署费用。这样,您就可以在检测到费用相关问题时停止流水线。或者,您可以为配置(例如增加副本数量)创建不同的部署审核流程。

如需了解详情,请参阅在 CI 流水线中使用 Policy Controller;如需查看交付平台的完整示例,请参阅借助 GKE Enterprise 实现现代化 CI/CD

宣传节省费用文化

许多组织会创建抽象信息和平台来向您隐藏基础架构的复杂性。对于将服务从虚拟机迁移到 Kubernetes 的公司来说,这是十分常见的做法。有时,这些公司会允许开发者在生产环境中配置自己的应用。然而,开发者从未接触过 Kubernetes 集群这一现象也并不罕见。

本部分中建议的做法并不表示您应该彻底停止创建抽象信息。相反,以下做法帮助您查看您在 Google Cloud 上的支出,并向您的开发者和操作员培训基础架构方面的知识。为实现此目的,您可以创建可以在其中使用传统或在线课程、论坛、对等审核、结对编程、CI/CD 和费用节省游戏化等方式的学习激励措施和计划。例如,在 Kubernetes 环境中,了解应用映像为 3 Gb、缺少就绪性探测或 HPA 配置错误的影响十分重要。

最后,正如 Google 的 DORA 研究成果中所述,文化能力是驱动更好的组织性能、更少的重复性工作、更弱的倦怠等状况的一些主要因素。而节省费用也不例外。授予员工对支出的访问权限能让他们能够更贴近业务目标并且更了解限制条件。

最佳做法摘要

下表总结了本文档中建议的最佳做法。

主题 任务
GKE 费用优化功能和选项
准备您的云原生 Kubernetes 应用
监控您的环境并实施费用优化的配置和做法
文化

后续步骤