K8s HPA原理及最佳实践

在Kubernetes整个体系中,弹性伸缩是至关重要的功能,其分为两种:水平弹性伸缩(Horizontal Pod Autoscaling,简称HPA)垂直弹性伸缩(Vertical Pod Autoscaler,简称VPA)。HPA可以根据观察到的资源实际使用情况(如CPU/内存)或其它自定义指标负载自动调整Pod副本数,VPA可以根据资源实际使用情况为其Pod中的容器设置最新的资源配额requests。这两者合理使用既可以满足业务对实例数的要求保证系统稳定性,同时又能充分提升集群资源的利用率。

K8s HPA原理及最佳实践

一、HPA 原理

HPA (Horizontal Pod Autoscaler) 的核心原理可以概括为:定期查询监控指标,然后根据其目标值(Target Value) 和当前值(Current Value),通过特定的算法计算出所需的 Pod 副本数量,自动控制 Deployment、StatefulSet 等资源的副本数量,以使应用的平均资源利用率(如 CPU、内存)维持在你设定的目标值

K8s HPA原理及最佳实践

下面是图中涉及的核心组件及其作用的文字说明:

  • HPA Controller:HPA 的“决策大脑”,是 kube-controller-manager 的一部分。它负责[定期循环](默认每隔 15秒)通过 API Server 查询其管理的所有 HPA 对象及其对应的监控指标,并根据指标数据计算是否需要扩缩容以及需要多少个 Pod 副本

  • API Server:Kubernetes 的“信息枢纽”。HPA Controller 通过它查询 HPA 配置、获取监控指标,也是通过它来更新工作负载的副本数量。

  • Metrics API指标数据的标准化接口。HPA Controller 只通过统一的 Metrics API 来获取指标数据,而不关心数据的具体来源。这层抽象使得 HPA 可以灵活地使用不同种类的指标。

    • resource.metrics.k8s.io:提供资源指标,如 Pod 的 CPU 和内存使用率,通常由 Metrics Server 实现

    • custom.metrics.k8s.io:提供自定义指标,这些指标通常与特定应用或 Kubernetes 对象(如 Pod 的 QPS)相关。常用 Prometheus Adapter 来从 Prometheus 中获取并暴露这些指标

    • external.metrics.k8s.io:提供外部指标,这些指标完全来自于 Kubernetes 集群之外的系统,如消息队列的长度、云服务的监控指标等。

  • Metrics Server:一个集群范围内的资源使用数据聚合器。它从每个节点上的 kubelet 收集核心资源指标(如 CPU 和内存),并通过 resource.metrics.k8s.io API 暴露它们,供 HPA 等组件使用。

  • Prometheus + Prometheus Adapter:一个常见的自定义指标方案Prometheus 负责采集和存储丰富的监控数据。Prometheus Adapter 则作为一个桥梁,查询 Prometheus 中的数据,并将其转换为 Kubernetes 能够理解的格式,通过 custom.metrics.k8s.io API 暴露给 HPA Controller

