公告Ryan 的 SRE 之旅 —— 内容持续更新,欢迎指正。

K8s如何实现服务自动扩缩容?,K8s扩缩容怎么配置?

2026-11-03 运维实践 0 阅读

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。新集群第一步先确认它在不在:

  1. kubectl get apiservice v1beta1.metrics.k8s.io,状态要是 Available。
  2. kubectl top pods -n prod,能出数字说明链路通了。报错 error: Metrics API not available 就是没装或没起来。
  3. 托管集群一般默认开启,自建集群用 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 自动扩缩容不生效怎么排查

按这个顺序查,八成问题在前三步

  1. kubectl top pods -n prod 有没有数据。没数据直接跳到 metrics-server 排查。
  2. kubectl describe hpa order-api -n prod 看 Events。出现 /65% 基本就是 requests 没配。
  3. 副本数是不是已经到 maxReplicas 了。到顶了不是故障,是容量规划问题。
  4. kubectl get pods -n prod | grep Pending,有 Pending 说明节点不够或调度受限。
  5. 检查 ResourceQuota、LimitRange、PodDisruptionBudget 有没有卡住创建。
  6. 检查节点亲和性、污点容忍,扩出来的 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 直接打断,正在处理的请求就真的丢了。

推荐阅读

RELATED
河北名美凯利建筑工程有限公司 冀ICP备2026046508号-4