间歇运行的批处理器、事件消费者和开发环境,经常长时间无事可做,却仍保留至少一个 Pod。GKE 1.37 引入了基于原生 HPA 的缩容到零能力:工作负载空闲时可以降到 0 个副本,外部指标再次出现积压后再自动唤醒。配合容量缓冲,还能减少等待节点创建带来的冷启动时间。
这项变化的重点不只是少运行几个 Pod,而是把“工作负载随时可启动”与“每个工作负载都要常驻计算资源”拆开。
从 KEDA 运维转向原生 HPA
过去,Kubernetes 中的事件驱动缩容到零通常依赖 KEDA。KEDA 功能成熟、支持多种事件源,但需要安装和维护 Operator,并为工作负载管理 ScaledObject 等自定义资源。对于规模较大的集群,这会增加升级、权限配置、故障排查和配置治理的工作量。
GKE 1.37 的方案把关键路径放进托管能力中,主要由两个部分组成:
AutoscalingMetric:把 Cloud Monitoring 或 Google Cloud Managed Service for Prometheus 中的外部信号映射为 HPA 可读取的指标。- 支持
minReplicas: 0的 HPA:指标低于阈值时停止全部 Pod;检测到待处理工作后,再把 Deployment 从 0 扩到 1 或更多副本。
这样可以减少外部指标适配器和额外 Operator,也缩短指标在多个组件之间轮询、转发的路径。不过,这并不意味着所有 KEDA 场景都应立即迁移:如果团队依赖 KEDA 的特定触发器、认证方式或跨平台一致性,仍需逐项验证 GKE 原生能力是否覆盖。
可复制的 Pub/Sub 消费者配置
下面以 Pub/Sub 订阅中的未投递消息数作为扩缩容信号。示例假设集群已经支持相关 GKE API,并且已有名为 worker-deployment 的 Deployment。运行前需要把 my-subscription 改成真实的订阅 ID。
将以下内容保存为 scale-to-zero.yaml:
apiVersion: autoscaling.gke.io/v1beta1
kind: AutoscalingMetric
metadata:
name: my-autoscalingmetric
spec:
metrics:
- promql:
name: pubsub-undelivered
query: >
{
"pubsub.googleapis.com/subscription/num_undelivered_messages",
subscription_id="my-subscription"
}
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: worker-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: worker-deployment
minReplicas: 0
maxReplicas: 50
metrics:
- type: External
external:
metric:
name: autoscaling.gke.io|my-autoscalingmetric|pubsub-undelivered
target:
type: AverageValue
averageValue: "10"
应用并检查资源:
kubectl apply -f scale-to-zero.yaml
kubectl get autoscalingmetric my-autoscalingmetric
kubectl get hpa worker-hpa --watch
这里的目标值是每个副本平均处理 10 条未投递消息。maxReplicas: 50 则为异常流量设置上限,避免一次积压导致无限制扩容。阈值不应直接照搬到生产环境,应结合单个 Pod 的吞吐量、消息处理耗时和下游容量进行压测。
如果需要一个最小测试 Deployment,可以这样实践。以下容器仅用于验证扩缩容流程,不会真正消费 Pub/Sub 消息;生产环境应替换为实际消费者镜像,并配置相应身份与权限。
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker-deployment
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: python:3.12-alpine
command: ["sh", "-c", "while true; do sleep 30; done"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
保存为 worker.yaml 后执行:
kubectl apply -f worker.yaml
kubectl apply -f scale-to-zero.yaml
kubectl describe hpa worker-hpa
kubectl get deployment worker-deployment -w
排查时不要只看副本数。kubectl describe hpa 中的 Conditions 和 Events 能说明 HPA 是否读到了外部指标,以及无法扩容是指标、权限还是调度容量导致的。
从零启动的真正瓶颈是节点容量
把 Deployment 缩到零,只解决了 Pod 的空闲成本。需求回来时,如果集群没有可用 CPU 和内存,GKE 仍需要创建节点、拉取镜像并启动容器。节点扩容可能引入约 60~90 秒等待,镜像体积、初始化逻辑和健康检查还会继续增加延迟。
GKE 容量缓冲通过维护一池可共享的预热计算资源来处理这个问题:
- 活跃缓冲提供可立即分配的资源,可由许多已经缩到零的工作负载共享。
- 待机缓冲以较低成本保留补充能力,用于在持续负载出现后快速回填活跃缓冲。
关键的成本模型因此发生变化:不再让每个低频应用各自保留一个副本,而是让多个应用共享一份集群级预热容量。工作负载本身可以保持零副本,但容量缓冲并非完全免费,应计入整体集群成本。
容量缓冲的大小需要根据并发唤醒概率决定。如果数百个任务不会同时启动,一小块共享缓冲可能已经足够;如果每天固定时间会同时触发大量作业,则要为峰值调度需求留出更多空间。
上线前要验证的边界
缩容到零适合有明确外部信号、允许短暂启动延迟且可以水平扩展的任务,例如队列消费者、低频批处理器和非工作时间闲置的开发服务。对持续接收同步请求、要求极低尾延迟或启动时需要长时间预热的服务,应谨慎使用。
上线前可以按以下清单检查:
- 确认唤醒信号独立于 Pod。 如果指标只能由正在运行的 Pod 上报,缩到零后就失去了唤醒依据。队列积压、负载均衡器信号和托管监控指标更适合这一模式。
- 验证指标归零行为。 区分真实的零、暂时缺失的数据和监控故障,避免错误缩容。
- 限制最大副本数。 扩容上限要与数据库连接数、外部 API 配额和消息系统吞吐能力匹配。
- 压测冷启动。 同时测量 HPA 发现指标、Pod 调度、镜像拉取、应用初始化和就绪探针所需时间。
- 评估容量缓冲。 比较保留共享缓冲的成本与业务能够接受的启动延迟,而不是只追求副本数归零。
- 准备回退方案。 可以先把
minReplicas调回1,再排查指标链路和容量配置。
GKE 原生缩容到零最适合从一两个低风险队列消费者开始试点。先观察空闲时长、冷启动分位数和消息积压恢复速度,再逐步扩大范围。节省空闲资源很重要,但真正可用的弹性系统,还必须保证指标可靠、容量及时到位,并且下游能够承受扩容后的并发。