欢迎光临
我们一直在努力

Kubernetes VPA 深度指南:当 HPA 不够用时,如何通过 Vertical Pod Autoscaler 自动优化资源分配

为什么你需要了解 VPA?

在 Kubernetes 集群的日常运维中,资源管理始终是最核心也最令人头疼的问题之一。大部分团队最开始接触的是 HPA(Horizontal Pod Autoscaler),它通过增减 Pod 副本来应对流量变化。但 HPA 有一个先天局限:它只解决”数量”问题,不解决”大小”问题。如果你的 Pod 设置的 Request 和 Limit 本身就不合理——比如一个 Java 应用实际只需要 512MB 内存,但你给它配了 4GB——HPA 扩出来的每个副本都在浪费资源。

这时就需要 VPA(Vertical Pod Autoscaler)出场了。VPA 会自动分析 Pod 的历史资源使用数据,动态调整 CPU 和内存的 Request 与 Limit 值,让每个 Pod 的资源配置与实际需求精准匹配。简单说:HPA 管”要几个 Pod”,VPA 管”每个 Pod 要多大”。

Kubernetes 集群资源管理示意图

很多开发者把 VPA 和 HPA 看作二选一的方案,这其实是个误区。在生产环境中,两者往往配合使用——VPA 负责长期优化 Pod 的基准资源配置,HPA 负责应对突发流量峰值。这种组合拳能让集群的资源利用率提升 30%-50%,对于运行大规模集群的团队来说,节省的成本相当可观。

本文将深入讲解 VPA 的工作原理、部署配置、生产实践以及常见的坑,帮助你真正用好这个强大的自动扩缩容工具。

VPA 的核心架构与工作原理

VPA 不是一个单一的组件,而是由三个协同工作的子组件构成的系统。理解它们各自的分工,是正确使用 VPA 的前提。

Recommender:资源建议的大脑

Recommender 是 VPA 中最核心的组件。它持续监听集群中所有 Pod 的历史资源使用指标(通过 Metrics Server 获取),然后基于这些数据计算出最优的 Request 和 Limit 建议。Recommender 的计算逻辑包含以下几个关键步骤:

  1. 数据采集:从 Metrics Server 拉取 Pod 级别的 CPU 和内存使用历史,默认保留 8 天的数据窗口
  2. 百分位计算:根据使用量的 P50(中位数)、P90、P95 百分位值,结合你设定的安全边际(margin),计算出推荐值
  3. 上下界约束:将计算结果限制在用户配置的 minAllowed 和 maxAllowed 范围内
  4. 推荐输出:生成 VPA 对象的 Recommendation 状态字段

下面是一个 VPA 对象被 Recommender 填充后的典型状态:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: "*"
        minAllowed:
          cpu: 100m
          memory: 256Mi
        maxAllowed:
          cpu: "4"
          memory: 8Gi
status:
  recommendation:
    containerRecommendations:
      - containerName: app
        target:
          cpu: 586m
          memory: 1587Mi
        lowerBound:
          cpu: 380m
          memory: 1024Mi
        upperBound:
          cpu: 1100m
          memory: 2048Mi
        uncappedTarget:
          cpu: 720m
          memory: 2100Mi

上面的 status 字段展示了 Recommender 的输出。target 是推荐的最终值,lowerBound 和 upperBound 用于 Updater 判断是否需要触发更新。

Updater:执行更新的调度器

Updater 负责将 Recommender 的建议转化为实际行动。它会定期扫描集群中所有开启自动更新模式的 VPA 对象,然后判断当前 Pod 的资源配置是否需要调整。

Updater 的触发逻辑是:如果当前 Pod 的实际资源配置低于 Recommender 给出的 lowerBound,或高于 upperBound,它就会触发 Pod 的优雅驱逐(Eviction)。被驱逐的 Pod 会被 Deployment 或 StatefulSet 重新创建,创建时 VPA 的 Admission Webhook 会自动注入新的资源值。

Updater 默认每 60 秒检查一次,可以通过 --updater-interval 参数调整。生产环境中建议保持这个默认值,过于频繁的检查会导致不必要的 Pod 重建。

Admission Controller:请求注入的守门员

Admission Controller 是一个 MutatingWebhook,它拦截所有 Pod 创建请求。当 Updater 驱逐了一个 Pod 后,新的 Pod 被调度时,这个 Webhook 会读取对应 VPA 对象的 Recommendation,然后将新的资源值注入到 Pod 的 spec 中。

