K8s如何实现服务自动扩缩容?,K8s扩缩容怎么配置?
Kubernetes 实现服务自动扩缩容,说到底就是把“运维盯着监控手动改副本数”换成一整套联动机制——HPA 看指标改 Pod 数量,Cluster Autoscaler 补节点,出了问题再由告警把人叫起来。三者对上号了才叫落地,只配一个 HPA 顶多算入了个门。
下面按 SRE 的日常视角拆:怎么配、指标怎么选、钱花在哪、不生效怎么查,以及一次真实的故障复盘。
先分清 K8s 自动扩缩容的三层,别一上来就写 YAML
不少团队第一次配弹性,直接在 Deployment 上挂个 HPA 就完事,结果流量一来 Pod 全 Pending,扩了个寂寞。原因很简单:扩缩容不是一个组件的事,是三层配合。
Pod 层、节点层、事件驱动层各管一摊
| 方案 | 管什么 | 触发依据 | 适合的场景 |
|---|---|---|---|
| HPA | Deployment 的副本数 | CPU、内存、自定义指标 | 无状态 Web 服务、API 网关 |
| VPA | 单个 Pod 的 requests/limits | 历史资源画像 | 难水平扩展的有状态服务 |
| Cluster Autoscaler / 弹性节点池 | 节点数量 | 出现 Pending Pod | 自建集群、云上托管节点池 |
| KEDA | 副本数,可缩到 0 | 队列长度、Kafka 堆积、Cron | 消息消费、批处理任务 |
行业共识认为,HPA 和节点弹性必须成对出现。只扩 Pod 不扩节点,等于把车开进了死胡同。反过来只扩节点不管 Pod,则是花钱养闲机器。
Kubernetes HPA 从零配通的完整路径
前置条件:先把 metrics-server 跑起来
HPA 默认只认 CPU 和内存,这两个指标来自 metrics-server。新集群第一步先确认它在不在:
kubectl get apiservice v1beta1.metrics.k8s.io,状态要是 Available。kubectl top pods -n prod,能出数字说明链路通了。报错error: Metrics API not available就是没装或没起来。- 托管集群一般默认开启,自建集群用
kubectl apply -f components.yaml装,注意别和生产节点抢资源。
还有一个新手最常踩的坑:Deployment 里没写 resources.requests,HPA 的 CPU 利用率永远显示 unknown。因为利用率是“实际用量 ÷ requests”,分母没了,指标自然算不出来。这一步不补,后面全白搭。
一份能直接上生产的 HPA 清单
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-api
namespace: prod
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-api
minReplicas: 3
maxReplicas: 30
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 2
periodSeconds: 60
几个参数值得掰开说。target 设 65% 而不是 80%,是给突发流量留缓冲;minReplicas: 3 是为了扛住单可用区故障,不是拍脑袋;maxReplicas 一定要结合节点池上限来定,写个 200 但集群最多调度 60 个 Pod,触发时只会看到一片 Pending。
behavior 段是防抖的关键
没配 behavior 的 HPA 会有明显的“呼吸效应”:流量抖一下,副本数上下横跳,日志里全是扩缩容事件。默认缩容稳定窗口是 300 秒,扩容窗口是 0 秒(新版行为),也就是“扩得快、缩得慢”,这个方向是对的。scaleDown 里再加一条“每 60 秒最多缩 2 个 Pod”,能避免大批 Pod 同时被摘掉导致连接抖动。
Kubernetes HPA 和 KEDA 哪个更适合小团队
这个问题在运维群里出现频率相当高。答案取决于你的服务是“吃 CPU”还是“吃队列”。
看触发源,不看流行度
HPA 的逻辑是“资源用量”,天生适合请求量正比于 CPU 的同步服务。但很多业务不是这样:一个消费者服务,CPU 常年 10%,Kafka 里却堆了十万条消息。这时候 HPA 完全看不见压力,因为它压根不关心队列长度。
KEDA 补的就是这块。它把队列深度、HTTP 请求数、Cron 表达式等外部指标拉进来,通过 metrics adapter 喂给 HPA 决策,还能把空闲服务缩到 0 个副本。对小团队来说,KEDA 的价值不在于功能多,而在于省机器——夜里没人下单的服务可以彻底缩到零。
运维成本的现实权衡
HPA 是 K8s 内置的,零额外组件。KEDA 要多部署一个 Operator 和一套 CRD,排查问题时多一层链路。我的建议是:先上 HPA 跑稳,等真遇到“指标看不出来”的场景,再引入 KEDA,别一开始就把技术栈堆满。
电商大促场景下 Kubernetes 弹性扩容怎么配置
大促的难点从来不是“能不能扩”,而是“扩得够不够快”。CPU 指标是滞后指标,等它涨上去,用户已经在转圈了。
把扩容动作提到流量到来之前
- 用 CronHPA 或 KEDA 的 cron 触发器,在活动开始前 30 分钟把 minReplicas 抬到预估峰值的 60%,活动结束后再降回来。
- 提前预热节点池,把 max 值预留好,别让 Cluster Autoscaler 在流量高峰现开机器——新节点从创建到可调度通常要几十秒到几分钟。
- 核心服务配好 HPA 的 scaleUp 激进策略,允许 30 秒内翻倍。
扩容之外,别忘了告警联动
自动扩缩容不是监控的替代品,而是监控的下游动作。SRE 侧要保留这几条告警:HPA 长时间顶在 maxReplicas(说明容量到顶了)、Pod 持续 Pending 超过 2 分钟、副本数大幅波动(判断是流量真实增长还是指标异常)。这些告警指向的是“弹性机制本身失效”,比业务告警更早一步暴露问题。
阿里云 ACK 上配置 K8s 自动扩缩容要多少钱
成本构成拆开看
弹性扩缩容本身不收费,收费的是它扩出来的资源。ACK 上的账单主要来自三块:节点费用(包年包月或按量)、弹性节点池的按量实例、以及 ECI 弹性容器实例按 Pod 计费。Serverless 版 ACK 直接把节点层省了,按 Pod 规格和运行时长算钱。
按量实例的单价普遍高于包年包月,所以“平时用包年包月底座 + 峰值用弹性节点”是成本最优的常见组合。把常态流量压在预留节点上,只有超出部分才走弹性,账单会好看很多。
三个能立刻省钱的开关
- 把 HPA 的 scaleDown 稳定窗口从默认值往下调一点,配合缩容策略,让夜间低谷真正缩下来。
- 无状态但低频的服务,考虑 KEDA 缩到 0,比常驻最小 1 副本一年能省下一笔。
- 给弹性节点池设上限和实例规格白名单,防止误配的 maxReplicas 把集群撑爆——这种事真的发生过。
Kubernetes 自动扩缩容不生效怎么排查
按这个顺序查,八成问题在前三步
kubectl top pods -n prod有没有数据。没数据直接跳到 metrics-server 排查。kubectl describe hpa order-api -n prod看 Events。出现基本就是 requests 没配。/65% - 副本数是不是已经到 maxReplicas 了。到顶了不是故障,是容量规划问题。
kubectl get pods -n prod | grep Pending,有 Pending 说明节点不够或调度受限。- 检查 ResourceQuota、LimitRange、PodDisruptionBudget 有没有卡住创建。
- 检查节点亲和性、污点容忍,扩出来的 Pod 落不到弹性节点上。
一次故障复盘:扩容成功,用户仍报错
某次大促,监控显示 HPA 在 2 分钟内把副本从 8 扩到 40,指标一切正常,但接口超时告警持续了将近四分钟。
复盘下来问题出在应用启动阶段。这些 Pod 用的是 JVM 服务,启动后要跑一段类加载和连接池预热,期间虽然 readinessProbe 已经通过,实际处理能力只有正常状态的零头。流量被打散到一群“刚起床还没醒”的实例上,等于扩容反而制造了一批低质量副本。
后来改了三处:加 startupProbe 把就绪判断延后到真正可用;HPA 扩出来的新 Pod 加 maxUnavailable 控制和慢启动标记;把预留式预热提前到活动开始前。教训是:自动扩缩容的验收标准不是“副本数涨了”,而是“新增副本能立刻扛住流量”。业内专家指出,弹性能力的瓶颈往往不在编排层,而在应用的可伸缩性上——这句话在这次事故里体现得相当彻底。
关于 Kubernetes 服务自动扩缩容的高频疑问
HPA 扩容了但 Pod 一直 Pending,怎么办?
先看是不是节点资源不足。执行 kubectl describe pod,Events 里出现 Insufficient cpu 或 0/12 nodes are available 就是容量问题,需要节点层弹性接手。如果 Cluster Autoscaler 已开启还是不扩,检查节点组的 max 值、可用区库存、以及 Pod 的 requests 是否大于单机可分配资源。
只用 CPU 指标够不够?
对大多数同步 API 够用,但有两类服务不适合:一类是 CPU 不敏感但有并发上限的(如连接数受限的服务),另一类是指标滞后于真实压力的(如消息消费者)。这两类更适合自定义指标或 KEDA,用 QPS、并发数、队列深度来触发,扩容决策会准得多。
缩容时正在处理的请求会不会丢?
只要优雅退出配到位就不会。Pod 被删除时先进入 Terminating 状态并从 Service Endpoints 摘除,此时不再有新流量进来,然后执行 preStop 钩子,最后发 SIGTERM。关键是 terminationGracePeriodSeconds 要大于 preStop 执行时间加业务最长处理时间,常见配置是 preStop 里 sleep 15、宽限期设 30 到 60 秒;宽限期短于实际处理时长时,进程会被 SIGKILL 直接打断,正在处理的请求就真的丢了。