K8s 系列 | 第 17 天:HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩


title: “K8s 系列 | 第 17 天:HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩”
tags:
– Kubernetes
– K8s系列
– DevOps
– HPA
– 自动扩缩
– 弹性伸缩
– 云原生
– 第3周



第 17/30 天


引言

在 Kubernetes 集群中,应用的负载总是在动态变化的:白天流量高峰、夜间低谷、大促期间的突发流量……传统运维模式下需要人工扩容或提前预留大量资源,不仅成本高昂,而且响应不够及时。

Horizontal Pod Autoscaler(HPA) 是 Kubernetes 内置的自动扩缩组件,它能够根据 CPU 使用率、内存使用率或自定义监控指标(如 QPS、连接数)自动调整 Pod 的副本数量,让应用始终以合适的规模运行。本文将深入解析 HPA 的工作原理、配置方式、高级用法以及生产实践中的关键注意事项。


核心概念

什么是 HPA?

HPA 是 Kubernetes 的一个控制器,它会周期性地检查目标资源(如 Deployment 或 StatefulSet)的监控指标,根据指标值与目标值的比率计算出期望的副本数,然后更新资源的 replicas 字段。

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

例如:当前有 2 个 Pod,平均 CPU 使用率为 80%,目标设置为 50%,则:

期望副本数 = ceil(2 × (80% / 50%)) = ceil(3.2) = 4

HPA 版本演进

版本 API 路径 说明
v1 autoscaling/v1 仅支持 CPU 指标
v2beta2 autoscaling/v2beta2 支持 CPU、内存、自定义指标、多指标
v2 autoscaling/v2 稳定版,GA 于 K8s 1.23+

生产环境推荐使用 autoscaling/v2,支持更丰富的指标来源。

核心组件

┌─────────────────────────────────────────────────┐
│                  HPA Controller                   │
│  ┌──────────┐   ┌──────────┐   ┌───────────────┐ │
│  │指标采集器 │──▶│ 计算引擎  │──▶│  更新控制器   │ │
│  └──────────┘   └──────────┘   └──────┬────────┘ │
│        │                               │          │
└────────┼───────────────────────────────┼──────────┘
         ▼                               ▼
  ┌────────────┐                 ┌───────────────┐
  │ Metrics    │                 │ Deployment /   │
  │ Server /   │                 │ StatefulSet   │
  │Prometheus │                 │ .spec.replicas│
  └────────────┘                 └───────────────┘

实战步骤

1. 部署测试应用

首先创建一个简单的 Deployment 和 Service 用于测试 HPA:

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

2. 创建基于 CPU 的 HPA

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache-hpa
  namespace: hpa-demo
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

使用 kubectl 创建:

# 创建命名空间
kubectl create namespace hpa-demo

# 部署应用
kubectl apply -f php-apache-deploy.yaml -n hpa-demo

# 创建 HPA
kubectl apply -f php-apache-hpa.yaml -n hpa-demo

# 查看 HPA 状态
kubectl get hpa -n hpa-demo

# 实时监控 HPA 变化
kubectl get hpa -n hpa-demo -w

3. 验证自动扩缩:模拟负载

# 启动一个临时 Pod 用来发送压力请求
kubectl run -i --tty load-generator --rm 
  --image=busybox:1.28 
  --restart=Never 
  -n hpa-demo 
  -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache.hpa-demo.svc.cluster.local; done"

在另一个终端观察 HPA 变化:

# 观察副本数自动增长
kubectl get hpa php-apache-hpa -n hpa-demo -w

当 CPU 使用率持续超过 50%,HPA 会增加 Pod 副本数。停止负载后几分钟,副本数会逐步降回最小值。

4. 配置基于内存的 HPA

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: memory-based-hpa
  namespace: hpa-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70

5. 配置基于自定义指标的 HPA(Prometheus + KEDA)

生产环境中往往需要根据每秒请求数(RPS)队列长度连接数等业务指标进行扩缩。这里推荐使用 KEDA(Kubernetes Event-driven Autoscaling)

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaledobject
  namespace: hpa-demo
spec:
  scaleTargetRef:
    name: php-apache
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus.monitoring.svc.cluster.local:9090
      metricName: http_requests_per_second
      query: |
        sum(rate(http_requests_total{namespace="hpa-demo"}[2m]))
      threshold: "100"

6. 多指标组合 HPA

