容器与编排

Kubernetes HPA 水平自动扩缩容配置与验证

面向已会用 Deployment 但没配过自动扩缩容的工程师:从装 metrics-server、写 HPA 到压测验证副本数真的膨胀。

作者:巧匠团队·8 分钟阅读·更新于 2026-09-06

前置条件:先有 metrics-server,HPA 才有数据可算

HPA 根据指标计算期望副本数,指标来自 metrics-server(CPU/内存)或自定义/外部指标。没装 metrics-server 时,HPA 对象能建但永远显示 `<unknown>` 读不到数据,也就不会扩缩容。

kind 或 minikube 有时默认没有 metrics-server,需显式安装。装完验证 kubectl top nodes 与 kubectl top pods 能出数字,才算就绪。

metrics-server 本质是每 15 秒向 kubelet 的 summary API 采样,注意隔离环境里的镜像地址与 TLS 选项,装好再配置 HPA 才有意义。

# 安装 metrics-server(最新 release 见其 GitHub)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 确认采集正常
kubectl top nodes
kubectl top pods

kubectl get apiservices | grep metrics

写第一份 HPA:按 CPU 设置 min/max 与阈值

HPA 用平均值算:收集所有 Pod 的 CPU,除以其 request 得到 utilization 百分比,超过 target(如 60%)就扩容,明显低于且持续一段时间就缩容。

要点:Pod 必须设置 resources.requests,否则 HPA 无基准可算。target 也可以写成固定值(value),但常用 utilization 百分比。

冷启动与抖动影响:扩容可能一次性补到 max,缩容留有 stabilizationWindowSeconds(默认 300s)避免抖。建议 min 至少 1-2 保证可用,max 按预算给。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60

# Deployment 侧必须有 requests:
#   resources:
#     requests: { cpu: 250m, memory: 256Mi }

错误示范:HPA 建了却 “unknown,不扩缩”

最常见的现象:kubectl get hpa 显示 TARGETS 列全是 <unknown>/--,副本数纹丝不动。原因排序:metrics-server 没装或没放采集权限、Deployment 没写 resources.requests、命名空间资源配额、或者用错了指标名称。

快速定位:kubectl describe hpa api-hpa 看 conditions 里的说明和 “unable to retrieve metrics” 消息;再 kubectl top pods 看该命名空间内是否有 CPU 数据。

修复顺序建议:先保证 top 有数据(修 metrics-server),再保证 request 存在,最后才怀疑 HPA yaml 本身。不要把 yaml 反复改而忽略数据源。

# 症状
kubectl get hpa
# NAME      REFERENCE   TARGETS   MINPODS   MAXPODS   REPLICAS
# api-hpa   Deployment/api  <unknown>/60%  2  10  2

# 看根因
kubectl describe hpa api-hpa
# ... Unable to retrieve metrics for resource cpu ...

kubectl top pods -n <ns>
# 空或 error: metrics not available yet  -> 先修 metrics-server

验证真的会扩:用负载把 CPU 顶上去

只配不验证等于没配。最直观的验证是给 Deployment 里某个 Pod 加临时 CPU 负载,观察 HPA 在几分钟内把副本从 min 拉到更高。

用 busybox 的 CPU 燃烧循环压,或直接 kubectl run 一个 `while :; do :; done` 的循环配合资源限制再监控。注意别把集群压到既不可再扩也卡死的地步。

验证后要收尾:删掉压测 Pod、把副本缩回 min(或清理 HPA 环境),避免测试负载留在线上占资源。

# 给目标 Deployment 派一个 CPU 燃烧 Pod
kubectl run loader \
  --image=busybox \
  --restart=Never \
  --requests='cpu=300m' \
  -- sh -c "while true; do :; done"

# 观察扩展(等待 stabilization 后)
kubectl get hpa api-hpa -w
kubectl get pods -w

# 收尾
kubectl delete pod loader
kubectl scale deployment api --replicas=2

再进一步:多指标与自定义指标(内存/外部队列)

单纯 CPU 对 I/O 型或批处理型服务不敏感,可加内存指标:Utilization 用 request 为分母,或 Value 用绝对 MB。

基于队列积压(如 Kafka 消费 lag、Celery 任务数)的扩缩是外部指标典型用例,需要外部指标适配器(KEDA 是常见的实现)。

多指标时 HPA 用“每个指标算出一个期望值,取其中最大需求”的策略,避免某项低但其它项高时漏扩。

spec:
  metrics:
  - type: Resource
    resource:
      name: cpu
      target: { type: Utilization, averageUtilization: 60 }
  - type: Resource
    resource:
      name: memory
      target: { type: Utilization, averageUtilization: 75 }
  # 或外部队列积压(经 KEDA / external adapter)
  # - type: External
  #   external:
  #     metric:
  #       name: kafka_lag
  #     target: { type: AverageValue, averageValue: "20" }

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。