首页 / Kubernetes (k8s) 入门教程 / HPA 水平自动扩缩

Kubernetes (k8s) 入门教程

HPA 水平自动扩缩

本教程共 65 篇 · 第 48 篇 · 更新于 2026-08-14 · 约 16 分钟阅读

KubernetesHPA自动扩缩autoscalingMetrics Server弹性

本节目标:搞懂 HPA 为什么能”按需增减副本”,会用 autoscaling/v2 写一个基于 CPU 的扩缩规则,并理解它的伸缩算法、扩缩行为和那些容易踩的坑。

白天流量高,你希望多开几个 Pod 一起扛。深夜流量低,你希望关掉多余 Pod 省资源。这种”看指标办事”的活儿,不用你半夜爬起来敲命令——交给 HPA 就行。

HPA 的全名是 HorizontalPodAutoscaler,意思是”水平 Pod 自动扩缩器”。它盯着某个工作负载(通常是 Deployment 或 StatefulSet),根据实时指标自动改它的副本数。注意是”水平”——加的是 Pod 个数,不是给单个 Pod 加 CPU。给单个 Pod 加资源那是第 49 章的 VPA 管的事。

48-1 什么是水平扩缩

先分清两个方向,很多人会混:

  • 水平扩缩(Horizontal):负载高了就多跑几个 Pod。好比多开几条收银台。
  • 垂直扩缩(Vertical):给正在跑的 Pod 加更多 CPU 或内存。好比把一条收银台加宽。

Kubernetes 里 HPA 负责前者,VPA 负责后者。本章只讲 HPA。

HPA 本身也是一个 Kubernetes 对象,类型是 HorizontalPodAutoscaler。你创建它,它就常驻在集群里,由一个控制器每 15 秒轮询一次指标(这个间隔由 --horizontal-pod-autoscaler-sync-period 控制,默认 15 秒)。

Note

HPA 管理的目标是带 scale 子资源的对象,最常见的是 Deployment 和 StatefulSet。DaemonSet 没有副本数的概念,所以不能挂 HPA。

48-2 HPA 的工作原理

HPA 控制器做四件事,可以按这个顺序理解:

  1. 拿到你指定的目标对象(比如名叫 web 的 Deployment)。
  2. 通过 scaleTargetRef 找到它,问 Metrics 接口要指标。
  3. 拿”当前指标值”和”你期望的指标值”算一个比例,推出”想要几个副本”。
  4. 把目标对象的 .spec.replicas 改成这个数,后面的 Deployment 控制器再去增删 Pod。

指标从哪来?最常见的是 metrics.k8s.io 这个 API,它由 Metrics Server 提供。注意 Metrics Server 不是默认装的,生产集群通常要单独部署。没有它,HPA 拿不到 CPU/内存数据,只能干瞪眼。

伸缩的核心算法很朴素,一句话:

期望副本数 = ceil( 当前副本数 × 当前指标值 ÷ 期望指标值 )

举例:现在 4 个副本,平均 CPU 用到 200m,你期望 100m。比例就是 200÷100=2,期望副本 = 4×2 = 8 个。反之如果 CPU 只有 50m,比例 0.5,期望副本 = 2 个,于是缩容。

Tip

比例太接近 1 时 HPA 不动手。默认容差是 10%(即 0.9~1.1 之间不扩不缩),避免指标抖动导致副本数反复横跳。

48-3 用 autoscaling/v2 定义 HPA

v1.36 请直接用 autoscaling/v2。它相比老版本最大的好处是 metrics 变成了数组,可以挂多个指标,还支持内存、自定义、对象、外部指标。

下面是一个最典型的”按 CPU 利用率扩缩”的写法:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  # 1. 绑定目标:要扩缩谁
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  # 2. 副本数上下限
  minReplicas: 2
  maxReplicas: 10
  # 3. 指标列表(v2 用数组)
  metrics:
  - type: Resource
    resource:
      name: cpu           # 也可以是 memory
      target:
        type: Utilization # 按"利用率百分比"算
        averageUtilization: 60

这里 type: Utilization + averageUtilization: 60 表示:希望所有 Pod 的平均 CPU 利用率维持在 60%。

Warning

用 CPU 做指标,目标 Pod 的容器必须设了 resources.requests.cpu。不然 HPA 不知道”请求的 100%“是多少,会报 <unknown> 且无法计算。内存指标同理,要设 requests.memory

