Kubernetes配额调优:让集群成本降四成
Kubernetes 配额调优:让集群成本降四成
很多团队把降本理解为换更便宜的节点,但 Kubernetes 成本失控通常来自 request 虚高。调度器按 request 预留资源,节点利用率很低却无法继续装箱,最终为闲置容量付费。本文给出一套可执行的配额调优流程:先把成本算清楚,再用监控和 VPA 找到真实需求,随后调整 request/limit、命名空间 ResourceQuota、HPA 与节点池,最后用策略门禁和灰度发布把成果固化。目标是在不牺牲稳定性的前提下,让集群成本下降约四成。40% 不是拍脑袋的承诺,而是当 CPU/内存 request 长期高于 P95 用量 2 倍以上时常见的可达区间。截至 2026 年 10 月,这套方法适用于主流托管 Kubernetes、自建集群以及常见 Serverless 容器平台。
前置条件
开始前请确认:
- 具备集群管理员或命名空间管理员权限。
- Prometheus 与 kube-state-metrics 已采集至少 14 天指标。
- 已部署 VPA recommender,并先使用仅推荐模式。
- 有 OpenCost、Kubecost 或云账单作为成本基线。
- 有变更窗口、告警群和回滚预案。
步骤 1:建立成本基线与标签规范
先算钱,再改配置。没有基线就无法证明降本,也无法判断哪个命名空间值得优先动刀。为命名空间和工作负载补齐 team、app、env、cost-center 标签,后续按标签聚合成本。
bash kubectl label ns prod team=payment env=prod cost-center=cc-102 --overwrite kubectl label deploy payment-api -n prod app=payment-api team=payment --overwrite
用 PromQL 先看每个命名空间的 CPU request 与真实用量:
promql sum(kube_pod_container_resource_requests{resource="cpu",namespace="prod"}) by (namespace) sum(rate(container_cpu_usage_seconds_total{namespace="prod",container!=""}[5m])) by (namespace)
内存同样处理,把 request、P95 working set、节点价格和月成本记入一张基线表。建议至少保留一周,后续每一步都和这张表对比。
步骤 2:量化 request 与真实用量的偏差
调优的核心不是“把值调小”,而是让 request 接近真实需求。重点看四类指标:CPU request 总量、CPU P95 用量、内存 request、内存 P95 working set;同时观察 CPU 限流次数与 OOMKilled。若某命名空间 request/usage 长期大于 2.5,或内存 request 高于 P95 的 1.8 倍,就应进入候选名单。
promql quantile_over_time(0.95, sum(rate(container_cpu_usage_seconds_total{namespace="prod",container!=""}[5m])) by (pod)[14d:5m] )
promql sum(container_memory_working_set_bytes{namespace="prod",container!=""}) by (pod)
把候选工作负载按“在线核心、普通在线、批处理”分类。核心在线看 P99 和延迟,普通在线看 P95,批处理看任务完成时间。不要用一天的数据下结论,至少覆盖一次业务高峰。
步骤 3:用 VPA 仅推荐模式生成建议
VPA 的价值在于持续给出 lowerBound、target、upperBound。生产环境先设置 updateMode 为 Off,只读建议,不自动改 Pod。
yaml apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: payment-api-vpa namespace: prod spec: targetRef: apiVersion: apps/v1 kind: Deployment name: payment-api updatePolicy: updateMode: 'Off'
bash kubectl apply -f payment-api-vpa.yaml kubectl get vpa -n prod payment-api-vpa -o yaml
target 是起点,不是圣旨。把 VPA 建议与监控 P95 交叉验证:如果 VPA 建议明显低于高峰用量,以监控为准;如果建议远高于实际,说明历史数据里有短时尖峰或采集异常,需要拉长窗口复核。
步骤 4:制定分层 request/limit 策略
不要所有服务一套参数。建议分三层:
- 核心在线:request 取 P95 的 1.2 倍,内存 limit 取 request 的 1.3 倍,CPU limit 可放宽到 2 倍,优先保证延迟。
- 普通在线:request 取 P95 的 1.1 倍,CPU limit 取 1.5 倍,内存 limit 取 1.25 倍。
- 批处理:request 压低,limit 放宽,配合 Job 与 Spot 节点,允许被驱逐。
内存 limit 不要压得太狠,否则 OOMKilled 会换来更多重启成本;CPU limit 过低会造成限流,延迟敏感服务可评估不设 CPU limit,但仍要通过 ResourceQuota 控制总量。LimitRange 只做兜底,不要把它当成调优结果。
yaml apiVersion: v1 kind: LimitRange metadata: name: default-limits namespace: prod spec: limits:
- type: Container defaultRequest: cpu: '100m' memory: '128Mi' default: cpu: '500m' memory: '512Mi' max: cpu: '4' memory: '8Gi'
步骤 5:用 ResourceQuota 给命名空间设预算
ResourceQuota 的作用是防止某个团队无限占用集群,同时让成本可见。先计算命名空间内所有工作负载的 request 总和,再乘 1.2 左右缓冲,得到 requests.cpu 与 requests.memory;limits 按实际策略设置。
yaml apiVersion: v1 kind: ResourceQuota metadata: name: prod-budget namespace: prod spec: hard: requests.cpu: '40' requests.memory: '80Gi' limits.cpu: '80' limits.memory: '120Gi' pods: '300'
bash kubectl apply -f prod-budget.yaml kubectl describe quota prod-budget -n prod
配额不是越小越好。配额过紧会让发布失败、HPA 无法扩容,反而推高人工成本。建议每月根据实际使用和业务增长调整一次,并把配额写进团队预算。
步骤 6:接入 HPA 与节点自动伸缩
request 调准后,HPA 才有意义。CPU 目标建议设在 60% 到 70%,给突发流量留余量;内存通常不作为唯一扩容指标,避免 GC 波动导致频繁扩缩。
yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: payment-api namespace: prod spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: payment-api minReplicas: 3 maxReplicas: 30 metrics:
- type: Resource resource: name: cpu target: type: Utilization averageUtilization: 65
节点侧开启自动伸缩与合并。以 Karpenter 为例,开启 underutilized 合并,让低利用率节点被回收;使用 Cluster Autoscaler 的团队则应关注 scale-down-delay 与节点池上限。无状态服务优先跑 Spot,核心服务保留按量或预留节点。
yaml apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: general spec: disruption: consolidationPolicy: WhenEmptyOrUnderutilized consolidateAfter: 5m
步骤 7:优化调度与装箱
节点碎片会吃掉降本收益。用 topologySpreadConstraints 替代过硬的 podAntiAffinity,让 Pod 在可用区内尽量均匀但不阻塞调度;批处理设置低优先级,在线服务设置高优先级,避免批任务挤占核心容量。节点池不要过度细分,小而多的节点池会增加碎片和系统组件开销。
yaml apiVersion: apps/v1 kind: Deployment metadata: name: payment-api namespace: prod spec: template: spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: payment-api
步骤 8:用策略即代码守住配额
调优成果很容易被下一次发布破坏。用 Kyverno 或 OPA Gatekeeper 要求 Pod 必须设置 request/limit,并限制单容器最大 request。先在审计模式运行一周,再切换到 Enforce。
yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-requests-limits spec: validationFailureAction: Enforce rules:
- name: check-resources
match:
any:
- resources:
kinds:
- Pod validate: message: '必须设置 CPU 与内存 request/limit' pattern: spec: containers:
- resources: requests: cpu: '?' memory: '?' limits: cpu: '?' memory: '?'
- resources:
kinds:
CI 中加入 kubectl diff 与 conftest 检查,超过 4 CPU 的 request 必须走审批。这样配额调优从一次性项目变成持续治理。
步骤 9:灰度上线与回滚
按开发、预发、生产 10% 金丝雀、全量的顺序推进。每次只改一个命名空间或一组服务,观察至少 30 分钟,重点看 OOMKilled、CPU 限流、P99 延迟、错误率、Pending Pod 和 HPA 行为。
bash kubectl rollout status deploy/payment-api -n prod kubectl rollout undo deploy/payment-api -n prod
promql sum(rate(container_cpu_cfs_throttled_periods_total{namespace="prod",container!=""}[5m])) by (pod)
出现 OOM、P99 上升超过 20%、错误率上升超过 0.5 个百分点,立即回滚。回滚不是失败,而是把风险控制在可接受范围内。
步骤 10:验证降本幅度并固化
用同一张基线表对比调优前后:命名空间 request 总量、实际 P95、节点数量、月成本与可用性。节省率按(旧月成本减新月成本)除以旧月成本计算。若 request 下降 45%,节点池又完成合并,40% 的整体成本下降通常可以实现;如果只改 YAML 不做节点回收,收益会打折。
promql sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace)
把成本看板放到团队周会:每个命名空间的 request 利用率、配额余量、OOM 次数、限流次数和月成本趋势。每月复核一次配额,每季度做一次 VPA 建议与真实用量的对账。保留 20% 左右缓冲,核心服务不要为了降本牺牲冗余。
小结
配额调优不是把数字改小,而是让 request 反映真实需求,让配额约束团队预算,让弹性和调度回收闲置容量。按本文十个步骤推进:先建基线,再找偏差,用 VPA 给建议,分层设 request/limit,用 ResourceQuota 控预算,用 HPA 和节点合并降闲置,用策略门禁防回潮,最后灰度验证。只要集群存在明显超配,2026 年用这套方法实现约四成成本下降是可以复现的。