水平 Pod 自动扩展
在 Kubernetes 中,一个 *水平 Pod 自动扩展器* 会自动更新工作负载资源(例如 部署 或 有状态集),目的是自动扩展工作负载以匹配需求。
水平扩展意味着对负载增加的响应是部署更多 Pod。这与 *垂直* 扩展不同,对于 Kubernetes 来说,这意味着为工作负载已经运行的 Pod 分配更多资源(例如:内存或 CPU)。
如果负载减少,并且 Pod 的数量超过配置的最小值,则水平 Pod 自动扩展器会指示工作负载资源(部署、有状态集或其他类似资源)缩减。
水平 Pod 自动扩展不适用于无法扩展的对象(例如:DaemonSet)。
水平 Pod 自动扩展器作为 Kubernetes API 资源和一个 控制器 来实现。该资源确定控制器的行为。水平 Pod 自动扩展控制器在 Kubernetes 控制平面 内运行,周期性地调整其目标(例如,部署)的期望规模,以匹配观察到的指标,例如平均 CPU 使用率、平均内存使用率或您指定的任何其他自定义指标。
有一个 使用水平 Pod 自动扩展的演练示例。
水平 Pod 自动扩展器如何工作?
图 1. 水平 Pod 自动扩展器控制部署及其副本集的规模
Kubernetes 将水平 Pod 自动扩展实现为一个间歇运行的控制循环(它不是一个连续的过程)。该间隔由 kube-controller-manager
的 --horizontal-pod-autoscaler-sync-period
参数设置(默认间隔为 15 秒)。
在每个周期内,控制器管理器会查询每个水平 Pod 自动扩展器定义中指定的指标相对于资源利用率。控制器管理器找到由 scaleTargetRef
定义的目标资源,然后根据目标资源的 .spec.selector
标签选择 Pod,并从资源指标 API(用于每个 Pod 资源指标)或自定义指标 API(用于所有其他指标)获取指标。
对于每个 Pod 资源指标(如 CPU),控制器会从资源指标 API 获取水平 Pod 自动扩展器所针对的每个 Pod 的指标。然后,如果设置了目标利用率值,则控制器会将利用率值计算为容器在每个 Pod 中的等效 资源请求 的百分比。如果设置了目标原始值,则直接使用原始指标值。然后,控制器对所有目标 Pod 的利用率或原始值(取决于指定的目标类型)求平均值,并产生一个用于扩展期望副本数量的比率。
请注意,如果某些 Pod 的容器没有设置相关的资源请求,则 Pod 的 CPU 利用率将未定义,自动扩展器不会对该指标采取任何操作。有关自动扩展算法工作原理的更多信息,请参见下面的 算法详细信息 部分。
对于每个 Pod 的自定义指标,控制器的功能类似于每个 Pod 的资源指标,除了它使用原始值,而不是利用率值。
对于对象指标和外部指标,会获取一个描述相关对象的单个指标。该指标与目标值进行比较,以生成如上所述的比率。在
autoscaling/v2
API 版本中,此值可以选择在进行比较之前除以 Pod 的数量。
水平 Pod 自动扩展器的常见用途是将其配置为从 聚合 API(metrics.k8s.io
、custom.metrics.k8s.io
或 external.metrics.k8s.io
)中获取指标。metrics.k8s.io
API 通常由名为 Metrics Server 的附加组件提供,该组件需要单独启动。有关资源指标的更多信息,请参见 Metrics Server。
对指标 API 的支持 解释了这些不同 API 的稳定性保证和支持状态。
水平 Pod 自动扩展控制器访问支持扩展的相应工作负载资源(例如部署和有状态集)。这些资源每个都具有一个名为 scale
的子资源,这是一个接口,允许您动态设置副本数量并检查它们的每个当前状态。有关 Kubernetes API 中子资源的一般信息,请参见 Kubernetes API 概念。
算法详细信息
从最基本的角度来看,水平 Pod 自动扩展控制器对期望指标值与当前指标值之间的比率进行操作
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
例如,如果当前指标值为 200m
,期望值为 100m
,则副本数量将加倍,因为 200.0 / 100.0 == 2.0
。如果当前值为 50m
,则会将副本数量减半,因为 50.0 / 100.0 == 0.5
。如果比率足够接近 1.0(在全局可配置的容差范围内,默认值为 0.1),则控制平面将跳过任何扩展操作。
当指定 targetAverageValue
或 targetAverageUtilization
时,currentMetricValue
是通过对水平 Pod 自动扩展器的规模目标中的所有 Pod 的给定指标求平均值来计算的。
在检查容差并确定最终值之前,控制平面还会考虑是否缺少任何指标,以及有多少个 Pod 就绪
。所有设置了删除时间戳的对象(具有删除时间戳的对象正在关闭/删除过程中)都会被忽略,所有失败的 Pod 都会被丢弃。
如果某个特定 Pod 缺少指标,它会被留待以后处理;具有缺少指标的 Pod 将用于调整最终的扩展量。
在对 CPU 进行扩展时,如果任何 Pod 尚未变为就绪(它仍在初始化,或者可能是健康状况不佳)或 Pod 的最新指标点在其变为就绪之前,则该 Pod 也会被留待处理。
由于技术限制,水平 Pod 自动扩展控制器在确定是否保留某些 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 数量的任何更改。
请注意,即使使用新的使用率比率,平均利用率的 *原始* 值也会通过水平 Pod 自动扩展器状态报告回来,不会考虑尚未就绪的 Pod 或缺少的指标。
如果在 HorizontalPodAutoscaler 中指定了多个指标,则会针对每个指标进行此计算,然后选择最大的预期副本数量。如果这些指标中的任何一个无法转换为预期副本数量(例如,由于从指标 API 获取指标时发生错误),并且可获取的指标建议缩容,则会跳过缩容。这意味着如果一个或多个指标的 desiredReplicas
大于当前值,则 HPA 仍然能够进行扩容。
最后,在 HPA 调整目标大小之前,会记录调整建议。控制器会在可配置的窗口内考虑所有建议,并选择该窗口内的最高建议。此值可以使用 --horizontal-pod-autoscaler-downscale-stabilization
标志进行配置,默认值为 5 分钟。这意味着缩容会逐渐进行,从而平滑快速波动的指标值的影响。
API 对象
HorizontalPodAutoscaler 是 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 的 replicas
字段。部署控制器负责设置底层 ReplicaSet 的 replicas
,以便它们在推出期间以及之后都加起来达到适当的数量。
如果您对具有自动缩放副本数量的 StatefulSet 执行滚动更新,则 StatefulSet 会直接管理其 Pod 集(没有类似于 ReplicaSet 的中间资源)。
对资源指标的支持
任何 HPA 目标都可以根据缩放目标中 Pod 的资源使用情况进行缩放。在定义 Pod 规范时,应指定资源请求,例如 cpu
和 memory
。这用于确定资源利用率,并由 HPA 控制器用于向上或向下缩放目标。要使用基于资源利用率的缩放,请指定如下所示的指标源
type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
使用此指标,HPA 控制器将使缩放目标中 Pod 的平均利用率保持在 60%。利用率是 Pod 当前资源使用量与请求资源之比。有关如何计算和平均利用率的更多详细信息,请参见 算法。
注意
由于所有容器的资源使用量都会加起来,因此 Pod 的总利用率可能无法准确地反映单个容器的资源使用情况。这可能会导致单个容器可能以高使用率运行,而 HPA 不会扩展,因为 Pod 的总体使用率仍在可接受的范围内。容器资源指标
Kubernetes v1.30 [稳定]
HorizontalPodAutoscaler API 还支持容器指标源,HPA 可以通过该源跟踪一组 Pod 中各个容器的资源使用情况,以便调整目标资源的大小。这使您能够为对特定 Pod 最重要的容器配置缩放阈值。例如,如果您有一个 Web 应用程序和一个提供日志记录的 sidecar 容器,则可以根据 Web 应用程序的资源使用情况进行缩放,而忽略 sidecar 容器及其资源使用情况。
如果修改目标资源以具有具有不同容器集的新 Pod 规范,则应修改 HPA 规范,以确保新添加的容器也用于缩放。如果指标源中指定的容器不存在或只存在于部分 Pod 中,那么这些 Pod 将被忽略,并重新计算建议。有关计算的更多详细信息,请参见 算法。要使用容器资源进行自动缩放,请定义如下所示的指标源
type: ContainerResource
containerResource:
name: cpu
container: application
target:
type: Utilization
averageUtilization: 60
在上面的示例中,HPA 控制器调整目标的大小,以便所有 Pod 中 application
容器的 CPU 平均利用率为 60%。
注意
如果更改 HorizontalPodAutoscaler 跟踪的容器的名称,则可以按特定顺序进行更改,以确保在应用更改时缩放仍然可用且有效。在更新定义容器的资源(如 Deployment)之前,应更新关联的 HPA 以跟踪新旧容器名称。这样,HPA 能够在整个更新过程中计算缩放建议。
将容器名称更改推送到工作负载资源后,请清理并从 HPA 规范中删除旧的容器名称。
根据自定义指标进行缩放
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 V2、custom.metrics.k8s.io 和 external.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 时才会使用。当 Pod 副本数量为 40 或更少时,将应用第一个策略。例如,如果有 80 个副本,并且目标必须缩容到 10 个副本,那么在第一步中将减少 8 个副本。在下一步中,当副本数量为 72 时,10% 的 Pod 为 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% 的当前运行副本,这意味着缩放目标可以缩减到允许的最小副本数。对于增加,没有稳定窗口。当指标表明应该增加目标时,目标会立即增加。有两个策略,最多可以在每 15 秒内添加 4 个 Pod 或 100% 的当前运行副本,直到 HPA 达到其稳定状态。
示例:更改缩减稳定窗口
为了提供 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
删除自动缩放器。
此外,还存在一个用于创建 HorizontalPodAutoscaler 对象的特殊 kubectl autoscale
命令。例如,执行 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 的 manifest(s) 中删除 spec.replicas
的值。如果没有这样做,每当对该对象进行更改时(例如通过 kubectl apply -f deployment.yaml
),这将指示 Kubernetes 将当前 Pod 的数量缩放为 spec.replicas
键的值。这可能不是期望的结果,并且在 HPA 处于活动状态时可能会造成麻烦。
请记住,删除 spec.replicas
可能会导致 Pod 数量的一次性下降,因为该键的默认值为 1(参考 Deployment Replicas)。更新后,除 1 个 Pod 外的所有 Pod 将开始其终止过程。之后的所有部署应用程序将按正常方式运行,并根据需要尊重滚动更新配置。您可以通过根据修改部署的方式选择以下两种方法之一来避免这种下降
kubectl apply edit-last-applied deployment/<deployment_name>
- 在编辑器中,删除
spec.replicas
。保存并退出编辑器后,kubectl
将应用更新。此步骤不会更改 Pod 数量。 - 现在可以从 manifest 中删除
spec.replicas
。如果您使用源代码管理,还可以提交更改或采取其他适合您跟踪更新方式的步骤来修改源代码。 - 从现在开始,您可以运行
kubectl apply -f deployment.yaml
使用 Server-Side Apply 时,您可以遵循 transferring ownership 指南,其中涵盖了此确切的用例。
下一步
如果您在集群中配置自动缩放,您可能还需要考虑使用 集群自动缩放 来确保您运行了正确数量的节点。
有关 HorizontalPodAutoscaler 的更多信息
- 阅读水平 Pod 自动缩放的 演练示例。
- 阅读
kubectl autoscale
的文档。 - 如果您想编写自己的自定义指标适配器,请查看 样板 以开始使用。
- 阅读 HorizontalPodAutoscaler 的 API 参考。