4、VPA(垂直伸缩):VPA原理、Recommender模式、与HPA的共存策略
好,咱们来聊聊VPA。说实话,HPA解决的是“加机器”的问题,而VPA解决的是“给机器加资源”的问题。一个是水平扩展,一个是垂直扩展。很多刚接触Kubernetes的同学容易把这两个搞混,其实它们俩的适用场景完全不同。
我最早接触VPA是在一个AI训练平台上。那时候GPU资源特别贵,Pod的资源申请写得特别保守,结果CPU和内存利用率长期不到30%。后来上了VPA,资源利用率直接翻了一倍。嗯,今天我就把VPA的底裤扒干净,从原理到实战,一次讲透。
4.1 VPA的核心原理
VPA的全称是Vertical Pod Autoscaler。它的工作说白了就是:根据Pod的实际资源使用情况,动态调整Pod的CPU和内存的requests和limits。
你想想看,传统方式下,我们得手动估算每个Pod需要多少资源。估少了,Pod被OOM Kill;估多了,资源白白浪费。VPA就是来解决这个问题的。
VPA的核心组件有三个:
- Recommender:负责采集指标,给出推荐值。这是VPA的大脑。
- Updater:负责执行更新。它会驱逐需要调整的Pod,让ReplicaSet重新创建。
- Admission Controller:负责在Pod创建时注入推荐值。这是VPA的守门员。
整个流程是这样的:Recommender从Metrics Server拉取Pod的历史指标,然后计算出推荐的资源值。Updater发现当前Pod的requests和推荐值差距太大,就驱逐这个Pod。Pod被重新创建时,Admission Controller会把推荐值写进去。
这里有个关键点:VPA调整Pod是需要重启的。这一点和HPA完全不同,HPA加副本是不需要重启的。所以,如果你的应用不能接受重启,那VPA可能就不太适合你。
4.2 Recommender模式详解
Recommender是VPA里最核心的部分。我当年研究它源码的时候,发现它的推荐算法其实挺有意思的。
Recommender支持两种模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| Auto | 自动推荐并自动应用 | 生产环境,资源利用率敏感 |
| Initial | 只在Pod创建时推荐一次 | 不想频繁重启的场景 |
| Off | 只推荐,不自动应用 | 先看看推荐值,手动调整 |
我个人习惯在生产环境用Auto模式,但前提是应用能接受重启。如果应用是那种启动特别慢的,比如Java应用要加载一堆类,那我会先用Off模式观察一段时间,确认推荐值稳定了再切到Auto。
Recommender的推荐算法基于百分位数。默认情况下,它使用P95的峰值作为推荐值。什么意思呢?就是过去8天里,95%的时间你的Pod资源使用量都低于这个值。这样既能保证大部分时间够用,又不会浪费太多资源。
小技巧:你可以通过VPA的YAML里的targetCPUPercentile和targetMemoryPercentile来调整百分位数。比如改成P99,会更保守,但资源浪费会多一些。
4.3 VPA的安装与配置
安装VPA其实不复杂。我一般用Helm来装:
# 添加VPA的Helm仓库
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
# 安装VPA
helm install vpa fairwinds-stable/vpa \
--namespace kube-system \
--set recommender.enabled=true \
--set updater.enabled=true \
--set admissionController.enabled=true
装完之后,我们来写一个VPA的YAML示例:
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: 128Mi
maxAllowed:
cpu: 4
memory: 8Gi
controlledResources: ["cpu", "memory"]
这里我设置了最小和最大限制。为什么要设?因为VPA有时候会推荐一个特别离谱的值。我曾经遇到过VPA给一个sidecar容器推荐了2核CPU,但实际上它只需要100m。所以,一定要设上下限,这是血的教训。
4.4 VPA与HPA的共存策略
这个问题是面试高频题,也是实际项目里最容易踩坑的地方。VPA和HPA能不能一起用?答案是:能,但有条件。
首先,VPA和HPA不能同时作用于同一个指标。比如,你不能让VPA调整CPU的requests,同时又让HPA基于CPU使用率扩缩容。这会导致两个控制器打架,一个在调大资源,一个在加副本,系统会变得很不稳定。
那怎么共存呢?我总结了几种策略:
策略一:HPA基于自定义指标,VPA基于CPU/内存
这是最常用的方案。HPA基于QPS、请求延迟等业务指标扩缩容,VPA负责优化每个Pod的资源分配。两者互不干扰。
策略二:HPA基于CPU/内存,VPA只做Initial模式
VPA只在Pod创建时给一个初始推荐值,之后就不管了。HPA基于CPU/内存动态扩缩容。这样VPA不会频繁重启Pod,HPA也能正常工作。
策略三:错开时间窗口
如果你非要用Auto模式的VPA和基于CPU的HPA,那就得错开它们的工作时间。比如,VPA每24小时调整一次,HPA每5分钟调整一次。但说实话,这个方案不太优雅,我不推荐。
注意:Kubernetes官方明确说了,VPA和HPA在同一个指标上共存是不支持的。如果你强行这么干,可能会遇到Pod反复重启、资源分配异常等问题。我曾经在一个客户现场见过这种情况,最后排查了两天才发现是VPA和HPA在打架。
4.5 避坑指南
最后,分享几个我踩过的坑:
- VPA不会减少Pod数量:VPA只调整单个Pod的资源,不会减少副本数。如果你发现Pod多了,那是HPA干的,别怪VPA。
- VPA重启Pod有代价:每次调整都会驱逐Pod,如果你的应用有长连接或者状态,可能会受影响。建议配合PDB(PodDisruptionBudget)使用。
- VPA的推荐值可能不稳定:特别是新上线的服务,历史数据不够,推荐值会跳来跳去。我建议先用Off模式观察一周,再切到Auto。
- 注意OOMKill的恶性循环:如果Pod频繁OOM,VPA会不断调大内存,但调大之后Pod可能还是OOM,因为内存泄漏了。这时候VPA解决不了问题,得先修代码。
嗯,VPA的内容差不多就这些了。说白了,VPA是一个很实用的工具,但也不是银弹。它最适合那些资源使用波动大、但又不能接受频繁扩缩容的场景。下一章咱们聊聊Cluster Autoscaler,那个是管集群层面的资源弹性的,到时候你会发现,这三个Autoscaler配合起来用,才是真正的弹性伸缩体系。