# Kubernetes VPA 垂直 Pod 自动扩缩容实战指南:智能调整容器资源配额
## 背景
Kubernetes 集群中,容器的资源配额(CPU 和内存)设置是个老难题。配高了浪费资源,配低了 Pod 被 OOM Killer 杀掉。Horizontal Pod Autoscaler(HPA)只能调副本数,改不了单个容器的大小。
VPA 就是来解决这个问题的。它能分析 Pod 实际用了多少资源,自动调整 requests,让容器拿到刚好够用的配额。
## 问题
生产环境里常见三种情况:
**场景一:资源浪费**
“`yaml
resources:
requests:
memory: “4Gi”
cpu: “2”
“`
一个简单的 REST API 服务配了 4GB 内存、2 个 CPU,实际运行只需要 512MB 内存和 0.5 个 CPU。将近 80% 的资源就这么浪费了。
**场景二:资源不够**
“`yaml
resources:
requests:
memory: “256Mi”
cpu: “100m”
“`
数据处理任务初始配小了,数据量上来后 Pod 频繁 OOMKilled,服务根本跑不稳。
**场景三:资源动态变化**
批处理任务开始要大量资源做数据加载,后面处理阶段需求骤降。固定配置根本兜不住。
HPA 只能靠加副本分担压力,集群开销反而增加了。VPA 直接从根上解决配额不合理的问题。
## 步骤
### 1. 安装 VPA 组件
VPA 三个组件:Recommender(推荐器)、Updater(更新器)、Admission Controller(准入控制器)。
“`bash
# 创建 VPA 命名空间
kubectl create namespace kubernetes-metrics
# 安装 VPA CRD
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/vpa-crds.yaml
# 安装 VPA 组件
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/vpa-rbac.yaml
# 下载 VPA 部署清单
wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/recommender-deployment.yaml
wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/updater-deployment.yaml
wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/admission-controller-deployment.yaml
# 修改镜像地址
sed -i ‘s|gcr.io/autoscaling/vpa-recommender:|registry.k8s.io/autoscaling/vpa-recommender:|g’ recommender-deployment.yaml
sed -i ‘s|gcr.io/autoscaling/vpa-updater:|registry.k8s.io/autoscaling/vpa-updater:|g’ updater-deployment.yaml
sed -i ‘s|gcr.io/autoscaling/vpa-admission-controller:|registry.k8s.io/autoscaling/vpa-admission-controller:|g’ admission-controller-deployment.yaml
# 部署
kubectl apply -f recommender-deployment.yaml
kubectl apply -f updater-deployment.yaml
kubectl apply -f admission-controller-deployment.yaml
“`
### 2. 验证安装
“`bash
# 检查 Pod 状态
kubectl get pods -n kube-system | grep vpa
# 查看推荐器日志
kubectl logs -n kube-system -l app=vpa-recommender –tail=50
“`
### 3. 创建测试应用
一个 PHP 应用来演示效果:
“`yaml
apiVersion: v1
kind: Namespace
metadata:
name: vpa-demo
—
apiVersion: apps/v1
kind: Deployment
metadata:
name: vpa-demo-app
namespace: vpa-demo
spec:
replicas: 2
selector:
matchLabels:
app: vpa-demo
template:
metadata:
labels:
app: vpa-demo
spec:
containers:
– name: demo-container
image: php:8.2-apache
ports:
– containerPort: 80
resources:
requests:
cpu: “100m”
memory: “128Mi”
command: [“php”, “-S”, “0.0.0.0:80”, “-t”, “/var/www/html”]
env:
– name: SIMULATE_LOAD
value: “true”
“`
初始配置较低,后面看 VPA 怎么调高。
### 4. 创建 VPA 策略
用 CRD 定义调整策略:
“`yaml
apiVersion: “autoscaling.k8s.io/v1”
kind: VerticalPodAutoscaler
metadata:
name: vpa-demo-policy
namespace: vpa-demo
spec:
targetRef:
apiVersion: “apps/v1”
kind: Deployment
name: vpa-demo-app
updatePolicy:
updateMode: “Auto”
resourcePolicy:
containerPolicies:
– containerName: “demo-container”
minAllowed:
cpu: “50m”
memory: “64Mi”
maxAllowed:
cpu: “4”
memory: “8Gi”
controlledResources: [“cpu”, “memory”]
“`
– **updateMode**: “Auto” 会自动更新 Pod 请求,”Off” 只给建议不动手
– **minAllowed / maxAllowed**: 调整的上下限,避免跑偏
– **controlledResources**: 要控制哪些资源类型
### 5. 生成负载
让 VPA 有数据可分析:
“`bash
# 进入 Pod
kubectl exec -it -n vpa-demo deploy/vpa-demo-app — /bin/bash
# 写个负载测试脚本
cat > /var/www/html/index.php << 'EOF'
/dev/null &
done
wait
“`
## 结果
### 查看 VPA 建议
等几分钟让它收集数据:
“`bash
kubectl get vpa vpa-demo-policy -n vpa-demo -o yaml
“`
输出示例:
“`yaml
status:
recommendation:
containerRecommendations:
– containerName: demo-container
lowerBound:
cpu: “156m”
memory: “198Mi”
target:
cpu: “350m”
memory: “512Mi”
uncappedTarget:
cpu: “450m”
memory: “650Mi”
upperBound:
cpu: “650m”
memory: “1Gi”
“`
– **target**: 最佳推荐值
– **lowerBound**: 再低可能不够用
– **upperBound**: 再高就浪费了
– **uncappedTarget**: 不考虑 maxAllowed 的目标值
### 自动更新 Pod
Updater 检测到差异后会触发更新:
“`bash
kubectl logs -n kube-system -l app=vpa-updater –tail=30
“`
日志:
“`
I0411 06:15:23.456789 1 updater.go:234] Updating Pod pod=vpa-demo/vpa-demo-app-abc123 container=demo-container oldRequest=cpu:100m,memory:128Mi newRequest=cpu:350m,memory:512Mi
“`
Pod 重启,应用新配置。滚动更新保证服务不断。
### 观察变化
“`bash
# 看资源配置
kubectl get pods -n vpa-demo -o wide
# 监控实际使用
kubectl top pods -n vpa-demo
“`
## 总结
VPA 解决了 Kubernetes 资源管理的核心痛点:
1. **省钱**: 不合理的配置调成实际需求,减少浪费
2. **稳**: 避免 OOM 导致的服务崩溃
3. **省事**: 不用人工盯着调,VPA 持续优化
几点要注意:
– 初始观察期需要 2-3 天收集数据,太早的建议不准
– VPA 调请求,HPA 调副本,两者可以一起用
– 自动模式会重启 Pod,生产环境把 minAllowed 设好
– 建议给资源调整加告警,及时知道发生了变化
VPA 特别适合资源需求波动大、不好预估的工作负载。