水平 Pod 自动扩展

在 Kubernetes 中,HorizontalPodAutoscaler 会自动更新工作负载资源(例如 DeploymentStatefulSet),目的是自动扩展工作负载以匹配需求。

水平扩展意味着对负载增加的响应是部署更多 Pod。这不同于垂直扩展,对于 Kubernetes 来说,垂直扩展意味着为已在为工作负载运行的 Pod 分配更多资源(例如:内存或 CPU)。

如果负载减少,并且 Pod 数量超过配置的最小值,则 HorizontalPodAutoscaler 会指示工作负载资源(Deployment、StatefulSet 或其他类似资源)缩减规模。

水平 Pod 自动扩展不适用于无法扩展的对象(例如:DaemonSet。)

HorizontalPodAutoscaler 作为 Kubernetes API 资源和 控制器 来实现。该资源决定了控制器的行为。水平 Pod 自动扩展控制器在 Kubernetes 控制平面 内运行,定期调整其目标(例如,Deployment)的所需规模,以匹配观察到的指标,例如平均 CPU 利用率、平均内存利用率或您指定的任何其他自定义指标。

有一个关于使用水平 Pod 自动扩展的演练示例

HorizontalPodAutoscaler 如何工作?

graph BT hpa[水平 Pod 自动扩展器] --> scale[规模] subgraph rc[RC / Deployment] scale end scale -.-> pod1[Pod 1] scale -.-> pod2[Pod 2] scale -.-> pod3[Pod N] classDef hpa fill:#D5A6BD,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef rc fill:#F9CB9C,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef scale fill:#B6D7A8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef pod fill:#9FC5E8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; class hpa hpa; class rc rc; class scale scale; class pod1,pod2,pod3 pod

图 1. HorizontalPodAutoscaler 控制 Deployment 及其 ReplicaSet 的规模

Kubernetes 将水平 Pod 自动扩展实现为一个间歇运行的控制循环(它不是一个连续的过程)。间隔由 kube-controller-manager--horizontal-pod-autoscaler-sync-period 参数设置(默认间隔为 15 秒)。

在每个周期中,控制器管理器都会根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。控制器管理器找到 scaleTargetRef 定义的目标资源,然后根据目标资源的 .spec.selector 标签选择 Pod,并从资源指标 API(用于每个 Pod 的资源指标)或自定义指标 API(用于所有其他指标)获取指标。

  • 对于每个 Pod 的资源指标(如 CPU),控制器从资源指标 API 中获取 HorizontalPodAutoscaler 目标的每个 Pod 的指标。然后,如果设置了目标利用率值,则控制器会将利用率值计算为每个 Pod 中容器上等效 资源请求 的百分比。如果设置了目标原始值,则直接使用原始指标值。然后,控制器获取所有目标 Pod 的利用率或原始值(取决于指定的目标类型)的平均值,并生成用于扩展所需副本数量的比率。

    请注意,如果某些 Pod 的容器没有设置相关的资源请求,则不会定义 Pod 的 CPU 利用率,并且自动扩展器不会对该指标采取任何操作。有关自动扩展算法工作原理的更多信息,请参阅下面的算法详细信息部分。

  • 对于每个 Pod 的自定义指标,控制器的功能与每个 Pod 的资源指标类似,只是它使用原始值,而不是利用率值。

  • 对于对象指标和外部指标,将获取单个指标,该指标描述了相关对象。将此指标与目标值进行比较,以生成如上所述的比率。在 autoscaling/v2 API 版本中,可以选择在进行比较之前将此值除以 Pod 的数量。

HorizontalPodAutoscaler 的常见用途是将其配置为从 聚合 APImetrics.k8s.iocustom.metrics.k8s.ioexternal.metrics.k8s.io)获取指标。metrics.k8s.io API 通常由名为 Metrics Server 的附加组件提供,该附加组件需要单独启动。有关资源指标的更多信息,请参阅Metrics Server

对指标 API 的支持解释了这些不同 API 的稳定性保证和支持状态。

HorizontalPodAutoscaler 控制器访问支持扩展的相应工作负载资源(例如 Deployment 和 StatefulSet)。这些资源都具有名为 scale 的子资源,这是一个接口,允许您动态设置副本数量并检查每个副本的当前状态。有关 Kubernetes API 中子资源的一般信息,请参阅Kubernetes API 概念

