4. HPA实战

前几节我们已经理解了 HPA 的控制器循环、指标来源与扩缩容算法。本节把视角落到工程现场:部署一个可观测的示例应用,为它配置同时基于 CPU 与内存的 HPA,再用压测制造负载,最后从指标、副本数和事件三个维度判断扩缩容是否按预期发生。整个过程的目标不是"跑通命令",而是建立一条可复现的验证链路:负载输入 → 指标变化 → HPA 决策 → 副本调整 → 结果判读。

一、准备示例应用与资源请求

HPA 的利用率是"实际用量 ÷ 请求值"的百分比,因此示例应用必须显式声明 requests,否则 CPU 利用率无法计算,HPA 会报 <unknown> 并拒绝扩缩容。下面部署一个基于 registry.k8s.io/hpa-example 的 PHP-Apache 应用,它会在收到请求时消耗 CPU,便于压测。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php-apache
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 200m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
spec:
  selector:
    app: php-apache
  ports:
  - port: 80
    targetPort: 80

这里把 CPU 请求设为 200m、内存请求设为 128Mi,是后续利用率计算的基准。注意 limits 与 requests 的差距不宜过大,否则 CPU 会被限流(throttling),表现为"负载很高但利用率上不去",干扰判断。应用就绪后,用 kubectl get pods 确认 Pod 处于 Running 且 Ready。

二、配置同时基于 CPU 与内存的 HPA

HPA 支持在 metrics 列表中声明多个指标,控制器会分别计算每个指标建议的副本数,并取最大值作为最终期望副本数。这是多指标 HPA 最关键的行为,也是本节验证的重点之一。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 100
        periodSeconds: 15

CPU 目标设为 50%,内存目标设为 70%。behavior.scaleDown.stabilizationWindowSeconds: 300 表示缩容前会回看最近 5 分钟的建议值并取最大,避免负载抖动导致副本数反复震荡。应用后可用 kubectl get hpa php-apache -w 持续观察,初始 TARGETS 应显示类似 1%/5% 的低利用率。

HPA 多指标决策与副本调整链路 压测负载 kubectl run load 持续 HTTP 请求 php-apache Pod requests: 200m / 128Mi limits: 500m / 256Mi metrics-server 采集 CPU / 内存 实际用量 HPA 控制器 CPU 利用率 vs 50% 内存利用率 vs 70% 取两者建议副本数的最大值 CPU 分支 期望副本 = ceil(当前副本 × 当前利用率 / 50%) 示例:1 × 200% / 50% = 4 建议副本数 = 4 内存分支 期望副本 = ceil(当前副本 × 当前利用率 / 70%) 示例:1 × 90% / 70% = 2 建议副本数 = 2 最终期望副本数 = max(4, 2) = 4 受 maxReplicas=10 约束,未触顶

三、压测与观察

启动一个临时压测 Pod,向 Service 持续发起请求。这里用无限循环模拟稳定负载,便于观察 HPA 的持续响应:

kubectl run -i --tty load-generator --rm --image=busybox:1.36 --restart=Never -- \
  /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

另开一个终端执行 kubectl get hpa php-apache -w,可以观察到 TARGETS 从 1%/5% 逐步攀升。假设在某个采样点 CPU 利用率达到 200%、内存利用率达到 90%,按算法:CPU 分支 ceil(1 × 200% / 50%) = 4,内存分支 ceil(1 × 90% / 70%) = 2,取最大值后期望副本数为 4。这与上方 SVG 中的示例一致。随后 kubectl get deploy php-apache 会显示副本数从 1 增加到 4,kubectl get pods 能看到新 Pod 陆续创建。

HPA 默认每 15 秒同步一次(--horizontal-pod-autoscaler-sync-period),且指标本身有采集延迟,因此从压测开始到副本数变化通常需要 30~60 秒,属于正常现象,不要误判为配置失效。

四、结果分析与常见异常判读

停止压测(在 load-generator 终端按 Ctrl+C)后,CPU 利用率会快速回落,但副本数不会立即下降。由于配置了 300 秒的缩容稳定窗口,HPA 会回看最近 5 分钟的建议值并取最大,因此大约 5 分钟后副本数才逐步回落到 1。这正是 stabilizationWindowSeconds 的作用:用时间换稳定,抑制抖动。

验证过程中常见的异常及判读方式如下:

现象可能原因排查方向
TARGETS 显示 <unknown>缺少 requests 或 metrics-server 不可用检查 Deployment 的 requests;kubectl top pods 是否可用
CPU 利用率上不去但负载很高CPU 被 limits 限流查看容器 throttling 指标,适当提高 limits
副本数不增加已达 maxReplicas,或未超过目标阈值检查 kubectl describe hpa 的 Events 与当前副本数
副本数反复震荡缩容窗口过短或指标抖动增大 stabilizationWindowSeconds
内存指标始终偏低应用内存占用平稳,未随请求增长属正常,此时由 CPU 分支主导扩容