第 9 章: K8s HPA:从自动扩缩容到企业级弹性伸缩

3 阅读2分钟

上一章讲了 Volume。本章讲 HPA(Horizontal Pod Autoscaler),让 Pod 数量根据负载自动增减。

9.1 为什么需要 HPA

业务流量不是均匀的。电商大促时流量翻十倍,深夜流量可能降到十分之一。手动扩容有几个问题:

  • 人不可能 24 小时盯着监控
  • 扩容速度跟不上流量峰值
  • 缩容不及时造成资源浪费

HPA 的作用就是:根据 CPU、内存或自定义指标,自动调整 Pod 副本数。

HPA 流程

CPU 高 → HPA 增加 Pod
CPU 低 → HPA 减少 Pod

9.2 HPA 依赖什么

HPA 需要知道 Pod 的实时指标,这依赖 Metrics Server 或 Prometheus。

9.2.1 Metrics Server

Metrics Server 是 K8s 官方推荐的轻量级指标采集器,默认每 15 秒采集一次 CPU 和内存使用率。

安装:

$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

安装后验证:

$ kubectl top node
NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master   250m         12%    2048Mi          34%
k8s-node1    180m         9%     1536Mi          25%
k8s-node2    160m         8%     1408Mi          22%

$ kubectl top pod
NAME                   CPU(cores)   MEMORY(bytes)
nginx-7c4d9f8b5c-2jx   5m           12Mi

如果 kubectl top 报 "Metrics API not available",说明 Metrics Server 没装好。

9.2.2 Prometheus adapter

HPA 默认只能用 CPU 和内存。如果想根据 QPS、队列长度、消息积压等自定义指标扩容,需要 Prometheus + prometheus-adapter。

应用暴露指标 → Prometheus 抓取 → adapter 注册为 K8s metrics API → HPA 读取

企业级弹性伸缩通常都会上 Prometheus + adapter,配合自定义指标。

9.3 HPA 的核心字段

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
字段含义
scaleTargetRef要自动伸缩的目标,比如 Deployment
minReplicas最小副本数,即使负载为 0 也不低于这个数
maxReplicas最大副本数,防止无限扩容
metrics触发扩容的指标
averageUtilization目标 CPU 利用率

9.4 targetCPUUtilizationPercentage 的坑

初学者常遇到 HPA 不生效,其中一个原因是:Pod 没有设置 resources.requests

HPA 计算利用率时,分母是 requests.cpu,不是 limits.cpu。如果 Pod 没配 requests,HPA 不知道 "利用率" 是相对于多少,就无法计算。

resources:
  requests:
    cpu: "200m"
  limits:
    cpu: "500m"

上面的配置,HPA 目标是 50%,即当 CPU 使用超过 100m 时,开始扩容。

老版本 HPA 用 targetCPUUtilizationPercentage 字段:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
spec:
  targetCPUUtilizationPercentage: 50

v2 版本更灵活,支持多指标、自定义指标、更精细的扩缩行为。

9.5 scale up 和 scale down 行为

HPA 的扩缩行为默认比较简单:每 30 秒检查一次,根据指标决定是否要扩缩。v2 版本可以配置更精细的行为。

spec:
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 100
        periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Pods
        value: 1
        periodSeconds: 60
字段含义
stabilizationWindowSeconds指标稳定窗口,防止抖动
scaleUp扩容策略
scaleDown缩容策略
policies每次最多扩/缩多少

scaleDown.stabilizationWindowSeconds: 300 表示缩容前先看 5 分钟指标,避免流量短暂下降就急着缩容。扩容通常可以更激进,缩容要保守。

9.6 实战:HPA 配置与压力测试

先创建一个带资源声明的 Deployment:

# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"
        ports:
        - containerPort: 80

创建 HPA:

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

应用并查看:

$ kubectl apply -f web-deployment.yaml -f web-hpa.yaml

$ kubectl get hpa
NAME      REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web-hpa   Deployment/web   0%/50%    2         10        2          1m

对 Service 进行压力测试:

$ kubectl run -it --rm load --image=busybox:1.28 --restart=Never -- sh
# 在容器内执行
$ while true; do wget -q -O- http://web; done

或者用 ab、wrk 等工具:

# 在集群内临时起一个压力测试 Pod
$ kubectl run -it --rm load --image=williamyeh/wrk --restart=Never -- \
  -t4 -c100 -d60s http://web

观察 HPA 变化:

$ kubectl get hpa -w
NAME      REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS
web-hpa   Deployment/web   75%/50%   2         10        4
web-hpa   Deployment/web   82%/50%   2         10        6
web-hpa   Deployment/web   60%/50%   2         10        8

停止压测后,过一段时间副本数会逐步降下来。

9.7 HPA 的局限与注意事项

问题说明
需要配 requests没有 CPU requests 时 HPA 无法计算利用率
扩容有延迟默认 30 秒检查一次, metrics 采集也有延迟
冷启动问题新 Pod 启动慢,流量高峰可能已经过了
缩容冷却默认缩容有 5 分钟稳定窗口
只能水平扩容HPA 增加 Pod 数量,不能扩大单个 Pod 资源
不能缩到 0传统 HPA minReplicas 不能为 0,KEDA 可以

企业级弹性方案通常不是只用 HPA,而是组合使用:

  • HPA 做 Pod 水平扩缩
  • VPA 做 Pod 资源垂直调整
  • Cluster Autoscaler 做节点水平扩缩
  • KEDA 做事件驱动缩容(包括缩到 0)

9.8 本章小结

  • HPA 根据指标自动调整 Pod 副本数
  • CPU 指标依赖 Metrics Server,自定义指标需要 Prometheus + adapter
  • averageUtilization 的分母是 resources.requests.cpu
  • v2 版本支持多指标和精细的扩缩行为控制
  • 缩容要比扩容保守,用 stabilizationWindowSeconds 避免抖动
  • HPA 是弹性伸缩的基础,但不是全部

9.9 课后练习

  1. 安装 Metrics Server,确认 kubectl top nodekubectl top pod 能正常输出。
  2. 创建一个带 CPU requests 的 Deployment,并配置 HPA 目标 50%。
  3. 对 Service 加压,观察副本数从 2 扩到 10 的过程。
  4. 停止压测,观察缩容过程,理解 stabilizationWindowSeconds 的作用。