算法详细信息

从最基本的角度来看,HorizontalPodAutoscaler 控制器根据所需指标值与当前指标值之间的比率进行操作

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]

例如,如果当前指标值为 200m,而所需值为 100m,则副本数量将翻倍,因为 200.0 / 100.0 == 2.0 如果当前值为 50m,则副本数量将减半,因为 50.0 / 100.0 == 0.5。如果比率足够接近 1.0(在全局可配置的容差范围内,默认为 0.1),则控制平面会跳过任何扩展操作。

当指定了 targetAverageValuetargetAverageUtilization 时,通过获取 HorizontalPodAutoscaler 规模目标中所有 Pod 的给定指标的平均值来计算 currentMetricValue

在检查容差并决定最终值之前,控制平面还会考虑是否缺少任何指标,以及有多少 Pod Ready。所有设置了删除时间戳的 Pod(具有删除时间戳的对象正在关闭/删除过程中)都将被忽略,所有失败的 Pod 都将被丢弃。

如果缺少特定 Pod 的指标,则将其留待以后处理;具有缺少指标的 Pod 将用于调整最终扩展量。

当扩展 CPU 时,如果任何 Pod 尚未准备好(它仍在初始化中,或者可能不健康) Pod 的最新指标点是在它准备好之前,则该 Pod 也会被留待以后处理。

由于技术限制,HorizontalPodAutoscaler 控制器在确定是否保留某些 CPU 指标时,无法准确确定 Pod 首次准备好的时间。相反,如果 Pod 未准备好并在启动后的短时间可配置窗口内转换为就绪状态,则它会将 Pod 视为“尚未准备好”。此值使用 --horizontal-pod-autoscaler-initial-readiness-delay 标志配置,其默认值为 30 秒。一旦 Pod 准备好,如果它在启动后的较长时间可配置时间内发生,它会将任何转换为就绪状态的操作视为第一次。此值使用 --horizontal-pod-autoscaler-cpu-initialization-period 标志配置,其默认值为 5 分钟。

然后,使用上面未留待以后处理或丢弃的剩余 Pod 计算 currentMetricValue / desiredMetricValue 基本扩展比率。

如果缺少任何指标,则控制平面会更加保守地重新计算平均值,假设这些 Pod 在缩减规模的情况下消耗了所需值的 100%,在扩大规模的情况下消耗了 0%。这会抑制任何潜在规模的大小。

此外,如果存在任何尚未准备好的 Pod,并且工作负载会在不考虑缺少指标或尚未准备好的 Pod 的情况下扩大规模,则控制器会保守地假设尚未准备好的 Pod 消耗了所需指标的 0%,从而进一步抑制了扩大规模的幅度。

在考虑了尚未准备好的 Pod 和缺失的指标后,控制器会重新计算使用率。如果新比率导致缩放方向反转,或者在新比率在容差范围内,则控制器不会采取任何缩放操作。在其他情况下,新比率用于决定 Pod 数量的任何变化。

请注意,即使使用了新的使用率,也会通过 HorizontalPodAutoscaler 状态报告回平均利用率的*原始*值,而不会考虑尚未准备好的 Pod 或缺失的指标。

如果在 HorizontalPodAutoscaler 中指定了多个指标,则会针对每个指标执行此计算,然后选择所需的副本数的最大值。如果任何这些指标无法转换为所需的副本数(例如,由于从指标 API 获取指标时出错)并且可以获取的指标建议缩减规模,则会跳过缩放。这意味着,如果一个或多个指标给出的“所需副本数”大于当前值,则 HPA 仍然能够扩展。

最后,在 HPA 缩放目标之前,会记录缩放建议。控制器会考虑可配置窗口内的所有建议,并从该窗口中选择最高建议。可以使用“--horizontal-pod-autoscaler-downscale-stabilization”标志配置此值,该标志默认为 5 分钟。这意味着缩减规模将逐渐发生,从而消除指标值快速波动带来的影响。

API 对象

Horizontal Pod Autoscaler 是 Kubernetes“autoscaling”API 组中的 API 资源。当前的稳定版本可以在“autoscaling/v2”API 版本中找到,该版本包括对基于内存和自定义指标进行扩展的支持。在使用“autoscaling/v1”时,“autoscaling/v2”中引入的新字段将保留为注释。