HPA 的工作流程是一个持续的控制循环,上图的数字编号也大致对应了这些步骤:

  1. 查询 HPA 配置:HPA Controller 定期(默认 15s,可通过 --horizontal-pod-autoscaler-sync-period 参数调整)通过 API Server 查询所有 HPA 对象的配置定义,包括目标工作负载、目标指标类型及其目标值、最小/最大副本数等。

  2. 获取监控指标:对于每个 HPA,Controller 通过对应的 Metrics API(资源、自定义或外部)来获取当前的监控指标值。

    • 源指标(如 CPU、内存)由 Metrics Server 提供。Metrics Server 通过 Kubelet 从每个节点的 cAdvisor 中采集所有 Pod 的资源使用数据,并聚合到集群层面。

      1. metrics.k8s.io: 主要提供Pod和Node的CPU和Memory相关的监控指标。

      2. custom.metrics.k8s.io: 主要提供Kubernetes Object相关的自定义监控指标。

      3. external.metrics.k8s.io:指标来源外部,与任何的Kubernetes资源的指标无关。

    • 自定义指标(如 QPS、应用内部指标)由 Kubernetes Custom Metrics API 提供,这通常需要安装像 Prometheus Adapter 这样的组件来将 Prometheus 等监控系统的指标转换为 Kubernetes API 可以理解的格式。

  3. 计算所需副本数:Controller 使用获取到的当前指标值和 HPA 中定义的目标指标值,通过算法计算出期望的 Pod 副本数量。

    • 计算公式期望副本数 = ceil[当前副本数 * (当前指标值 / 目标指标值)]

      例如,当前有 2 个 Pod,CPU 使用率为 80%,HPA 目标 CPU 使用率为 40%,则期望副本数 = ceil[2 * (80 / 40)] = ceil[4] = 4。HPA 会考虑多种指标(选择计算结果中最大的副本数)并内置了容忍度(默认 0.1,即比率变化不超过 10% 则忽略)和冷却窗口等机制来防止副本数抖动

  4. 调整副本数:如果计算出的期望副本数与当前副本数不同,HPA Controller 会通过 API Server更新目标工作负载(如 Deployment)的 replicas 字段,为了避免副本数量因指标瞬时波动而剧烈变化(“抖动”),HPA 引入了冷却机制

    • 扩容:如果计算出的 期望副本数 > 当前副本数,HPA 就会增加副本数。

      扩容冷却 (默认 3 分钟):扩容操作没有全局等待期,但快速连续扩容时,每次扩容后等待时间会逐渐增加。

    • 缩容:如果计算出的 期望副本数 < 当前副本数,HPA 就会减少副本数。

      缩容冷却 (--horizontal-pod-autoscaler-downscale-stabilization,默认 5 分钟):在一次缩容操作后,会等待一段时间(默认5分钟),再执行下一次缩容操作。

  5. 工作负载控制器响应:相应的工作负载控制器(如 Deployment Controller)检测到 replicas 字段变化,会开始创建删除 Pod,以使实际运行的 Pod 数量等于期望值。

  6. 调度新 Pod:新创建的 Pod 会被 Scheduler 调度到合适的节点上运行。如果节点资源不足,这些 Pod 会处于 Pending 状态。

  7. 节点扩缩容(可选):如果集群中使用了 Cluster Autoscaler (CA),它会检测到因资源不足而无法调度的 Pod(Pending状态),然后自动扩容集群节点来提供更多资源。Pod 被成功调度和运行后,才能开始处理业务流量,此时指标数据也会随之变化,HPA 的下一个循环周期又会开始。

在实际应用中,基于原生HPA系统架构实现适配业务自定义特性的整体设计架构如下:

K8s HPA原理及最佳实践

二、基于 CPU 和内存的最佳实践示例

前提条件

  1. 安装 Metrics Server

    • HPA 需要 Metrics Server 来获取 CPU/内存指标。

    • 安装命令(对于大多数集群):

    kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    • 验证安装:kubectl top nodes

  2. 为 Pod 设置资源请求

    • 这是最关键的一步! HPA 计算使用率的公式是:(Pod 当前实际使用量 / Pod 的资源请求值) * 100%

    • 如果 Pod 没有设置 spec.containers[].resources.requests,HPA 将无法进行有意义的计算。

示例:为 Nginx Deployment 配置同时基于 CPU 和内存的 HPA

1. 创建 Deployment (nginx-deployment.yaml)

这个 Deployment 明确设置了 CPU 和内存的 requests

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3 # 初始副本数
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "250m"   # 每个 Pod 请求 0.25 核 CPU
            memory: "256Mi" # 每个 Pod 请求 256MiB 内存
          limits:
            cpu: "500m"
            memory: "512Mi"

应用它:kubectl apply -f nginx-deployment.yaml

2. 创建 HPA (nginx-hpa.yaml)

我们使用 autoscaling/v2 API,它支持多指标和更丰富的配置。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 2   # 最小副本数
  maxReplicas: 10  # 最大副本数
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization # 目标类型为利用率
        averageUtilization: 50 # CPU 平均使用率目标为 50%
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization # 目标类型为利用率
        averageUtilization: 70 # 内存平均使用率目标为 70%
  behavior: # (可选) 高级伸缩行为控制
    scaleDown:
      stabilizationWindowSeconds: 300 # 缩容冷却期 300 秒 (5分钟)
      policies:
      - type: Pods
        value: 2
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Pods
        value: 2
        periodSeconds: 60

应用它:kubectl apply -f nginx-hpa.yaml

HPA 行为解释

  • CPU 规则:HPA 会努力使所有 Pod 的 CPU 平均使用率 维持在 50%

    • 如果平均使用率是 75%,期望副本数 = ceil[3 * (75 / 50)] = ceil[3 * 1.5] = ceil[4.5] = 5。HPA 会将副本数扩容到 5。

  • 内存规则:HPA 会努力使所有 Pod 的 内存平均使用率 维持在 70%

    • 如果平均使用率是 85%,期望副本数 = ceil[3 * (85 / 70)] = ceil[3 * 1.21] = ceil[3.63] = 4

  • 多指标决策:当同时配置了多个指标时,HPA 会分别计算每个指标所需的副本数,然后选择其中最大的那个值

    • 在上面的例子中,CPU 算出来需要 5 个,内存算出来需要 4 个,那么 HPA 最终会将副本数扩容到 5。