这个组件的存在意味着:即使你手动删除了 Pod,新创建的 Pod 也会自动获得 VPA 推荐的资源配置——不需要任何人工干预。

VPA 的三种更新模式如何选择?

VPA 提供了三种更新模式(updateMode),适用于不同的运维场景:

模式 更新方式 适用场景
Off 仅提供建议,不自动执行 新集群、观望期,只想看推荐值
Initial 仅在 Pod 首次创建时设置 StatefulSet、有状态应用,避免重建
Auto 自动驱逐并重建 Pod 无状态应用、Deployment

让我用一个实际的配置示例来说明:

# Off 模式:仅查看推荐
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: recommendation-only
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Off"

# Initial 模式:Redis 等有状态应用
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: redis-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: redis-cluster
  updatePolicy:
    updateMode: "Initial"

# Auto 模式:无状态 Web 服务
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: web-service
  updatePolicy:
    updateMode: "Auto"

选择建议:如果你刚接触 VPA,建议先用 Off 模式运行一周,观察 Recommender 给出的推荐值是否合理。当你确认推荐值稳定后,再对无状态应用切换到 Auto 模式。对于 StatefulSet 和数据库类应用,务必使用 Initial 模式——Auto 模式下的 Pod 驱逐可能导致数据丢失。

VPA + HPA 组合部署的最佳实践

前面提到,VPA 和 HPA 可以协同工作,但需要满足一个关键前提:两者不能同时基于同一指标对同一个 Pod 进行扩缩。这是因为如果 HPA 在增减副本数量,而 VPA 同时在调整每个副本的大小,两者会互相干扰,导致系统震荡。

正确的组合方式是:VPA 仅调整 CPU/内存的 Request,HPA 基于自定义指标(如 QPS、请求延迟)来扩缩副本。配置示例如下:

# VPA: 仅管理 CPU Request(不要管理 CPU 的 Limit)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-combined-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: web-service
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: "*"
        controlledResources: ["cpu", "memory"]
        controlledValues: RequestsOnly  # 只调整 Request

---
# HPA: 基于 QPS 进行水平扩缩
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-combined-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-service
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Object
      object:
        metric:
          name: requests_per_second
        describedObject:
          apiVersion: v1
          kind: Service
          name: web-service
        target:
          type: Value
          value: 500

这种配置模式有几个关键要点:

  • controlledValues: RequestsOnly:VPA 只调整 Request,不碰 Limit。Limit 由你手动设置一个合理的倍数,比如 Request 的 2 倍
  • HPA 避免使用 CPU/Memory:既然 VPA 在动态调整 Request,HPA 就不要再用 CPU 利用率作为扩缩依据。改用业务指标如 QPS、连接数等
  • 需要 Kubernetes 1.25+:VPA ≥ 0.14 版本才完整支持 controlledValues 参数

这种组合方案在 Netflix、Spotify 等大型 K8s 生产环境中已经得到广泛验证。根据公开的案例数据,采用 VPA + HPA 组合后,集群的 CPU 平均利用率从 25% 提升到了 55%,内存利用率从 40% 提升到了 70%。

VPA 的部署与安装

VPA 不是 Kubernetes 内置组件,需要手动安装。官方推荐通过 Helm 或直接 apply YAML 清单的方式部署:

# 方式一:Helm 安装(推荐)
helm repo add cowboysysop https://cowboysysop.github.io/charts
helm upgrade --install vertical-pod-autoscaler cowboysysop/vertical-pod-autoscaler \
  --namespace kube-system \
  --set recommender.enabled=true \
  --set updater.enabled=true \
  --set admissionController.enabled=true

# 方式二:直接 apply 官方清单
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh

安装完成后,验证组件是否正常运行:

kubectl get pods -n kube-system | grep vpa

# 输出应类似:
# vpa-admission-controller-7f8d9c6b-abcde   1/1  Running
# vpa-recommender-6b9f7c8d9-xyz12           1/1  Running
# vpa-updater-5c7d9e8f0-uvw34               1/1  Running

# 查看日志确认 Recommender 正常工作
kubectl logs -n kube-system -l app=vpa-recommender --tail=50

注意:VPA 依赖 Metrics Server 提供资源指标数据。如果你的集群还没有安装 Metrics Server:

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

生产环境中常见的问题与避坑指南

在经过多个生产集群的实际部署后,我总结了一些容易踩的坑,分享出来供你参考:

OOMKill 循环风险

这是 VPA Auto 模式最常见的风险。当 VPA 推荐的内存值偏低时,Pod 可能因为内存不足被 OOM Killer 杀掉,然后被 Updater 驱逐重建,重建后又被 OOM Kill,形成死循环。