创建 HorizontalPodAutoscaler API 对象时,请确保指定的名称是有效的 DNS 子域名。有关 API 对象的更多详细信息,请参阅 HorizontalPodAutoscaler 对象

工作负载规模的稳定性

当使用 HorizontalPodAutoscaler 管理一组副本的规模时,由于所评估指标的动态性质,副本的数量可能会频繁波动。这有时被称为*抖动*或*拍打*。它类似于控制论中的*滞后*概念。

滚动更新期间的自动缩放

Kubernetes 允许您对 Deployment 执行滚动更新。在这种情况下,Deployment 会为您管理底层 ReplicaSet。为 Deployment 配置自动缩放时,您需要将 HorizontalPodAutoscaler 绑定到单个 Deployment。HorizontalPodAutoscaler 管理 Deployment 的“副本”字段。部署控制器负责设置底层 ReplicaSet 的“副本”,以便它们在推出期间以及之后加起来达到合适的数量。

如果您对具有自动缩放副本数的 StatefulSet 执行滚动更新,则 StatefulSet 会直接管理其 Pod 集(没有类似于 ReplicaSet 的中间资源)。

对资源指标的支持

任何 HPA 目标都可以根据缩放目标中 Pod 的资源使用情况进行缩放。在定义 Pod 规范时,应指定资源请求,例如“cpu”和“memory”。这用于确定资源利用率,并由 HPA 控制器用于向上或向下缩放目标。要使用基于资源利用率的缩放,请指定如下所示的指标源

type: Resource
resource:
  name: cpu
  target:
    type: Utilization
    averageUtilization: 60

使用此指标,HPA 控制器会将缩放目标中 Pod 的平均利用率保持在 60%。利用率是资源的当前使用量与 Pod 的请求资源量之比。有关如何计算和平均利用率的更多详细信息,请参阅 算法

容器资源指标

功能状态: Kubernetes v1.30 [稳定]

HorizontalPodAutoscaler API 还支持容器指标源,其中 HPA 可以跟踪一组 Pod 中各个容器的资源使用情况,以便缩放目标资源。这使您可以为特定 Pod 中最重要的容器配置缩放阈值。例如,如果您有一个 Web 应用程序和一个提供日志记录的边车容器,则可以根据 Web 应用程序的资源使用情况进行缩放,而忽略边车容器及其资源使用情况。

如果您修改目标资源以使用一组不同的容器来获得新的 Pod 规范,则应修改 HPA 规范(如果新添加的容器也应用于缩放)。如果指标源中指定的容器不存在或仅存在于 Pod 的子集中,则这些 Pod 将被忽略,并重新计算建议。有关计算的更多详细信息,请参阅 算法。要使用容器资源进行自动缩放,请定义如下所示的指标源

type: ContainerResource
containerResource:
  name: cpu
  container: application
  target:
    type: Utilization
    averageUtilization: 60

在上面的示例中,HPA 控制器会缩放目标,以便所有 Pod 的“应用程序”容器中 cpu 的平均利用率为 60%。

基于自定义指标进行缩放

功能状态: Kubernetes v1.23 [稳定]

(“autoscaling/v2beta2”API 版本以前将此功能作为测试版功能提供)

如果您使用“autoscaling/v2”API 版本,则可以将 HorizontalPodAutoscaler 配置为根据自定义指标(未内置到 Kubernetes 或任何 Kubernetes 组件中)进行缩放。然后,HorizontalPodAutoscaler 控制器会从 Kubernetes API 查询这些自定义指标。

有关要求,请参阅 对指标 API 的支持

基于多个指标进行缩放

功能状态: Kubernetes v1.23 [稳定]

(“autoscaling/v2beta2”API 版本以前将此功能作为测试版功能提供)

如果您使用“autoscaling/v2”API 版本,则可以为 HorizontalPodAutoscaler 指定多个指标以进行缩放。然后,HorizontalPodAutoscaler 控制器会评估每个指标,并根据该指标提出新的规模。HorizontalPodAutoscaler 会采用为每个指标建议的最大规模,并将工作负载设置为该规模(前提是该规模不超过您配置的总体最大值)。

对指标 API 的支持

