4. 基于CPU与内存的HPA实战

Horizontal Pod Autoscaler(HPA)是 OpenShift 中实现工作负载水平弹性伸缩的核心控制器。它并不直接创建 Pod,而是通过持续读取指标、计算期望副本数,再修改目标 Deployment(或 ReplicaSet、StatefulSet 等)的 spec.replicas 字段,由 Deployment 控制器完成实际的 Pod 增减。理解这条“指标采集 → 期望副本计算 → 修改副本数 → 控制器扩缩”的链路,是本节实战的关键。

HPA 的期望副本数由如下公式决定:

desiredReplicas = ceil( currentReplicas × ( currentMetricValue / targetMetricValue ) )

其中 currentMetricValue 是所有目标 Pod 指标的平均值(例如平均 CPU 使用率),targetMetricValue 是 HPA 中设定的目标值。举例来说,若当前有 2 个副本,平均 CPU 使用率为 80%,目标为 50%,则期望副本数为 ceil(2 × 80/50) = ceil(3.2) = 4。这个公式决定了 HPA 的伸缩方向与幅度,也是观察负载变化时判断“为什么扩到 4 个而不是 3 个”的依据。

前置条件:Deployment 必须声明资源 requests

HPA 计算 CPU 使用率时,分母是 Pod 的 CPU requests,而不是 limits,也不是节点容量。因此目标 Deployment 的容器必须显式声明 resources.requests.cpu,否则 HPA 无法计算百分比,会报 missing request for cpu 并停止伸缩。内存指标同理,需要 resources.requests.memory。下面是一个可用的 Deployment 片段:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-frontend
  namespace: demo-hpa
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-frontend
  template:
    metadata:
      labels:
        app: web-frontend
    spec:
      containers:
      - name: app
        image: quay.io/example/web-frontend:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"

这里 requests.cpu 为 200m,意味着单个 Pod 的 CPU 使用率 100% 对应 200m 的实际用量。若 HPA 目标设为 60%,则每个 Pod 平均使用 120m 时即达到目标。

方式一:使用 oc 命令快速创建 HPA

OpenShift 的 oc autoscale 命令可以在一条命令内完成 HPA 创建,适合快速验证:

oc autoscale deployment/web-frontend \
  --name=web-frontend-hpa \
  --min=2 --max=8 \
  --cpu-percent=60 \
  -n demo-hpa

参数含义:--min 与 --max 限定副本数区间,HPA 永远不会把副本数调整到该区间之外;--cpu-percent=60 表示目标平均 CPU 使用率为 60%。创建后可用 oc get hpa -n demo-hpa 查看,TARGETS 列会显示类似 3%/60% 的当前值与目标值。

方式二:使用 YAML 定义,支持多指标

当需要同时基于 CPU 和内存伸缩,或需要更精细的行为控制时,应使用 YAML 定义。以下示例同时配置 CPU 与内存两个指标:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-frontend-hpa
  namespace: demo-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-frontend
  minReplicas: 2
  maxReplicas: 8
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 75
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60

多指标时,HPA 会分别计算每个指标对应的期望副本数,然后取最大值作为最终结果。也就是说,只要 CPU 或内存任一指标要求更多副本,就会按更大的那个扩。这保证了不会因为某一维度被忽略而出现瓶颈。behavior.scaleDown.stabilizationWindowSeconds: 300 表示缩容前会观察 5 分钟内的历史推荐值,取其中最大值,避免负载短暂回落就立即缩容造成抖动。

观察负载变化下的副本调整

创建 HPA 后,可用 oc get hpa web-frontend-hpa -n demo-hpa -w 持续观察。为了制造负载,可对 Service 发起压测,例如使用 hey 或 ab 持续请求:

oc run load-generator --image=williamyeh/hey --restart=Never -n demo-hpa \
  -- -z 5m -c 50 http://web-frontend.demo-hpa.svc.cluster.local:8080/

随着请求量上升,平均 CPU 使用率会从个位数攀升。当超过 60% 时,HPA 开始扩容,副本数从 2 逐步增加到 4、6,直至接近 maxReplicas=8 或负载被摊薄到目标值以下。压测结束后,CPU 回落,HPA 在 stabilizationWindow 结束后开始缩容,副本数逐步回到 minReplicas=2。整个过程可通过 oc get pods -n demo-hpa -w 看到 Pod 的创建与终止。

HPA 基于 CPU/内存的伸缩链路与副本变化 Metrics Server 采集 Pod CPU / 内存 相对 requests 计算 HPA Controller desired = ceil(cur × cur/target) 多指标取最大值 min=2 max=8 Deployment web-frontend spec.replicas 被修改 requests: cpu 200m Pods 2 → 4 → 6 → 8 负载摊薄 回落至 2 负载变化与副本调整(示例) 100% 60% 0% 时间 → 目标 60% 平均 CPU 使用率 副本数 2 4 6 8 4 2 空闲 压测上升 峰值 回落缩容

结果判读与常见问题

观察 HPA 时,重点看三列:TARGETS 显示当前指标与目标值,MINPODS/MAXPODS 显示区间,REPLICAS 显示当前副本数。若 TARGETS 长期显示 <unknown>/60%,通常说明 Metrics Server 未就绪或 Pod 缺少 requests;若副本数在目标值附近反复跳动,可适当增大 stabilizationWindowSeconds 或调整目标值留出缓冲。扩容受 maxReplicas 限制,缩容受 minReplicas 限制,这两个值应结合节点容量与业务最低可用副本数设定,而不是随意取大。

内存指标作为伸缩依据时需谨慎:内存使用率通常不会随请求量线性回落,容易导致扩容后难以缩容。建议内存目标值设置得比 CPU 更宽松,或仅将内存作为扩容触发条件、缩容仍以 CPU 为主。
HPA 与 Deployment 的 spec.replicas 存在“争夺”:若手动 oc scale 修改副本数,HPA 会在下一次同步时按计算结果覆盖。需要临时固定副本数时,应先暂停或删除 HPA。

完成本节实战后,应能独立完成:为带 requests 的 Deployment 创建 HPA、用 oc 与 YAML 两种方式定义、通过压测观察副本从 2 扩到 8 再缩回 2 的完整过程,并能根据 TARGETS 与事件判断伸缩是否符合预期。