验证与监控

1.查看 HPA 状态

kubectl get hpa nginx-hpa -w

输出会显示当前的指标值、目标值、最小/最大副本数和当前的副本数。

NAME         REFERENCE                       TARGETS             MINPODS   MAXPODS   REPLICAS   AGE
nginx-hpa    Deployment/nginx-deployment    50%/70%, 45%/65%    2         10        3          5m
# TARGETS 列显示为 CPU目标%/内存目标%,当前CPU%/当前内存%

2.查看 HPA 详细信息

kubectl describe hpa nginx-hpa

这个命令会输出非常详细的信息,包括事件日志,帮助你诊断 HPA 为什么不伸缩。

三、最佳实践总结

  1. 必须设置 resources.requests:没有它,HPA 无法工作。

  2. 使用 autoscaling/v2 APIv2 比 v2beta2 更稳定,且功能强大。

  3. 谨慎设置目标值

    • 目标值设置过高(如 CPU 90%)可能导致 Pod 在触发扩容前就已过载。

    • 目标值设置过低(如 CPU 10%)可能导致资源浪费和过多的副本。

    • 建议:从保守值开始(如 CPU 50-70%),根据实际生产监控数据进行调整。

  4. 合理配置 minReplicas 和 maxReplicas

    • minReplicas 应保证应用的基本可用性。

    • maxReplicas 应避免因意外流量或程序 Bug 导致资源耗尽。

  5. 利用 behavior 字段控制伸缩速率和冷却:根据应用的启动和冷却特性,调整 scaleUp 和 scaleDown 策略,避免抖动。

  6. 结合就绪探针和存活探针:确保新扩容的 Pod 真正准备好接收流量后,才被纳入服务的负载均衡。

  7. 结合日志与事件:注意容忍度、冷却窗口对扩缩容的影响,关注 ScalingActive、ScalingLimited 等状态变化。

  8. 考虑使用自定义指标:对于 Web 服务,基于 HTTP QPS(每秒请求数)进行扩缩容通常比基于 CPU 更直接、更灵敏。这需要安装 Prometheus 和 Prometheus Adapter。

  9. 让应用支持平滑启动和终止:确保新 Pod 启动后能快速就绪(利用就绪探针),并在终止时能优雅处理完已有请求(处理 SIGTERM 信号),避免服务中断。

四、关于 HPA 的进阶思考

1. HPA 的局限性及与其他自动伸缩方案的搭配

HPA 主要负责 Pod 水平扩缩容,但它依赖于集群有足够的资源来调度新创建的 Pod。如果集群资源不足,即使 HPA 创建了新的 Pod,这些 Pod 也会因无法调度而处于 Pending 状态,无法提供服务。

因此,在生产环境中,HPA 通常需要与 Cluster Autoscaler (CA) 或 Karpenter 搭配使用

  • HPA: 负责应用层伸缩,根据业务负载调整 Pod 数量。

  • CA/Karpenter: 负责基础设施层伸缩,根据 Pod 的资源请求调整集群节点数量,为 HPA 创建的 Pod 提供运行资源

2. 克服“弹性滞后”:AHPA 与预测性伸缩

传统 HPA 基于当前的监控指标进行反应式扩缩容,这存在一定的“弹性滞后”(Reactive Scaling)。即从流量增加到 HPA 完成扩容需要一定时间(指标采集、计算、Pod 启动、应用预热等),可能导致流量高峰时应用响应变慢

为解决这个问题,出现了预测性弹性伸缩(Predictive Scaling)方案,如 Advanced Horizontal Pod Autoscaler (AHPA)。AHPA 能够分析历史指标数据(如过去几天的 CPU 负载、QPS 变化规律),预测未来的负载波动,并提前进行扩容。例如,对于每天早高峰流量明显增大的应用,AHPA 可以在高峰来临前就提前扩容,避免流量激增时的响应延迟。在业务低谷时,它也会定时回收资源,节约成本


参考:

anzhihe 安志合个人博客,版权所有 丨 如未注明,均为原创 丨 转载请注明转自:https://chegva.com/6520.html | ☆★★每天进步一点点,加油!★★☆ | 

您可能还感兴趣的文章!

发表评论

电子邮件地址不会被公开。 必填项已用*标注