默认情况下,HorizontalPodAutoscaler 控制器会从一系列 API 中检索指标。为了让它能够访问这些 API,集群管理员必须确保

  • API 聚合层已启用。

  • 已注册相应的 API

    • 对于资源指标,这是“metrics.k8s.io”API,通常由 metrics-server 提供。它可以作为集群插件启动。

    • 对于自定义指标,这是“custom.metrics.k8s.io”API。它由指标解决方案供应商提供的“适配器”API 服务器提供。请咨询您的指标管道,以查看是否有可用的 Kubernetes 指标适配器。

    • 对于外部指标,这是“external.metrics.k8s.io”API。它可能由上面提供的自定义指标适配器提供。

有关这些不同指标路径及其区别的更多信息,请参阅 HPA V2custom.metrics.k8s.ioexternal.metrics.k8s.io 的相关设计提案。

有关如何使用它们的示例,请参阅 使用自定义指标的演练使用外部指标的演练

可配置的缩放行为

功能状态: Kubernetes v1.23 [稳定]

(“autoscaling/v2beta2”API 版本以前将此功能作为测试版功能提供)

如果您使用“v2”HorizontalPodAutoscaler API,则可以使用“behavior”字段(请参阅 API 参考)来配置单独的放大和缩小行为。您可以通过在“behavior”字段下设置“scaleUp”和/或“scaleDown”来指定这些行为。

您可以指定一个*稳定窗口*,以防止缩放目标的副本数出现 抖动。缩放策略还允许您控制缩放时副本的变化率。

缩放策略

可以在规范的“behavior”部分中指定一个或多个缩放策略。当指定了多个策略时,默认情况下会选择允许最大更改量的策略。以下示例显示了缩小时的此行为

behavior:
  scaleDown:
    policies:
    - type: Pods
      value: 4
      periodSeconds: 60
    - type: Percent
      value: 10
      periodSeconds: 60

“periodSeconds”表示该策略必须保持为真的过去时间长度。您可以为“periodSeconds”设置的最大值为 1800(半小时)。第一个策略*(Pod)*允许在一分钟内最多缩减 4 个副本。第二个策略*(百分比)*允许在一分钟内最多缩减当前副本数的 10%。

由于默认情况下会选择允许最大更改量的策略,因此只有当 Pod 副本数超过 40 时才会使用第二个策略。对于 40 个或更少的副本,将应用第一个策略。例如,如果有 80 个副本,并且目标必须缩减到 10 个副本,则在第一步中,将减少 8 个副本。在下一次迭代中,当副本数为 72 时,Pod 数的 10% 为 7.2,但该数字会向上舍入为 8。在自动缩放器控制器的每个循环中,将根据当前副本数重新计算要更改的 Pod 数。当副本数降至 40 以下时,将应用第一个策略*(Pod)*,并且一次将减少 4 个副本。

可以通过为缩放方向指定“selectPolicy”字段来更改策略选择。通过将值设置为“Min”,这将选择在副本数中允许最小更改的策略。将值设置为“Disabled”将完全禁用该方向的缩放。

稳定窗口

稳定窗口用于在用于缩放的指标不断波动时限制副本数的 抖动。自动缩放算法使用此窗口来推断先前的所需状态,并避免对工作负载规模进行不必要的更改。

例如,在以下示例代码段中,为“scaleDown”指定了一个稳定窗口。

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300

当指标表明应缩减目标时,算法会查看先前计算的所需状态,并使用指定时间间隔内的最高值。在上面的示例中,将考虑过去 5 分钟内的所有所需状态。

这近似于滚动最大值,并避免了缩放算法频繁删除 Pod 只是为了在片刻之后触发重新创建等效 Pod 的情况。

默认行为

要使用自定义缩放,并非所有字段都必须指定。只能指定需要自定义的值。这些自定义值将与默认值合并。默认值与 HPA 算法中的现有行为匹配。

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
    - type: Pods
      value: 4
      periodSeconds: 15
    selectPolicy: Max

