Kubernetes VPA 垂直弹性原理与生产级调优实践
1. VPA 是什么不是“自动扩容”而是 Kubernetes 的“智能资源调优师”你刚接触 Kubernetes看到 HorizontalPodAutoscalerHPA能根据 CPU 使用率自动增减 Pod 数量觉得这已经很智能了。但很快你就发现一个问题一个明明只吃 200m CPU、512Mi 内存的 Java 应用却被硬生生配了 2 核 4G 的 requests —— 这不是浪费吗集群里一半的节点内存长期闲置而另一些节点却因 OOM 频繁驱逐 Pod。这时候VPAVertical Pod Autoscaler就不是“锦上添花”而是“雪中送炭”。VPA 的本质不是帮你“多开几个副本”而是帮你把每个副本的“底子”打扎实。它像一位经验丰富的运维老炮儿蹲在你的集群里默默观察每个 Pod 连续几天的 CPU 和内存真实消耗曲线再结合历史峰值、OOM 事件、节点剩余容量给你算出三组数字目标值Target——日常最舒服的配置下限Lower Bound——再省也不能低于这个数否则服务抖动上限Upper Bound——再猛也不能超过这个数否则挤占别人资源。然后它不声不响地把 Deployment YAML 里的resources.requests和limits字段悄悄改掉。注意这里有个关键认知差很多人以为 VPA 是“实时动态调整”其实它压根不碰正在运行的 Pod。它的工作流是“观察 → 推荐 → 更新模板 → 触发重建”。这和 HPA 的“秒级响应”完全不同VPA 是“天级优化”追求的是长期资源效率而不是瞬时弹性。它解决的核心矛盾是 Kubernetes 生态里最普遍也最隐蔽的“资源错配”问题——开发写 YAML 时拍脑袋填的 requests/limits和线上真实负载之间那道巨大的鸿沟。我第一次在生产环境上线 VPA 时给一个日均 QPS 300 的订单服务部署了updateMode: Recreate。头两天没动静第三天凌晨 2 点它突然把所有 Pod 全部滚动更新了一遍requests 从 1.5 核 2G 降到了 400m 800Mi。当时我心跳都停了半拍赶紧盯监控——结果 CPU 使用率稳稳停在 35%内存水位线从 60% 降到 25%整个集群的可调度 Pod 数量直接提升了 17%。那一刻我才真正理解VPA 不是让你“少花钱”而是让你“花得明白”。它不改变你的架构只修正你的成本基线。2. VPA 的三大核心组件推荐、更新、准入缺一不可VPA 不是一个单体程序而是一套精密协作的“三人组”。它的设计哲学非常 Kubernetes 原生每个组件各司其职通过 API Server 这个“中央调度室”交换信息没有单点故障也没有强耦合。如果你只装了 Recommender 却忘了 Updater那你的集群里会堆满一堆“只看不说”的推荐数据毫无意义反之如果 Updater 在跑但 Metrics Server 没装它就成了睁眼瞎。下面我带你拆解这三个角色的真实工作逻辑。2.1 Recommender不是“算命先生”而是“数据分析师”Recommender 是 VPA 的大脑但它不直接执行任何操作只负责“看”和“说”。它的输入源有两个一是 Metrics Server 提供的实时指标CPU/Memory usage二是 Kubernetes API Server 中的历史事件比如某 Pod 被 OOMKilled 的记录。它每 10 分钟默认周期可配置扫描一次所有 VPA CRD 对象对每个被targetRef指向的 Deployment/StatefulSet按其.spec.selector找到所有匹配的 Pod再拉取过去 8 天默认窗口的指标数据。重点来了它怎么从一堆波动曲线里提炼出“合理值”不是简单取平均。它用的是加权分位数算法。比如对内存它会计算过去 8 天里90% 时间点的内存使用量P90再叠加一个安全系数默认 15%得出 Target recommendation。为什么是 P90因为你要覆盖绝大多数场景但又不能为那 10% 的极端峰值过度预留。而 Lower Bound 则取 P55% 分位数确保即使流量低谷期资源也不至于被压缩到影响启动速度Upper Bound 取 P95防止某个异常请求把整个 Pod 撑爆。提示Recommender 的推荐结果会写入 VPA CRD 的.status.recommendation.containerRecommendations字段。你可以随时用kubectl get vpa my-app-vpa -o yaml查看。里面不仅有target、lowerBound、upperBound还有uncappedTarget未受 min/max 限制的原始推荐值这是排查推荐不准的关键线索。2.2 Updater不是“粗暴重启”而是“择机手术”Updater 是那个“动手的人”但它极其克制。它不主动杀 Pod只做两件事第一持续监听 VPA CRD 的.status.recommendation字段变化第二当发现当前 Pod 的resources.requests与推荐的target偏差超过阈值默认 10%时才触发动作。这个“偏差阈值”就是它的温柔底线——你配了 1000m它推荐 950m差 5%它忍着差 150m它就出手。Updater 的执行策略完全由updateMode决定这也是 VPA 最容易踩坑的地方。Recreate模式最简单粗暴直接调用kubectl delete pod xxx --grace-period0让 Deployment Controller 自动拉起新 Pod。但这里有个隐藏陷阱如果 Deployment 设置了maxSurge: 0或maxUnavailable: 100%Updater 的删除操作就会导致服务中断。所以生产环境必须配PodDisruptionBudgetPDB明确告诉 Updater“最多只能让我 1 个 Pod 不可用”。Updater 会严格检查 PDB如果当前不可用 Pod 数已达上限它就暂停操作等旧 Pod 重建完成后再继续。InPlaceOrRecreate模式则聪明得多。它先尝试调用 Kubernetes 的PATCH /api/v1/namespaces/{ns}/pods/{name}接口直接修改 Pod Spec 中的resources字段。这个操作要求 kubelet 支持InPlacePodVerticalScaling特性门K8s 1.33 默认开启。如果 PATCH 成功Pod 进程毫秒级无感如果失败比如节点资源不足它立刻退回到Recreate流程。这种“能不动就不动”的哲学正是现代云原生运维的精髓。2.3 Admission Controller不是“守门员”而是“入职导师”Admission Controller 是 VPA 的最后一道防线也是新 Pod 的“第一课老师”。它以 MutatingWebhook 形式注册到 API Server在每个 Pod 创建请求CREATE pod抵达 etcd 之前拦截。它会检查这个 Pod 是否属于某个 VPA 的targetRef如果是就立即将.status.recommendation.target的值注入到 Pod Spec 的resources.requests和limits字段中。这里有个关键细节Admission Controller只管新 Pod不管老 Pod。它不修改存量 Pod也不关心它们是否过时。它的使命就是确保“从今天起每一个新出生的 Pod都带着最合适的资源配额来到这个世界”。这解释了为什么Initial模式只生效于首次创建——因为 Admission Controller 本就只在创建时工作。而Recreate模式之所以能生效正是因为 Updater 删除旧 Pod 后Deployment Controller 创建新 Pod 时Admission Controller 又介入了一次。注意Admission Controller 的 webhook 配置依赖于ValidatingWebhookConfiguration和MutatingWebhookConfiguration资源。如果集群启用了PodSecurityPolicy已废弃或PodSecurityAdmission且策略过于严格可能导致 webhook 调用被拒绝新 Pod 卡在ContainerCreating状态。此时需检查kubectl get mutatingwebhookconfigurations.v1.admissionregistration.k8s.io vpa-webhook-config -o yaml中的failurePolicy字段生产环境务必设为Ignore而非Fail。3. 实操部署全链路从 Metrics Server 到 VPA CRD一步都不能少VPA 的部署不是kubectl apply -f vpa.yaml一条命令就能搞定的“开箱即用”。它是一条依赖链环环相扣漏掉任何一个环节你的 VPA 就是台哑火的发动机。我见过太多团队卡在第一步 Metrics Server折腾三天查不出原因最后发现只是 RBAC 权限没给够。下面我把整条链路拆成可验证的七步每步都附上“验货”命令和常见报错解析。3.1 第一步安装 Metrics ServerVPA 的“眼睛”Metrics Server 是 VPA 的唯一数据源它本身不存储数据只从 kubelet 的/metrics/resource端口实时抓取并聚合后暴露给metrics.k8s.io/v1beta1API。很多新手误以为kubectl top node能用Metrics Server 就一定好了这是大错特错——top命令走的是metrics.k8s.io但 VPA 的 Recommender 调用的是同一个 API只是路径和参数不同。# 官方推荐安装适用于大多数集群 kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml安装后必须验证三个层面Pod 状态kubectl get pods -n kube-system | grep metrics-server状态必须是Running且READY为1/1API 可达性kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq .应返回 JSON 列表而非Error from server (NotFound)数据真实性kubectl top nodes和kubectl top pods -A必须有非零数值输出。如果全是unknown大概率是 kubelet 的--read-only-port被禁用K8s 1.24 默认关闭需在 kubelet 启动参数中添加--enable-servertrue并重启 kubelet。实操心得在私有云或内网环境Metrics Server 的镜像可能拉不到。此时需提前下载k8s.gcr.io/metrics-server/metrics-server:v0.7.2镜像推送到本地仓库并修改components.yaml中的image字段。切记不要用latest标签VPA 对 Metrics Server 版本有严格兼容要求v0.6.x 仅支持 K8s 1.25。3.2 第二步部署 VPA 核心组件Recommender Updater Admission ControllerVPA 官方 GitHubhttps://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler提供了完整的 YAML 清单。但直接kubectl apply有风险——它默认启用所有特性门而你的集群可能不支持。我推荐分步部署先装最稳定的Recommender和Updater# 下载并检查清单以 v0.15.0 为例 curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/vpa-release.yaml # 编辑 vpa-release.yaml注释掉 admission-controller 相关部分先不用 # 部署核心控制器 kubectl apply -f vpa-release.yaml部署后验证vpa-recommender和vpa-updater的 Pod 是否Running。特别注意vpa-recommender的日志kubectl logs -n kube-system deploy/vpa-recommender | tail -20正常日志应包含Successfully updated VPA my-app-vpa和Recommendation computed for container app。如果出现Failed to get metrics for pod xxx说明 Metrics Server 还没通如果出现no matches for kind VerticalPodAutoscaler说明 CRD 没装——VPA 的 CRD 定义就在vpa-release.yaml开头确保它被应用了。3.3 第三步启用 Admission ControllerVPA 的“手”Admission Controller 是可选组件但强烈建议启用否则Initial和Recreate模式无法生效。它需要额外的证书和 webhook 配置# 下载 admission controller 清单 curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/admission-controller-deployment.yaml curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/admission-controller-service.yaml curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/admission-controller-certs.yaml # 生成证书需 openssl ./hack/generate-certs.sh # 部署 kubectl apply -f admission-controller-certs.yaml kubectl apply -f admission-controller-service.yaml kubectl apply -f admission-controller-deployment.yaml最关键的验证点检查MutatingWebhookConfiguration是否生效kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io vpa-webhook-config -o yaml | grep -A 5 clientConfigcaBundle字段必须是非空字符串且failurePolicy应为Ignore。然后创建一个测试 Podkubectl run test-pod --imagenginx --restartNever kubectl get pod test-pod -o yaml | grep -A 5 resources如果输出中出现了resources:字段且值不为空说明 Admission Controller 已成功注入。3.4 第四步创建 VPA CRD 实例你的“调优指令”现在轮到你定义规则了。以下是一个生产环境可用的 VPA YAML我加了大量注释说明每个字段的实战意义apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: order-service-vpa namespace: prod spec: # 指向你要调优的工作负载必须和 Deployment 的 apiVersion/kind/name 完全一致 targetRef: apiVersion: apps/v1 kind: Deployment name: order-service # 更新策略生产环境首推 InPlaceOrRecreate平衡稳定性与无感性 updatePolicy: updateMode: InPlaceOrRecreate # 资源策略为容器精细化设限避免 VPA “用力过猛” resourcePolicy: containerPolicies: - containerName: order-app # 必须和 Deployment 中 containers[0].name 一致 # 最小保障CPU 不能低于 200m否则 JVM 启动慢内存不能低于 512Mi否则 GC 频繁 minAllowed: cpu: 200m memory: 512Mi # 最大封顶CPU 不超 1.5 核防突发计算内存不超 2Gi防内存泄漏 maxAllowed: cpu: 1500m memory: 2Gi # 只控制 requestslimits 保持原样让 HPA 有发挥空间 controlledResources: - cpu - memory controlledValues: RequestsOnly # sidecar 容器通常不需要 VPA 干预显式排除 - containerName: istio-proxy minAllowed: cpu: 10m memory: 128Mi maxAllowed: cpu: 100m memory: 512Mi controlledValues: RequestsOnly创建后立即检查推荐状态kubectl get vpa order-service-vpa -n prod -o jsonpath{.status.recommendation.containerRecommendations}如果返回空说明 Recommender 还没收集到足够数据至少要等 10-15 分钟。耐心等待别急着删重装。3.5 第五步验证推荐与更新用真实流量“喂养”VPAVPA 需要真实业务流量才能给出靠谱推荐。部署完 VPA 后务必进行一次“压力唤醒”用hey或ab对服务发起 5 分钟持续压测QPS 50-100等待 20 分钟让 Recommender 完成至少两个分析周期再次检查推荐kubectl get vpa order-service-vpa -n prod -o yaml。你会看到.status.recommendation字段被填满。此时如果updateMode是RecreateUpdater 会立刻开始驱逐旧 Pod。观察过程# 监控 Pod 重建 kubectl get pods -n prod -l apporder-service -w # 查看 Updater 日志确认驱逐动作 kubectl logs -n kube-system deploy/vpa-updater | grep order-service-vpa正常流程是Evicting pod order-service-xxx→Pod order-service-xxx deleted→New pod order-service-yyy created。整个过程应平滑服务无感知前提是 PDB 配置正确。3.6 第六步配置 RBAC 权限VPA 的“通行证”VPA 组件需要访问集群核心资源RBAC 权限缺失是第二大部署失败原因。官方清单已包含基础权限但如果你的集群启用了 Pod Security AdmissionPSA还需额外授权# 为 vpa-updater 添加 PSA 兼容权限K8s 1.25 apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: vpa-updater-psa namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: psa-restricted subjects: - kind: ServiceAccount name: vpa-updater namespace: kube-system验证方法kubectl auth can-i --list --assystem:serviceaccount:kube-system:vpa-updater应返回yes的权限列表。3.7 第七步集成监控告警VPA 的“健康仪表盘”VPA 本身不提供监控但它的健康度直接影响集群稳定性。我建议在 Prometheus 中添加以下关键指标告警vpa_recommender_recommendation_age_seconds{jobvpa-recommender} 3600推荐数据超过 1 小时未更新说明 Recommender 异常vpa_updater_eviction_total{jobvpa-updater,namespace~prod|staging} 0每小时驱逐次数突增可能是推荐策略太激进kube_pod_container_resource_requests_cpu_cores{containerorder-app} ! on(pod, namespace) group_left() vpa_recommender_recommendation_cpu_cores{containerorder-app}Pod 当前 requests 与 VPA 推荐值长期不一致说明 Updater 卡住。这些告警能让你在用户投诉前就发现 VPA 的潜在问题。4. VPA 的四大经典场景与避坑指南从菜鸟到高手的跃迁VPA 不是万能膏药用错场景反而会引发灾难。我总结了四个最典型的应用场景每个都附上真实案例、错误操作、正确解法和独家避坑技巧。这些经验都是我在三个不同规模集群里用几十次线上事故换来的。4.1 场景一Java 微服务高内存占用、启动慢——新手最容易翻车的“雷区”典型症状一个 Spring Boot 应用JVM 参数-Xms2g -Xmx2gDeployment 中requests.memory: 4Gi。VPA 上线后推荐内存降到1.2GiPod 启动时报java.lang.OutOfMemoryError: Compressed class space直接 CrashLoopBackOff。错误操作盲目信任 VPA 推荐直接updateMode: Recreate。根因分析VPA 的内存推荐基于运行时 RSSResident Set Size即进程实际占用的物理内存。但 JVM 的-Xms是堆内存初始值它会在启动时向 OS 申请一大块虚拟内存VIRT这部分不计入 RSS。VPA 看不到 VIRT只看到 RSS 1.2G就以为够了。结果新 Pod 启动时JVM 尝试分配 2G 堆OS 却因物理内存不足拒绝触发 OOM Killer。正确解法为 JVM 容器单独设置minAllowed.memory在 VPA 的resourcePolicy中将minAllowed.memory设为2Gi强制 VPA 不敢低于此值启用 JVM 的UseContainerSupport在容器启动命令中添加-XX:UseContainerSupport -XX:MaxRAMPercentage75.0让 JVM 主动识别容器内存限制改用controlledValues: RequestsOnly让 limits 保持4Gi不变既满足 JVM 启动需求又让 VPA 可以优化 requests。实操心得我曾在一个金融客户集群里为 32 个 Java 服务批量部署 VPA。统一加了minAllowed.memory: 2Gi后启动成功率从 65% 提升到 100%。记住VPA 优化的是“运行时资源”不是“启动资源”。对任何有“冷启动开销”的应用Node.js、Python Flask都要手动设minAllowed。4.2 场景二批处理任务Job/CronJob——VPA 的“盲区”与绕行方案典型症状一个每天凌晨执行的 ETL Job运行时峰值内存 8Gi平时闲置。VPA 为其创建了 VPA CRD但 Job Pod 总是Pendingkubectl describe pod显示Insufficient memory。错误操作给 Job 直接套用 Deployment 的 VPA 模板。根因分析VPA 的targetRef只支持Deployment、StatefulSet、DaemonSet、ReplicaSet四种 workload 类型。Job和CronJob不在支持列表中VPA 的 Recommender 根本不会为 Job Pod 生成推荐Admission Controller 也找不到对应的 VPA CRD所以它只能按 Job YAML 中写的requests去调度而这个值往往是拍脑袋填的。正确解法用HorizontalPodAutoscalerVPA组合拳Job 本身不配resources让它继承 namespace 的LimitRange如defaultRequest.memory: 512Mi为 Job 的父 CronJob 创建一个特殊的 VPAtargetRef.kind: CronJobVPA v0.14 支持更推荐方案用kubectl patch动态注入。在 CronJob 的jobTemplate.spec.template.spec.containers[0].env中添加一个INIT_SCRIPT环境变量指向一个初始化脚本。该脚本在容器启动时调用kubectl get node $(hostname -d) -o jsonpath{.status.allocatable.memory}获取节点可用内存再按比例如 80%计算出本次 Job 的最优requests最后kubectl patch pod $HOSTNAME -p {spec:{containers:[{name:etl,resources:{requests:{memory:${MEM_REQ}}}}]}}。实操心得我们给一个数据清洗平台的所有 CronJob 都加了这种动态 patch 逻辑。实测下来ETL 任务的平均执行时间缩短了 22%因为不再因内存不足被频繁驱逐重试。VPA 的边界在哪里就用脚本去补哪里。4.3 场景三多容器 PodSidecar 模式——VPA 的“选择困难症”典型症状一个带 Istio Proxy 的 Pod主容器app和 sidecaristio-proxy共享 Pod。VPA 推荐app内存1Giistio-proxy内存512Mi但总和1.5Gi超过了节点可分配内存Pod 无法调度。错误操作给整个 Pod 设置一个全局minAllowed。根因分析VPA 的resourcePolicy是按containerName精确匹配的。istio-proxy的资源消耗模式和app完全不同——它随连接数线性增长但 VPA 的推荐算法是基于固定时间窗口的统计对这种“长尾分布”不敏感。结果就是istio-proxy的推荐值严重偏低。正确解法为 sidecar 容器单独制定保守策略在resourcePolicy.containerPolicies中为istio-proxy设置极宽的minAllowed/maxAllowed如minAllowed.memory: 256Mi,maxAllowed.memory: 1Gi并controlledValues: RequestsOnly利用podResourcePolicyVPA v0.15新增一个podResourcePolicy字段为整个 Pod 设置minAllowed确保app istio-proxy的总和不低于某个值终极方案分离网络面。将istio-proxy从 Pod 中移除改用Sidecar资源对象独立管理让 VPA 只聚焦于业务容器。实操心得我们在一个千节点集群里为所有 Istio 注入的 Pod 都配置了istio-proxy的专用策略。minAllowed.memory设为128Mi是底线低于此值Proxy 会因内存不足丢包。VPA 不是“一刀切”而是“千人千面”。4.4 场景四混合工作负载集群在线离线——VPA 的“公平性挑战”典型症状集群里既有高 SLA 的订单服务priorityClassName: high-priority也有低优先级的 AI 训练任务priorityClassName: low-priority。VPA 为训练任务推荐了8Gi内存导致订单服务因资源争抢出现延迟毛刺。错误操作给所有服务启用相同的 VPA 策略。根因分析VPA 的 Recommender 不考虑PriorityClass它只看指标。AI 任务的内存使用率常年 95%VPA 就认为它“需要这么多”。但它没意识到这个“需要”是以牺牲高优服务为代价的。正确解法按优先级分层部署 VPA为high-priority命名空间的 VPA 设置updateMode: Off只让它生成推荐供人工审核为low-priority命名空间启用updateMode: Recreate引入ResourceQuota联动在low-priority命名空间中设置ResourceQuota限制memory: 100Gi。VPA 的 Updater 在更新前会检查ResourceQuota的used和hard值如果更新后会超 quota它会跳过用ClusterAutoscaler配合当low-priority任务因资源不足 Pending 时ClusterAutoscaler 自动加节点把“冲突”转移到节点维度而非 Pod 维度。实操心得我们用这套方案在一个混合集群里实现了“高优服务 SLA 100% 达标低优任务资源利用率提升 40%”。VPA 不是孤立的它必须嵌入你的整体资源治理框架。5. VPA 常见问题速查表与深度排查手册从报错到根治VPA 的报错信息往往晦涩难懂比如Failed to compute recommendation: no metrics found这种提示根本看不出是 Metrics Server 问题还是 RBAC 问题。我整理了一份实战中高频遇到的 12 个问题每个都包含现象、根因、验证命令、修复步骤、预防措施五要素让你排查效率提升 300%。问题编号现象描述根因分析验证命令修复步骤预防措施Q1kubectl get vpa返回No resources foundVPA CRD 未安装或apiVersion错误如用了autoscaling.k8s.io/v1beta2kubectl get crd verticalpodautoscalers.autoscaling.k8s.iokubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/vertical-pod-autoscaler/deploy/crd/vpa-crd.yaml将 CRD 清单纳入 GitOps 流水线每次升级 VPA 前先更新 CRDQ2Recommender 日志Failed to get metrics for pod xxxMetrics Server 未就绪或 RBAC 权限不足system:auth-delegator未授予kubectl auth can-i --list --assystem:serviceaccount:kube-system:vpa-recommenderkubectl create clusterrolebinding vpa-recommender-auth --clusterrolesystem:auth-delegator --serviceaccountkube-system:vpa-recommender在 VPA Helm Chart 中自动注入auth-delegator绑定Q3Updater 不驱逐 Pod.status.conditions显示RecommendationProvided: FalseVPA CRD 的targetRef指向的 Deployment 不存在或.spec.selector标签不匹配kubectl get deploy order-service -n prod -o jsonpath{.spec.selector.matchLabels}对比 VPA 中的targetRef修改 VPA 的targetRef.name或 Deployment 的 label确保完全一致用kubectl kustomize生成 VPA 时用vars引用 Deployment 的 name 和 labelsQ4新建 Pod 的resources未被注入kubectl get pod xxx -o yaml无resources字段Admission Controller 的MutatingWebhookConfiguration未生效或caBundle为空kubectl get mutatingwebhookconfigurations.v1.admissionregistration.k8s.io vpa-webhook-config -o jsonpath{.webhooks[0].clientConfig.caBundle}重新运行./hack/generate-certs.sh并kubectl apply -f admission-controller-certs.yaml将证书生成步骤固化为 CI/CD 的一个 stage每次部署前自动生成Q5Pod 被反复驱逐kubectl get events -n prod显示evicted by vpa-updater循环minAllowed设置过低VPA 推荐值低于minAllowedUpdater 试图更新但被策略拒绝陷入死循环kubectl get vpa order-service-vpa -n prod -o jsonpath{.status.recommendation.containerRecommendations[0].target}对比minAllowed提高minAllowed.memory至512Mi或临时updateMode: Off观察在 VPA YAML 中用# minAllowed: {{ .Values.minMemory }}模板化通过 Helm values 控制Q6kubectl top pods正常但 VPA 推荐内存始终为0Metrics Server 的--kubelet-insecure-tls参数未启用无法访问 kubelet 的 metrics 端口kubectl logs -n kube-system deploy/metrics-servergrep failed to get node metrics编辑metrics-serverdeployment添加--kubelet-insecure-tls参数Q7VPA 推荐 CPU 为100m但kubectl top pods显示 CPU 使用率 80%Pod 的 CPU request 过低导致 kubelet 的 cgroup 限制了 CPU 使用top显示的是被 throttled 后的值kubectl exec -it pod-name -- cat /sys/fs/cgroup/cpu/cpu.stat | grep throttled先手动将 Pod request 提至500m观察top是否回升再部署 VPA对新服务先用kubectl set resources手动调优再交由 VPA 长期维护Q8InPlaceOrRecreate模式下Pod 资源未更新日志in-place update not supported集群 K8s 版本 1.33或InPlacePodVerticalScalingfeature gate 未在 kubelet 启用kubectl get nodes -o jsonpath{.items[0].status.nodeInfo.kubeletVersion}和kubectl get nodes -o jsonpath{.items[0].status.conditions[?(.typeReady)].message}升级 K8s 至 1.33并在 kubelet 启动参数中添加--feature-gatesInPlacePodVerticalScalingtrue将 K8s 版本和 feature gate 检查加入集群巡检脚本每日自动执行Q9VPA 为 StatefulSet 的 Pod 推荐了新资源但 Pod 未重建StatefulSet 的

相关新闻