解决方法:始终设置合理的 minAllowed,不要低于应用实际运行所需的基础内存。推荐先以 Off 模式运行两周,观察 Recommender 的 lowerBound,然后以这个值的 1.2 倍作为 minAllowed。

resourcePolicy:
  containerPolicies:
    - containerName: "*"
      minAllowed:
        cpu: 200m
        memory: 512Mi   # 设置安全下限

滚动更新与 VPA 的冲突

当你手动触发 Deployment 滚动更新时,Updater 可能也在同时驱逐 Pod。这会导致新版本 Pod 刚启动就被 VPA 驱逐,造成更新延迟。

解决方法:在滚动更新前将 VPA 模式临时切换到 Off,更新完成并确认稳定后再切回 Auto。或者使用 updateMode: Initial,让 VPA 只在新 Pod 首次启动时设置资源值,后续即使推荐值变化也不触发重建。

多个容器在同一个 Pod 中

VPA 默认会为每个容器分别生成推荐值。如果你的 Pod 包含 Sidecar 容器(如 Istio Proxy),需要分别为它们配置 resourcePolicy。

resourcePolicy:
  containerPolicies:
    - containerName: "app"
      mode: "Auto"
      minAllowed:
        cpu: 100m
        memory: 256Mi
    - containerName: "istio-proxy"
      mode: "Initial"   # 对 Sidecar 只做初始配置
      minAllowed:
        cpu: 50m
        memory: 128Mi

VPA 对 burstable 和 guaranteed QoS 的影响

当 VPA 自动调整 CPU Request 后,Pod 的 QoS 等级可能发生变化。如果你的业务要求 Guaranteed QoS(Request == Limit),需要设置 controlledValues: RequestsAndLimits,并确保 VPA 同时调整两者:

resourcePolicy:
  containerPolicies:
    - containerName: "*"
      controlledResources: ["cpu", "memory"]
      controlledValues: RequestsAndLimits  # 同时调整 Request 和 Limit
      maxAllowed:
        cpu: "4"
        memory: 8Gi

监控 VPA 效果:如何判断优化是否成功

部署 VPA 之后,你需要持续监控它的实际效果。以下是几个关键指标:

推荐稳定性

使用以下命令查看 VPA 的推荐历史,判断推荐值是否已经收敛:

# 查看 VPA 当前的推荐状态
kubectl describe vpa my-app-vpa

# 使用 promql 查询推荐值的变化趋势
# 推荐值波动幅度 < 20% 视为稳定

Pod 重建频率

Auto 模式下 Updater 驱逐 Pod 的次数是一个重要指标:

# 查看 Updater 触发的驱逐事件
kubectl get events --field-selector reason=EvictedByVPA -n my-namespace

# 如果每天每个 Deployment 的驱逐次数超过 2 次
# 说明 Recommender 的推荐不够稳定,需要调整 minAllowed/maxAllowed

资源利用率变化

这是最终的 KPI。部署 VPA 前后,对比集群的资源利用率:

# 查看集群级别的资源分配情况
kubectl describe node | grep -A 5 "Allocated resources"

# 安装 Grafana 后使用 dashboard 11074 查看 VPA 专属面板

根据我的经验,VPA 上线后的第一个月效果最明显——集群的整体资源利用率通常能提升 20%-40%。三个月后趋于稳定,此时调整频率会大幅下降,进入”微调”阶段。

总结:什么时候该用 VPA?

最后做一个简单的决策指南:

  • 适合用 VPA 的场景:微服务架构、无状态 Web 服务、批处理任务、CI/CD Runner——这些应用的资源消耗模式相对可控,VPA 能精准匹配
  • 不适合用 VPA 的场景:数据库(MySQL/PostgreSQL)、缓存(Redis/Memcached)、消息队列——这些有状态应用的资源配置通常需要人工根据业务数据量精细调整,VPA 的自动驱逐可能造成服务中断
  • 先用 Off 模式观察:对于不确定是否适合的应用,先用 Off 模式运行两周,看推荐值是否合理,再决定是否启用 Auto

VPA 不是银弹,但它确实是 Kubernetes 集群资源管理工具箱中不可或缺的一件利器。配合 HPA、Cluster Autoscaler 一起使用,才能构建出一个真正高效、自动化的 Kubernetes 集群。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » Kubernetes VPA 深度指南:当 HPA 不够用时,如何通过 Vertical Pod Autoscaler 自动优化资源分配
分享到: 更多 (0)