想用”绝对数值”而不是百分比?把 target.type 改成 AverageValue,用 averageValue

  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: AverageValue
        averageValue: 500Mi   # 每个 Pod 平均内存用量目标 500Mi

48-4 多指标与自定义指标

metrics 是数组,可以写多个。HPA 会对每个指标分别算出一个”期望副本数”,然后取最大值去执行。意思是:只要有一个指标说”该扩了”,它就扩。

除了资源指标(CPU、内存),v2 还支持三类需要额外监控系统的指标:

  • Pods(Pod 指标):描述 Pod 自身的自定义指标,比如每秒数据包。只支持 AverageValue
  • Object(对象指标):描述同命名空间里另一个对象,比如某个 Ingress 的 QPS。支持 ValueAverageValue
  • External(外部指标):和集群内任何对象都没关系的外部数据,比如消息队列里堆积的任务数。
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: web-route
      target:
        type: Value
        value: 10k
Note

Pod/Object/External 这几类自定义指标需要你额外部署 Prometheus Adapter 之类的组件,把监控数据暴露成 custom.metrics.k8s.ioexternal.metrics.k8s.io。新手先吃透 CPU/内存就够了。

48-5 扩缩行为 behavior

光说”扩到几个”还不够细。扩太快可能把后端打挂,缩太快可能瞬间没容量。HPA 用 spec.behavior 控制扩缩的”节奏”。

spec:
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容稳定窗口,默认 300 秒
      policies:
      - type: Pods
        value: 4
        periodSeconds: 60               # 60 秒内最多缩 4 个
      - type: Percent
        value: 10
        periodSeconds: 60               # 或 60 秒内最多缩 10%
      selectPolicy: Min                 # 多个策略取"变化量最小"的那个
    scaleUp:
      stabilizationWindowSeconds: 0     # 扩容一般不等,立即响应
      policies:
      - type: Pods
        value: 4
        periodSeconds: 15
      selectPolicy: Max                 # 扩容取"变化量最大"

几个要点:

  • scaleDown.stabilizationWindowSeconds 默认 5 分钟。意思是:即使指标暂时掉下来,也会参考最近 5 分钟的建议,避免一掉就缩、一涨又扩的抖动。
  • policies 里可以同时写”按个数(Pods)“和”按百分比(Percent)“,selectPolicy 决定取哪个。Max 更激进,Min 更保守,Disabled 直接禁止缩容。
  • 扩容默认几乎不等待,这样流量来了能马上顶上。
Tip

Web 服务建议:扩容敏感(容忍度低)、缩容保守(稳定窗口拉大)。批处理任务反过来,缩容可以更积极以省成本。

48-6 状态条件与排查

写完 HPA,怎么确认它真的在干活?两个命令:

# 看当前指标与目标,TARGET 显示 当前/期望
kubectl get hpa web-hpa

# 看详细状态、事件、条件
kubectl describe hpa web-hpa

kubectl describe hpa 里有个 Conditions 段,三个条件很关键:

  • AbleToScale:能不能扩缩(比如距上次扩缩时间够不够长)。
  • ScalingActive:指标能不能正常拿到。如果是 False,多半是 Metrics Server 没装或指标名写错。
  • ScalingLimited:是不是被 min/max 副本数卡住了。

常见现象与原因:

  • TARGET 显示 <unknown>:目标 Pod 没设资源 requests,或 Metrics Server 没就绪。
  • 副本数一直不动:指标在容差区间内,或 ScalingLimited 为 True(已到上下限)。
  • 想缩却缩不动:minReplicas 设太高,或 scaleDown.selectPolicy: Disabled
Warning

HPA 只能扩缩”副本数”。如果某个 Pod 内部有热点容器把 CPU 吃满、但整个 Pod 平均利用率还在范围内,HPA 不会扩。这时可以用容器级指标 ContainerResource(指定某个容器的名字)来更精准地触发。

小结

HPA 是弹性伸缩的第一块砖:按指标加减副本,省心又省钱。记住这几条:

  1. autoscaling/v2metrics 是数组,能挂多指标。
  2. 目标 Pod 必须设 resources.requests,否则 CPU/内存指标算不出来。
  3. 指标拿不到先查 Metrics Server;副本不动先看 Conditions。
  4. behavior 给扩缩加节奏,别让容量坐过山车。

下一章看 VPA:当问题不是”几个 Pod”,而是”每个 Pod 该分多少资源”时,它就派上用场了。