Kubernetes v1.37 在 API 层支持将工作负载水平缩容到零副本。该功能现已进入 Beta,且默认启用。使用适当HorizontalPodAutoscaler(HPA),并配置对象指标或外部指标,就能把工作负载缩容至零,并在指标变化时恢复副本。
在 v1.37 之前,从零扩容需要附加组件、外部组件,或者启用 Alpha 特性门控。现在它已经成为 Kubernetes 核心的一部分。
缩容至零可以删除队列消费者、批处理程序等工作负载的最后一个空闲 Pod。每个 Pod 预留专用 CPU、GPU 等昂贵资源时,节省效果最明显。
代价是冷启动时间:HPA 必须观察指标、调度 Pod,然后启动应用。当任务可以等待在持久化队列中时,这种方式很合适。
没有就绪 Pod 时,Kubernetes Service 不会缓冲请求。因此,HTTP 等请求驱动的工作负载需要独立的缓冲层。
为什么从零扩容需要不同的指标
HPA 通常依据 CPU 或内存使用率扩缩容。两种指标都来自运行中的 Pod;副本数变为零后,就没有 Pod 可供测量,也就没有信号能让 HPA 再次扩容。
对象指标和外部指标没有这一限制。例如,队列长度独立于消费任务的工作进程存在。即使没有工作进程运行,HPA 仍能读取队列长度。
下面的示例使用外部指标,使队列消费者能够缩容至零并从零恢复。
配置外部指标
下例使用名为 queue_consumer_lag 的 Prometheus 指标,假设 Prometheus 已经采集了类似下面的时间序列:
queue_consumer_lag{namespace="default",name="worker_tasks"}
Kubernetes 需要指标适配器,才能通过 External Metrics API 提供这个值。一种实现是 Prometheus Adapter,可以通过 externalRules 配置项暴露该时间序列:
externalRules:
- seriesQuery: '{__name__="queue_consumer_lag",name!=""}'
metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (name)
resources:
overrides:
namespace:
resource: namespace
适配器的具体安装方法与发现规则取决于监控配置。完整配置选项请参见 Prometheus Adapter 的外部指标指南。
创建 HPA 之前,可以验证 Kubernetes 是否能读取指标:
kubectl get --raw \
'/apis/external.metrics.k8s.io/v1beta1/namespaces/default/queue_consumer_lag?labelSelector=name%3Dworker_tasks'
请求应返回 worker_tasks 的当前值。如果没有返回,先修复指标流水线,再配置 HPA。指标不可用时,HPA 无法从零扩容。
配置 HPA
以下 HPA 指向名为 queue-worker 的 Deployment,允许零到十个副本,每30个排队任务请求一个副本:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: queue-worker
annotations:
kubernetes.io/description: "Scales queue-worker based on the number of queued tasks"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: queue-worker
minReplicas: 0
maxReplicas: 10
metrics:
- type: External
external:
metric:
name: queue_consumer_lag
selector:
matchLabels:
name: worker_tasks
target:
type: Value
value: "30"
指标语义说明:以上 YAML 保留原文写法,但 Value 表示总指标目标,与上文“每 30 个排队任务请求一个副本”的说法不一致。Kubernetes 官方 HPA 教程在这个队列场景中使用 AverageValue 与 averageValue: 30。文末另列修正版,不替换原例。
队列为空时,HPA 可以把 Deployment 缩容至零。任务到来时,外部指标仍然可用,HPA 据此计算新的副本数,并由 maxReplicas 将其限制为最多十个。
启动 Deployment 时至少设置一个副本。手动把 Deployment 设为零一直意味着暂停自动扩缩容。HPA 保留这一行为,不会唤醒并非由它自身缩容至零的工作负载。
常规 HPA 行为仍然适用。尤其是,默认缩容稳定窗口为五分钟,可以避免队列长度短暂下降就立即移除所有工作进程。如需不同的行为,可通过 spec.behavior.scaleDown 配置该窗口。
HPA 如何区分零副本与暂停
从零扩容带来一个歧义:零副本可能意味着 HPA 自动缩容,也可能意味着运维人员手动暂停了工作负载。
控制器使用 ScaledToZero 状态条件解决这一问题。HPA 把工作负载从至少一个副本缩容至零时,会记录 ScaledToZero=True。这个条件告诉后续调谐循环,零副本状态由控制器管理,应该继续评估对象指标或外部指标。
重新扩容后,控制器把条件改为 ScaledToZero=False,原因设为 NotScaledToZero。工作负载处于零副本且没有 ScaledToZero=True 条件时,会继续保持暂停。
可以使用以下命令检查这些条件:
kubectl describe hpa queue-worker
如果适配器不能返回配置的指标,HPA 会报告 ScalingActive=False,并给出类似 FailedGetExternalMetric 的原因。恢复指标,或手动扩容工作负载以恢复处理能力。
升级或回滚之前
在 Kubernetes v1.37 中,HPAScaleToZero 特性门控在 kube-apiserver 和 kube-controller-manager 上都默认启用。API Server 接受 minReplicas: 0;Controller Manager 负责基于状态条件执行扩缩容。
在控制平面版本不一致的升级过程中,应先等待两个组件都支持并启用该特性,再创建带有 minReplicas: 0 的 HPA。如果 Controller Manager 禁用了该特性,它会将 replicas: 0 视为手动暂停,可能让工作负载一直停留在零副本。
在禁用特性门控,或降级到没有实现基于状态条件扩缩容的版本之前:
- 把受影响的 HPA 改为
minReplicas: 1或更高。 - 把当前处于零副本的工作负载扩容到至少一个副本。
minReplicas: 0 还要求至少配置一个对象指标或外部指标。如果 HPA 只包含 CPU 或内存等资源指标,API Server 会拒绝它。
从 Alpha 到 Beta
首个 Alpha 实现随 Kubernetes v1.16 发布。Kubernetes v1.36 添加了 ScaledToZero 条件及相应控制器行为,以区分自动缩容与手动暂停。
Kubernetes v1.37 在补充依据外部指标缩容至零并重新扩容的集成测试和端到端测试后,默认启用了该功能。下一步是在考虑晋升 GA 之前收集实际运维反馈。
如何进一步了解?
- 阅读缩容至零与从零扩容的文档。
- 阅读 KEP-2021:HPA 支持依据对象与外部指标缩容至零并从零扩容。
- 了解如何配置 Prometheus Adapter 外部指标。
如何参与
该功能由 SIG Autoscaling 负责。加入 Kubernetes Slack 和 #sig-autoscaling 频道,分享 Beta 使用反馈。
致谢
感谢 SIG Autoscaling 贡献者,将该功能从最初的 v1.16 实现推进到基于状态条件的重新设计及 Beta 阶段。也感谢 Guy Templeton 和 Adrian Moisey 审阅 KEP,以及帮助其为 Kubernetes v1.37 做好准备的发布、文档和生产就绪审阅者。
修正版:每 30 个排队任务配置一个工作副本
下面是依据官方 HPA 教程补充的修正版,只将原例的外部指标目标从总值 Value/value 改为每副本平均值 AverageValue/averageValue,其余配置不变。仍需提供文章前述的外部指标、Deployment 和支持缩容至零的控制平面。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: queue-worker
annotations:
kubernetes.io/description: "Scales queue-worker based on the number of queued tasks"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: queue-worker
minReplicas: 0
maxReplicas: 10
metrics:
- type: External
external:
metric:
name: queue_consumer_lag
selector:
matchLabels:
name: worker_tasks
target:
type: AverageValue
averageValue: "30"
冷启动、稳定窗口、指标可用性和手动暂停等约束仍按上文处理。











暂无评论内容