资讯动态

Kubernetes 自动缩放全链路:HPA/VPA/CA 配置与避坑指南

发布时间:2026/9/30 11:58:59 来源:尧图企业网站定制
1. 先把“自动缩放”这个东西拆清楚再动手Kubernetes 自动缩放我第一次在生产环境接触是在四年前。那时候 HPA 刚刚普及团队里一群人对着“CPU 超过 70% 加副本”的规则一顿猛拍结果一到大促就翻车。后来踩的坑多了才意识到自动缩放不是三个字母 HPA 那么简单。本文以 v1.26.0 集群为例按照“数据源 - 水平缩放 - 垂直缩放 - 节点缩放”的顺序把我整理过的实战经验完整讲一遍适合刚接触自动缩放、准备在自己的部署环境里搭建 HPA/VPA/CA 的工程师参考也适合已经被自动缩放整得焦头烂额、想系统排查一遍的同学。下面所有配置和命令都是我在真实环境验证过的可以直接复现。1.1 三个层面的缩放分别管哪一摊事很多人把“自动缩放”和“增加副本数”画等号这是第一个误区。在 Kubernetes 里自动缩放至少分成三个层面Pod 副本数的水平缩放HPA、Pod 资源配额的垂直缩放VPA、集群节点数量的容量缩放Cluster Autoscaler简称 CA。这三个层面解决的问题完全不同。HPAHorizontal Pod Autoscaler管的是横向伸缩。副本数不够就加 Pod副本数过剩就减 Pod。它解决的是“总处理能力不足”的问题应对的是并发量、QPS 的波动。VPAVertical Pod Autoscaler管的是垂直伸缩。它分析 Pod 的历史资源用量自动调整 CPU/memory 的 requests。它解决的是“单个 Pod 的资源配额设得不合理”的问题。比如你写了个 cpu: 500m实际经常飙到 900mVPA 会帮你把基线拉高。CACluster Autoscaler管的是节点层面。当 Pod 因为节点资源不足而 Pending 时自动加机器当节点资源利用率长期偏低时自动回收机器。它解决的是“整个集群容量不够”的问题。我记得有个生活化的类比跟团队新人讲的时候效果很好服务是餐厅Pod 是餐桌HPA 是忙时加桌子VPA 是把每张桌子换成大一号的CA 则是发现店里实在坐不下了去隔壁扩租铺面。三者配合才能真正应对流量波动缺一个都会在特定场景下出问题。比如只有 HPA 没有 CA高峰期 Pod 塞满了现有节点加副本也只能 Pending服务照样挂。1.2 为什么我先讲数据源再讲缩放动作自动缩放的核心其实不是“动作”而是“数据”。无论是 HPA 还是 VPA第一步都必须拿到 Pod 的真实资源用量。很多人上来就写 HPA YAML结果 Deployment 里的容器没配置resources.requests或者 metrics-server 根本没装好导致缩放的决策依据全是“空气”表现就是 HPA 的 TARGETS 列长期显示unknown让你无从下手。所以这篇文章的顺序是有讲究的。第二章先带你验证一个能正常采集资源指标的集群第三章再上 HPA 做水平缩放第四章讲 VPA 如何补充垂直维度第五章把节点级别的 Cluster Autoscaler 串进来。每一步我都会给出配置文件、验证命令和踩坑记录保证你照着走能落地。2. 准备一个干净环境kubeadm 初始化 v1.26.02.1 初始化命令与 preflight 检查的常见拦路虎我这次的实验环境用的是 v1.26.0初始化命令如下kubeadm init \ --kubernetes-versionv1.26.0 \ --apiserver-advertise-address192.168.10.10 \ --pod-network-cidr10.244.0.0/16执行后你会看到这样的输出[init] using kubernetes version: v1.26.0 [preflight] running pre-flight checks看到这句“running pre-flight checks”不代表万事大吉它只是开始检查。我实际部署中遇到最多的几类检查失败是这样处理的swap 未关闭。v1.26.0 的 kubelet 默认要求 swap 关闭解决办法是swapoff -a然后把/etc/fstab里的 swap 行注释掉保证重启后不反弹。6443 端口被占用。常见于同一台机器上跑过旧版集群ss -lnt | grep 6443确认后把残留的 kube-apiserver 进程清干净。sandbox 镜像拉取失败。v1.26.0 默认 pause 版本是 3.9可以先执行kubeadm config images pull提前把镜像拉好避免 init 到一半卡住。preflight 全部通过后kubeadm 会生成 kubeconfig 文件和 Token。记得把$HOME/.kube/config拷好后面所有kubectl操作都依赖它。然后选择一个 CNI 插件我用的是 Calico装完以后用kubectl get nodes确认节点状态变成 Ready这是进入下一步的前提。2.2 安装 metrics-server给缩放装上“眼睛”HPA 和 VPA 依赖的指标来自 metrics-server它不是默认安装的组件。v1.26.0 配合 metrics-server v0.6.x 比较合适用官方 components.yaml 安装kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml装完不要急着验证先等着 Deployment 起来再拿kubectl top试。我在这步必然踩的坑是kubelet 使用的自签名证书不被 metrics-server 信任Pod 能起来但一直处于 CrashLoopBackOff。日志里会看到 x509 certificate 相关报错。解决办法是给 metrics-server 加一个启动参数--kubelet-insecure-tls。用 patch 命令改起来最快kubectl patch deployment metrics-server -n kube-system \ --typejson \ -p[{op:add,path:/spec/template/spec/containers/0/args/-,value:--kubelet-insecure-tls}]还有一种典型场景是节点有多个内网 IPmetrics-server 连错网段导致超时。这时加上--kubelet-preferred-address-typesInternalIP基本能解决。改完以后等 Pod 重新起来然后验证kubectl top nodes kubectl top pods -A只要输出里有实实在在的 CPU 和内存数值说明指标链路已经打通。这一步是整个自动缩放体系的基石我会反复强调指标不正常后面全是白做。宁可多花十分钟把这一步验证透也不要急着去写 HPA。3. HPA 实操把 Pod 数量“自动”起来3.1 HPA 的缩放算法与两个容易被忽略的参数HPA 的核心算法并不复杂官方公式是desiredReplicas ceil(currentReplicas * (currentMetricValue / desiredMetricValue))举个例子当前 4 个副本CPU 平均使用率 85%目标值设为 50%那么期望副本数就是ceil(4 * 85 / 50) ceil(6.8) 7。HPA 会按这个公式周期性地计算期望副本数默认每 15 秒同步一次这个周期由 kube-controller-manager 的--horizontal-pod-autoscaler-sync-period控制。但公式只是表象真正影响行为的是另外两个参数容忍度tolerance默认 0.1即当指标偏离目标值在 10% 以内时HPA 认为“可以接受”不做伸缩。这个机制是为了避免临界点时副本数反复横跳。如果你的服务对抖动极度敏感可以调小它比如--horizontal-pod-autoscaler-tolerance0.05但要小心过于频繁的伸缩动作。冷却窗口stabilizationWindowSeconds这个参数决定 HPA 在做出缩容或扩容决定前要多长时间内观察历史建议。尤其是缩容的冷却窗口默认在 v1.26.0 里是 300 秒。这套机制的整体逻辑很像开车时的油门控制你不可能看到速度掉了一点就猛踩油门仪表盘上的瞬时数值往往会被过滤掉系统看的是更长时间窗口里的趋势。3.2 autoscaling/v2支持多指标和更精细的缩放行为v1.26.0 里稳定的 HPA API 版本是autoscaling/v2相比老版本的 v1最大的增强是支持多指标和 behavior 缩放行为控制。v1 版本一次只能配一个 CPU 目标v2 可以同时监控 CPU、内存、自定义指标取计算结果的最大值来调整副本数。同时 v2 里的behavior字段允许你分别定义 scaleUp 和 scaleDown 的策略比如“一分钟内最多新增多少个副本”“缩容窗口期是多少秒”。这在实际生产中非常有用因为老版本的 HPA 缩容特别激进流量一波动副本数立刻被打回原形下一波高峰又来扩容有延后用户体验就会抖动。新环境我建议直接使用 autoscaling/v2理由很简单语义清晰、多指标支持、行为可控制。在老版本集群上做迁移也不复杂核心就是 YAML 结构从targetCPUUtilizationPercentage改成 metrics 列表里的resource.cpu.target.averageUtilization。3.3 一份可以直接复现的 HPA 配置假设我们有一个叫web的 Deployment容器里已经配好了requests。这是 HPA 能工作的前提关于这一点我后面还会强调。下面是完整的 HPA 配置apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: web-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 - type: Resource resource: name: memory target: type: AverageValue averageValue: 800Mi behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 0 selectPolicy: Max policies: - type: Percent value: 100 periodSeconds: 60 - type: Pods value: 4 periodSeconds: 60应用后查看状态kubectl apply -f web-hpa.yaml kubectl get hpa web-hpa正常时 TARGETS 列会显示类似CPU: 37%/60%memory: 780Mi/800Mi。如果显示Unknown去查 Deployment 是否设置了 requests这是新手最常犯的错。另外我在这里用 memory 的 AverageValue 目标实际生产环境我不建议对 memory 设过死的值因为内存有大页缓存、GC 波动等因素经常会出现“指标超了但 Pod 运行良好”的误判更适合的做法是监控内存使用率趋势或者干脆只靠 CPU 加自定义业务指标。3.4 缩容震荡问题为什么副本数不能像过山车一样掉HPA 新手上路最容易碰到的不是不扩容而是缩容太猛。服务流量一波动HPA 在下一轮同步就把副本削到最小值过了几分钟流量又上来又开始扩容如此反复。业务侧看到的现象就是 Pod 频繁被杀、频繁新建日志和监控一片混乱。v2 的 behavior 字段就是用来治这个问题的。我的配置里scaleDown.stabilizationWindowSeconds: 300表示系统会记录过去 5 分钟的所有缩容建议然后选择最保守的那个执行。配了Percent: 50periodSeconds: 60之后HPA 在一分钟内最多缩掉当前副本数的 50%。这两个组合的效果是即使指标短暂下跌也不会立刻触发大规模缩容系统会“迟疑”一会儿确认趋势形成后才动手。扩容侧我反而激进一点Percent: 100意味着每分钟最多可以增加一倍副本Pods: 4表示每分钟最多加 4 个selectPolicy: Max取两者中较大的。这样在流量突增时扩容能跟上而缩容始终以稳定优先。这套配置我反复强调一点扩容要快缩容要慢。这是自动缩放里最值得背诵的经验。4. VPA把 Pod 的资源基线调准4.1 VPA 的三个组件与底层原理HPA 解决“加桌子”的问题VPA 解决“换大桌子”的问题。在实际业务里很多 Pod 不是不够用而是 requests 设得太小导致调度器低估资源需求节点超卖严重最终某个 Pod 被 OOM甚至整个节点被打挂。VPA 的价值在于它可以自动把资源 requests 调整到一个科学合理的值。VPA 包含三个核心组件Recommender负责采集 Pod 历史资源用量计算推荐值。它是 VPA 的“大脑”输出的是推荐 requests。Updater在 updateMode 为 Auto 时负责驱逐需要变更的 Pod让它以新的资源请求重建。Admission Controller拦截新建 Pod 的请求把推荐值写入到容器的 requests 中。推荐值的计算不简单它用的是分位数。比如 Recommender 会考察 Pod 在最近 8 天内的 CPU 使用CPU 用的是第 90 百分位而内存因为释放不及时会用第 95 百分位甚至峰值。所以 VPA 推荐的 requests 通常比手工拍脑袋的数值更贴近真实需求尤其是内存这种波动大的资源。4.2 VPA 的部署方式与 Auto 模式配置安装 VPA 最直接的方式是克隆官方仓库然后跑脚本git clone https://github.com/kubernetes/autoscaler cd autoscaler/vertical-pod-autoscaler ./hack/vpa-up.shvpa-up.sh会在集群里创建 VPA 相关的 Deployment 和 Webhook。不过每次升级或重启这些组件时Webhook 的证书就可能失效导致创建 Pod 时报Internal error occurred: failed calling webhook。我的建议是生产环境把证书托管给 cert-manager不要用脚本自动生成的临时证书。下面是一份 Auto 模式的 VPA 配置apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: web-vpa spec: targetRef: apiVersion: apps/v1 kind: Deployment name: web updatePolicy: updateMode: Auto resourcePolicy: containerPolicies: - containerName: * minAllowed: cpu: 100m memory: 128Mi maxAllowed: cpu: 4 memory: 4GiupdateMode: Auto表示推荐值算出来以后VPA 会主动修改 Deployment 的 Pod template 并触发重建。minAllowed和maxAllowed可以防止 VPA 给出极端值比如内存建议被算到 8Gi但你的容器最多也就需要 2Gi那就在上限里卡住。我个人建议生产环境第一周用updateMode: Initial只对新创建的 Pod 生效不做主动驱逐观察推荐值是否合理再切到 Auto。4.3 VPA 与 HPA 共存的正确姿势VPA 和 HPA 绝对不能盲目叠加这是官方文档也明确警告过的不要对同一个 Deployment 的 CPU/内存指标同时使用 HPA 和 VPA。原因很直接VPA 会修改 requests而 HPA 的 CPU 目标值是“利用率百分比”分母就是 requests。requests 从 500m 变成 1000m即使 CPU 绝对使用量没变利用率百分比也会差一倍两个系统会互相拉扯最终导致副本数和 requests 双双反复横跳。我在生产环境的做法是两种如果服务有明显的峰谷周期先只上 VPA运行一段时间让 requests 归位到合理水平然后再加 HPA如果必须同时用让 HPA 走自定义指标比如 QPS、P99 时延VPA 只负责 CPU/memory requests两者的数据源不同互不干扰。此外VPA Auto 模式会驱逐 Pod 来应用新 requests如果服务只有一个副本驱逐期间就是断服窗口。所以 VPA 上线前一定要保证服务的副本数至少为 2或者有滚动发布能力兜底。这个细节我在实际项目里栽过跟头一个内部工具只跑了一个副本VPA 一调整监控里直接出现一道断档。5. 节点级别缩放Cluster Autoscaler 的实战逻辑5.1 CA 的扩容与缩容判定逻辑HPA 和 VPA 都是“集群内”的伸缩它们能调动的资源上限受到集群节点数量的限制。如果所有节点都满了HPA 就算把 maxReplicas 调到 100新 Pod 也只能停留在 Pending 状态。这时候需要 Cluster Autoscaler简称 CA出马。CA 的扩容触发条件只有一个出现了无法调度的 Pod。典型链路是这样的HPA 决定扩容副本调度器发现现有节点资源不足新 Pod 进入 PendingCA 检测到 Pending Pod 后在云厂商的自动伸缩组里增加一台新节点节点 Ready 后调度器把 Pod 调度上去。整个链路是自动完成的不需要人工去云控制台创建机器。缩容则相反。CA 会定期检查每个节点的资源利用率如果某个节点上的所有 Pod 都能被重新调度到其他节点而且该节点的整体利用率低于某个阈值默认是 50%持续 10 分钟它就会考虑把这个节点回收掉。这里有两个保护机制值得注意一是刚扩容出来的节点有 10 分钟的“冷静期”不会被立刻缩掉二是 CA 在缩容前会模拟调度确保所有 Pod 都能找到新家否则会放弃缩容。5.2 部署 CA 时云厂商配置与 HPA 配合顺序CA 的部署不算复杂但因为要调用云厂商的 API所以需要提前准备好凭证。以常用的云环境为例需要把节点池的自动缩放范围和区域信息配置到 CA 的启动参数里./cluster-autoscaler \ --nodes1:10:default-node-group \ --scale-down-utilization-threshold0.5 \ --scale-down-unneeded-time10m \ --max-nodes-total100--nodes格式是min:max:节点组名称--scale-down-unneeded-time是缩容前的观察时间。CA 部署到 kube-system 命名空间后可以用kubectl logs观察它的决策日志日志里会明确写“Pod unschedulable、Scale up”这类信息排查起来很直观。生产和 HPA 配合的完整顺序我在多次大促活动的复盘里总结成下面几步HPA 先扩容 Pod直到 maxReplicas新 Pod 因节点资源不足进入 PendingCA 感知 Pending Pod自动扩容节点流量下降后 HPA 先缩 Pod节点利用率随之下降CA 再按缩容阈值回收多余节点。这个链条里最容易被忽略的是“等待时间”。流量高峰过后HPA 可能 5 分钟内就会把副本缩下来但 CA 的缩容观察期通常是 10 分钟起步所以你不会看到“流量刚降节点跟着秒删”的情况。反过来如果发现节点长期不缩优先检查是不是有 Pod 被 PDB 保护着或者节点的利用率一直没低于阈值。6. 高频问题排查速查表与实操心得6.1 指标拿不到、target 显示 Unknown 的排查链路自动缩放调试过程中我遇到最多的问题就是“HPA 配好了但不起作用”。下面这张表是我平时排查用的速查表按频率排序现象可能原因排查方法解决办法kubectl top nodes报 metrics not available 错误metrics-server 未部署或启动失败kubectl get pods -n kube-system查看 metrics-server 状态与日志加上--kubelet-insecure-tls检查证书与网络kubectl top pods有数据但 HPA 的 TARGETS 显示 UnknownDeployment 未设置 requestskubectl get pod -o yaml查看 output 里是否有 resources.requests给所有容器补上 CPU/memory requestsHPA 的 CPU 一直显示 0%/目标target 类型配成了 AverageValue但业务实际用量低于该绝对值kubectl get hpa -o yaml确认 metrics 类型根据业务特征选择 Utilization 还是 AverageValueHPA 报 500 错误聚合 API 未正确注册kubectl get apiservicegrep metrics如果 metrics-server 已经工作kubectl top也有数据但 HPA 仍然异常那就要检查 HPA 的 events。任何异常都会在kubectl describe hpa里留下事件记录这个命令比你翻日志高效得多。6.2 缩放震荡、副本数来回跳的解决手段缩放震荡的本质是反馈回路不稳定指标短期超过目标扩容新 Pod 还没 ready负载被打散后指标又快速回落缩容等新 Pod 一释放流量指标又开始上涨。如此循环最后监控图上看到的是一条锯齿线。我的经验是三层手段一起用应用层加快服务的启动速度配置合理的 readinessProbe让新 Pod 业务就绪后 HPA 才把它纳入决策范围。HPA 层把 scaleDown 的 stabilizationWindowSeconds 从 0 提到 300 秒以上让缩容变得“迟钝”一点。必要时调大容忍度。指标层如果用的是自定义指标比如通过 Prometheus Adapter 暴露的 QPS把指标的聚合窗口拉长到 1-2 分钟过滤掉短暂尖峰。还有一个很容易踩的坑Prometheus Adapter 默认的抓取间隔是 30 秒如果这 30 秒里 Deployment 发生了一次重新调度指标可能出现短暂空洞HPA 拿到空数据后有可能把它当成 0直接触发缩容。这种问题的特征就是“缩容过于积极明明刚扩容完就缩回去了”。6.3 整条链路的验证顺序与检查命令清单最后整理一份从 kubeadm 初始化到自动缩放全链路的验证顺序。我强烈建议不要跳步每一步都确认通过后再进入下一步kubectl get nodes # 节点是否 Ready kubectl get pods -A # 核心组件是否 Running kubectl top nodes # metrics-server 是否采集到节点指标 kubectl top pods -A # metrics-server 是否采集到 Pod 指标 kubectl get hpa -A # HPA 的 TARGETS 是否正常 kubectl describe hpa name # HPA 事件是否有异常 kubectl logs -n kube-system CA-pod # CA 的伸缩决策日志哪一步输出不符合预期就先处理哪一步不要跳过障碍去调 HPA 参数。自动缩放最怕的不是参数不好而是数据源不健康问题却被误判成缩放策略的问题。7. 一些真正值得带走的经验自动缩放这套体系在 v1.26.0 这种新版本上已经比较完善但它的成熟不代表配置简单。我最大的体会是不要试图一口气把所有组件都配上而是先把单一组件跑通、压测、观察再加下一个。先上 HPA看它能不能在压测下从 2 个副本拉到 8 个再把 CA 接进来看 Pending Pod 是否能触发新节点最后才是 VPA 这种需要长期观察的组件。个人在实际操作中还有个习惯把 maxReplicas 预留到预估峰值的 2 倍。这看起来是浪费实际上是在给 CA 扩容节点争取时间。比如你预计高峰需要 30 个副本就把 maxReplicas 设成 60这样当 CA 还在等待云厂商创建节点的几分钟里HPA 可以先用现有节点的余量多塞一些 Pod。等到新节点 Ready副本数再逐步收敛。这个小技巧帮我在几次真实的大促中保住了 SLO。如果你读完这篇文章按照链路一步步把环境验证下来自动缩放就不再是玄学。它就是一个有数据、有反馈、有稳定机制控制的系统工程。希望这些踩坑经验能让你少走弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