Pod 水平自动扩缩
在 Kubernetes 中,*HorizontalPodAutoscaler* 会自动更新工作负载资源(例如 Deployment 或 StatefulSet),目的是自动扩展工作负载以匹配需求。
水平扩展意味着对增加的负载的响应是部署更多的 Pod。这与 *垂直* 扩展不同,对于 Kubernetes 来说,垂直扩展意味着为工作负载已运行的 Pod 分配更多资源(例如:内存或 CPU)。
如果负载减少,并且 Pod 的数量高于配置的最小值,则 HorizontalPodAutoscaler 指示工作负载资源(Deployment、StatefulSet 或其他类似资源)缩小规模。
水平 Pod 自动缩放不适用于无法缩放的对象(例如:DaemonSet。)
HorizontalPodAutoscaler 作为 Kubernetes API 资源和一个 控制器实现。该资源确定控制器的行为。水平 Pod 自动缩放控制器在 Kubernetes 控制平面中运行,定期调整其目标(例如,Deployment)的期望规模,以匹配观察到的指标,例如平均 CPU 利用率、平均内存利用率或您指定的任何其他自定义指标。
这里有一个使用水平 Pod 自动缩放的 演练示例。
HorizontalPodAutoscaler 如何工作?
图 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 的常见用途是将其配置为从 聚合 API(metrics.k8s.io
、custom.metrics.k8s.io
或 external.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),则控制平面将跳过任何缩放操作。
当指定 targetAverageValue
或 targetAverageUtilization
时,通过取 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 获取指标时出错),并且可以获取的指标建议缩减,则会跳过伸缩。这意味着,如果一个或多个指标给出的 desiredReplicas
大于当前值,则 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 的 replicas
字段。deployment 控制器负责设置底层 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 [stable]
(默认启用: true)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 的 application
容器中 cpu 的平均利用率为 60%。
注意
如果更改 HorizontalPodAutoscaler 正在跟踪的容器的名称,则可以按特定顺序进行更改,以确保在应用更改时伸缩仍然可用且有效。在更新定义容器的资源(例如 Deployment)之前,应更新关联的 HPA 以跟踪新旧容器名称。这样,HPA 可以在整个更新过程中计算伸缩建议。
将容器名称更改推出到工作负载资源后,通过从 HPA 规范中删除旧容器名称来清理。
基于自定义指标进行伸缩
Kubernetes v1.23 [stable]
(之前的 autoscaling/v2beta2
API 版本以 beta 功能提供了此功能)
前提是你使用 autoscaling/v2
API 版本,你可以配置 HorizontalPodAutoscaler 以基于自定义指标(即不是 Kubernetes 或任何 Kubernetes 组件内置的指标)进行伸缩。然后,HorizontalPodAutoscaler 控制器会从 Kubernetes API 查询这些自定义指标。
有关要求,请参阅对指标 API 的支持。
基于多个指标进行伸缩
Kubernetes v1.23 [stable]
(之前的 autoscaling/v2beta2
API 版本以 beta 功能提供了此功能)
前提是你使用 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 [stable]
(之前的 autoscaling/v2beta2
API 版本以 beta 功能提供了此功能)
如果你使用 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(半小时)。第一个策略(Pods)允许在一分钟内最多缩减 4 个副本。第二个策略(Percent)允许在一分钟内最多缩减当前副本的 10%。
由于默认情况下会选择允许最大更改量的策略,因此只有当 Pod 副本数超过 40 时才会使用第二个策略。当副本数为 40 或更少时,将应用第一个策略。例如,如果有 80 个副本,并且目标必须缩减到 10 个副本,则在第一步中将减少 8 个副本。在下一次迭代中,当副本数为 72 时,10% 的 Pod 为 7.2,但该数字四舍五入为 8。在自动伸缩器控制器的每次循环中,要更改的 Pod 数量都会根据当前副本数重新计算。当副本数降至 40 以下时,将应用第一个策略(Pods),并且每次将减少 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 个策略,每 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
设置为 minimum。将 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 都将开始其终止过程。之后进行的任何部署应用程序都将像往常一样运行,并按照需要遵守滚动更新配置。您可以通过以下两种方法之一来避免这种降级,具体取决于您修改部署的方式
kubectl apply edit-last-applied deployment/<deployment_name>
- 在编辑器中,删除
spec.replicas
。当您保存并退出编辑器时,kubectl
将应用更新。此步骤不会发生 Pod 计数的更改。 - 您现在可以从清单中删除
spec.replicas
。如果您使用源代码管理,还可以提交您的更改,或采取其他适当的步骤来修订源代码,以便跟踪更新。 - 从现在开始,您可以运行
kubectl apply -f deployment.yaml
下一步
如果您在集群中配置了自动缩放,您可能还需要考虑使用集群自动缩放,以确保您运行的节点数量正确。
有关 HorizontalPodAutoscaler 的更多信息
- 阅读有关水平 Pod 自动缩放的演练示例。
- 阅读
kubectl autoscale
的文档。 - 如果您想编写自己的自定义指标适配器,请查看样板文件以开始使用。
- 阅读 HorizontalPodAutoscaler 的 API 参考。