对于缩小规模,稳定窗口为 *300* 秒(或者如果提供了 `--horizontal-pod-autoscaler-downscale-stabilization` 标志,则为该标志的值)。缩小规模只有一个策略,允许移除当前正在运行的 100% 副本,这意味着可以将扩缩目标缩小到允许的最小副本数。对于扩大规模,没有稳定窗口。当指标表明应该扩大目标时,目标会立即扩大。有 2 个策略,在 HPA 达到稳定状态之前,每 15 秒最多可以添加 4 个 Pod 或当前正在运行的副本的 100%。

示例:更改缩小规模稳定窗口

要提供 1 分钟的自定义缩小规模稳定窗口,应将以下行为添加到 HPA

behavior:
  scaleDown:
    stabilizationWindowSeconds: 60

示例:限制缩小规模速率

要将 HPA 每分钟移除 Pod 的速率限制为 10%,应将以下行为添加到 HPA

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60

为了确保每分钟移除的 Pod 不超过 5 个,您可以添加第二个固定大小为 5 的缩小规模策略,并将 `selectPolicy` 设置为最小值。将 `selectPolicy` 设置为 `Min` 意味着自动缩放器会选择影响 Pod 数量最少的策略

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60
    - type: Pods
      value: 5
      periodSeconds: 60
    selectPolicy: Min

示例:禁用缩小规模

`selectPolicy` 值为 `Disabled` 会关闭给定方向的缩放。因此,要防止缩小规模,将使用以下策略

behavior:
  scaleDown:
    selectPolicy: Disabled

kubectl 中对 HorizontalPodAutoscaler 的支持

HorizontalPodAutoscaler 与所有 API 资源一样,都受到 `kubectl` 的标准方式支持。您可以使用 `kubectl create` 命令创建新的自动缩放器。您可以通过 `kubectl get hpa` 列出自动缩放器,或通过 `kubectl describe hpa` 获取详细描述。最后,您可以使用 `kubectl delete hpa` 删除自动缩放器。

此外,还有一个特殊的 `kubectl autoscale` 命令用于创建 HorizontalPodAutoscaler 对象。例如,执行 `kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80` 将为 ReplicaSet *foo* 创建一个自动缩放器,其目标 CPU 利用率设置为 `80%`,副本数介于 2 到 5 之间。

隐式维护模式停用

您可以隐式停用目标的 HPA,而无需更改 HPA 配置本身。如果目标的期望副本数设置为 0,并且 HPA 的最小副本数大于 0,则 HPA 会停止调整目标(并将自身的 `ScalingActive` 条件设置为 `false`),直到您通过手动调整目标的期望副本数或 HPA 的最小副本数重新激活它。

将 Deployment 和 StatefulSet 迁移到水平自动缩放

启用 HPA 后,建议从 Deployment 和/或 StatefulSet 的 清单 中移除 `spec.replicas` 的值。如果未完成此操作,则每次应用对该对象的更改时(例如,通过 `kubectl apply -f deployment.yaml`),都会指示 Kubernetes 将当前 Pod 数缩放到 `spec.replicas` 键的值。这可能不是期望的行为,并且在 HPA 活动时可能会造成麻烦。

请记住,移除 `spec.replicas` 可能会导致 Pod 数量的一次性下降,因为此键的默认值为 1(参考 Deployment 副本)。更新后,除 1 个 Pod 外的所有 Pod 都将开始其终止程序。之后,任何部署应用程序都将正常运行,并根据需要遵循滚动更新配置。您可以根据修改部署的方式选择以下两种方法之一来避免这种降级

  1. kubectl apply edit-last-applied deployment/<deployment_name>
  2. 在编辑器中,移除 `spec.replicas`。保存并退出编辑器后,`kubectl` 将应用更新。在此步骤中,Pod 数量不会发生任何变化。
  3. 您现在可以从清单中移除 `spec.replicas`。如果您使用源代码管理,还要提交您的更改,或者根据您跟踪更新的方式采取其他任何适当的步骤来修改源代码。
  4. 从现在开始,您可以运行 `kubectl apply -f deployment.yaml`

使用 服务器端应用 时,您可以遵循 转移所有权 指南,其中涵盖了此确切用例。

下一步

如果您在集群中配置了自动缩放,您还可以考虑使用 集群自动缩放 来确保您运行的节点数量合适。

有关 HorizontalPodAutoscaler 的更多信息

上次修改时间:2024 年 2 月 18 日下午 2:59 PST:添加有关集群自动缩放的概念页面 (b39e01b971)