同时指定多个指标,HPA 会选择所有指标中计算出的最大副本数

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: multi-metric-hpa
  namespace: hpa-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  - type: Pods
    pods:
      metric:
        name: requests_per_second
      target:
        type: AverageValue
        averageValue: "1000"

常见问题

❓ HPA 扩缩为什么有延迟?

HPA 默认每 15 秒采集一次指标,但指标本身也有延迟(metrics-server 默认 60 秒更新一次)。从负载突增到完成扩容,通常需要 1-3 分钟。对于延迟敏感的场景,可以考虑:

  • 使用 KEDA 支持的事件驱动扩缩(基于 Kafka 队列深度、RabbitMQ 消息数等)
  • 配置 cluster-proportional-autoscaler 进行提前扩容
  • 结合 VPACluster Autoscaler 做协同扩缩

❓ 为什么 Pod 数没有降下来?

HPA 有冷却机制--horizontal-pod-autoscaler-downscale-stabilization,默认 5 分钟),防止指标抖动导致频繁扩缩。可以通过 HPA 的 behavior 字段自定义:

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300  # 冷却窗口
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Pods
      value: 4
      periodSeconds: 60
    - type: Percent
      value: 100
      periodSeconds: 60
    selectPolicy: Max

❓ Pod 必须有 resource requests 吗?

是的! HPA 基于 CPU/内存的指标要求目标 Pod 必须设置了 resources.requests.cpuresources.requests.memory,否则 metrics-server 无法采集 Pod 的资源使用率。


生产最佳实践

  1. 始终设置 requests 和 limits:没有 resource 限制的 Pod 无法被 HPA 有效管理
  2. 冷却时间配置:根据业务波动特征调整 behavior.scaleDown 窗口,避免扩缩震荡
  3. 最小副本数 ≥ 2:防止单点故障,保障滚动更新时仍有可用副本
  4. 多指标组合:不要只依赖 CPU,加入内存或业务指标以获得更准确的扩缩决策
  5. 容量规划兜底:HPA 的最大副本数受集群资源限制,提前预留 Node 资源或启用 Cluster Autoscaler
  6. 监控与告警:对 HPA 自身行为进行监控,设置副本达到上限时的告警通知
  7. 预配置 vs 响应式:对于已知的流量高峰(如秒杀、促销),提前扩容比 HPA 响应更可靠

总结

HPA 是实现 Kubernetes 应用弹性伸缩的核心工具。从简单的 CPU 指标到复杂的多指标组合,再到基于 Prometheus 和 KEDA 的事件驱动扩缩,HPA 体系提供了从开发到生产的完整解决方案。

关键要点:
– HPA 通过指标比率计算目标副本数,支持 CPU、内存、自定义指标
– 使用 autoscaling/v2 API 获取最丰富的功能集
– 自定义指标需配合 metrics-server 或 Prometheus Adapter
– 通过 behavior 字段自定义扩缩策略以适应业务特点
– 结合 PodDisruptionBudget、Cluster Autoscaler 构建完整的弹性体系


下期预告

第 18 天:VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩——如果说 HPA 解决的是”横向加机器”的问题,那 VPA 解决的是”给机器加资源”的问题,而 Cluster Autoscaler 则负责”整个集群加节点”。三剑合璧,打造真正的全栈自动弹性伸缩体系!


📚 系列目录
第 1 天:Kubernetes 是什么?核心概念与架构全景解析
第 2 天:手把手搭建你的第一个 K8s 集群(kubeadm 实战)
第 3 天:Pod 详解
第 4 天:Deployment 与 ReplicaSet
第 5 天:Service 与网络基础
第 6 天:Namespace 与资源配额
第 7 天:ConfigMap 与 Secret
第 8 天:Volume 与 PersistentVolume
第 9 天:StorageClass 与动态存储供给实战
第 10 天:StatefulSet:有状态应用的部署与管理
第 11 天:Ingress 与 Ingress Controller
第 12 天:NetworkPolicy
第 13 天:Headless Service 与服务发现
第 14 天:CSI 存储插件与生产存储选型指南
第 15 天:污点与容忍度:掌控 Pod 调度
第 16 天:Node Affinity 与 Pod Affinity
▶ 第 17 天:HPA 水平自动扩缩(本篇)
– [第 18 天:VPA 与 Cluster Autoscaler(待发布)]
– [第 19 天:Job 与 CronJob(待发布)]
– [第 20 天:PriorityClass 与抢占式调度(待发布)]
– [第 21 天:资源配额与 LimitRange(待发布)]
– … 后续更多精彩内容,敬请期待!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容