
简介《容器云平台容量规划及管理优化.pdf》面向容器云平台架构师、运维工程师及PaaS平台设计人员聚焦互联网与证券行业资源使用时段集中、利用率偏低、容量规划困难等现实痛点系统梳理从用户体验、资源管理到需求预测的完整优化思路。资源包共1个PDF文件大小约708KB内容围绕租户与管理员的资源视图设计、多集群全局资源视角、Kubernetes与PaaS、云管、DevOps及服务治理的整合展开并深入讲解计算、持久化存储与网络资源的容量评估方法。文中结合证券行业上午9至10点资源高峰的典型场景剖析平台组件与Kubernetes组件资源占用、微服务拆分浪费、基础镜像选型等易被忽视的细节给出弹性扩容与避免过度浪费的平衡策略。目前已有65人学习适合希望提升资源利用率、降低运营成本并构建灵活分配机制的从业者参考。1. 容器云平台容量规划为什么你的集群总是“一半浪费、一半排队”很多团队上容器云平台的头一年都会经历同一个剧本业务方抱怨 Pod 调度不上去、扩容慢运维侧一看监控整体 CPU 利用率长期趴在 15% 上下内存更夸张一堆节点跑着个位数负载。于是开始加节点加完发现利用率更低了成本却翻了一倍。这不是玄学是容量规划没做。容器云平台的容量规划本质是回答三个问题现在有多少可分配资源、业务真实需要多少、未来什么时候会不够。它跟传统虚拟机容量规划最大的区别在于——容器的资源单位是 request/limit调度看 request实际跑起来看 usage三者之间的差值就是浪费和风险的来源。管理优化则是在规划落地之后持续把 request 和真实 usage 之间的偏差收窄让调度更准、扩缩容更及时、成本更可控。这套东西适合谁适合已经有一套 Kubernetes 或基于 K8s 的容器云平台、节点规模超过 20 台、开始被成本或调度问题困扰的团队。如果你还在单机跑 Docker Compose这篇可以先收藏等集群起来再看。下面按“先搞清楚资源账本 → 再动手采集和建模 → 然后落地优化 → 最后避坑”的顺序讲每一步都给可复现的命令和参数。2. 先把资源账本算清楚request、limit 与真实 usage 的三本账容量规划翻车十有八九是账本没对齐。容器云平台里同时存在三套资源数字很多人只盯着其中一套结果就是“监控看着很闲调度却说没资源”。2.1 三本账分别是什么谁在用它做决策第一本账是request声明在 Pod 的resources.requests里。调度器kube-scheduler只认这个值它决定 Pod 能不能被放到某个节点上。节点可分配资源减去所有已调度 Pod 的 request 总和就是调度视角的剩余量。第二本账是limit声明在resources.limits里。它决定容器运行时containerd 或 Docker给容器设多大的 cgroup 上限。CPU 超了会被 throttle内存超了会被 OOMKill。注意limit 不参与调度决策。第三本账是真实 usage来自 cAdvisor / metrics-server / Prometheus 采集到的实际消耗。它才是业务真正吃掉的资源。三本账的关系通常是request ≥ usage否则会被频繁驱逐或 throttlelimit ≥ request否则配置本身有问题。浪费就藏在request - usage这个差值里风险藏在usage逼近limit的那些时刻。提示很多团队只配 limit 不配 requestK8s 会把 request 默认等于 limit调度器按 limit 算账集群看起来“很满”实际 usage 很低这是最典型的隐性浪费。2.2 用 kubectl 和 PromQL 把三本账拉出来先看单个命名空间下所有 Pod 的 request/limit 配置情况# 列出所有 Pod 的 request/limit按命名空间过滤 kubectl get pods -n production -o custom-columns\ NAME:.metadata.name,\ CPU_REQ:.spec.containers[*].resources.requests.cpu,\ CPU_LIM:.spec.containers[*].resources.limits.cpu,\ MEM_REQ:.spec.containers[*].resources.requests.memory,\ MEM_LIM:.spec.containers[*].resources.limits.memory这条命令用custom-columns把关键字段直接打平方便你快速扫一遍有没有明显不合理的配置。参数说明-n production换成你的业务命名空间[*]表示取所有容器如果一个 Pod 有多个容器输出会用逗号分隔需要人工核对。再看节点维度的可分配资源和已分配 request# 查看每个节点的可分配资源与已分配 request kubectl describe nodes | grep -A 5 Allocated resources输出里Requests那一行就是调度视角的占用率。如果这个百分比长期高于 70% 但实际 CPU usage 低于 20%说明 request 虚高需要往下调。真实 usage 用 PromQL 拉假设你已经部署了 Prometheus# 按命名空间统计 CPU 真实使用率相对 request sum(rate(container_cpu_usage_seconds_total{container!POD}[5m])) by (namespace) / sum(kube_pod_container_resource_requests{resourcecpu}) by (namespace)这个查询算的是“真实 CPU 使用量 / request 总量”结果如果普遍低于 0.3就是明确的 request 过高信号。[5m]是采样窗口生产环境建议用[30m]或[1h]平滑掉毛刺。2.3 把三本账对齐成一张容量基线表光看单个指标没用要把节点、命名空间、业务线三个维度的三本账汇总成一张基线表。我一般会按下面这个结构整理每周更新一次维度可分配 CPU已分配 request真实 usageP95request/usage 比风险标记节点池 A64 核52 核14 核3.7request 虚高节点池 B128 核110 核96 核1.15接近饱和命名空间 order32 核28 核9 核3.1需下调 request命名空间 search32 核30 核29 核1.03高风险这张表的价值在于一眼能看出哪些池子是“假忙”哪些是“真忙”。节点池 B 和 search 命名空间就是需要优先处理的前者要扩容或迁移后者要优化 request 精度。节点池 A 和 order 命名空间则是“账面紧张、实际浪费”下调 request 就能释放调度空间不用加机器。真实 usage 一定要用 P95 或 P99不要用平均值。平均值会被大量低峰时段拉低掩盖掉业务高峰时的真实压力。我见过用平均值做规划、结果大促当天集体 OOM 的血泪案例。3. 容量建模从历史数据算出“该给多少”而不是“拍多少”账本对齐之后下一步是回答“request 到底该设多少”。拍脑袋设 request 是容量规划最大的敌人要么设高了浪费要么设低了被 throttle。这一章讲怎么用历史数据建模把 request 算出来。3.1 用 P95/P99 分位数定 request而不是用峰值最朴素也最可靠的方法取业务过去 714 天真实 usage 的 P95 分位数作为 CPU requestP99 作为内存 request。为什么 CPU 用 P95、内存用 P99因为 CPU 是可压缩资源短时超了只是被 throttle影响可控内存是不可压缩资源超了直接 OOMKill必须留更厚的安全垫。用 PromQL 算某个 Deployment 过去 14 天的 CPU P95# 过去 14 天某 Deployment 的 CPU P95单位核 quantile_over_time(0.95, sum(rate(container_cpu_usage_seconds_total{ namespaceproduction, pod~order-service-.*, container!POD }[5m])) by (pod)[14d:5m] )参数说明quantile_over_time的第一个参数是分位数0.95 就是 P95[14d:5m]表示在 14 天范围内以 5 分钟为步长采样pod~order-service-.*是正则匹配换成你的业务前缀。算出来的值向上取整到 0.1 核就是建议的 CPU request。内存同理把container_cpu_usage_seconds_total换成container_memory_working_set_bytes分位数改成 0.99注意单位是字节要除以1024^3换算成 GiB。3.2 用 VPA 的 recommender 做自动化建议手动算分位数适合少量核心服务服务多了就得靠工具。Vertical Pod AutoscalerVPA的 recommender 组件就是干这个的它会持续分析历史 usage给出 request/limit 的建议值。部署 VPA 后创建一个VerticalPodAutoscaler对象先跑updateMode: Off模式只出建议不改配置apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: order-service-vpa namespace: production spec: targetRef: apiVersion: apps/v1 kind: Deployment name: order-service updatePolicy: updateMode: Off # 只给建议不自动改updateMode: Off是关键生产环境千万别一上来就用AutoVPA 自动改 request 会触发 Pod 重建业务高峰期重建就是事故。跑一周后看建议kubectl describe vpa order-service-vpa -n production输出里的Recommendation段会给出lowerBound、target、upperBound三个值。target就是建议的 requestupperBound可以作为 limit 的参考。我一般取target作为新 request取upperBound的 1.2 倍作为 limit。3.3 把建模结果落成配置一次安全的 request 调整流程算出建议值之后不能直接改线上 Deployment。我一般走这个流程第一步在预发环境用建议值跑 3 天观察有没有 throttle 和 OOM。第二步生产环境灰度先改 10% 的副本用kubectl rollout控制节奏。第三步观察 24 小时重点看container_cpu_cfs_throttled_seconds_total和container_memory_working_set_bytes两个指标。第四步全量滚动更新。# 灰度调整先改 10% 副本的 request kubectl set resources deployment order-service \ --requestscpu500m,memory1Gi \ --limitscpu1000m,memory2Gi \ -n production # 观察 throttle 情况 kubectl top pods -n production -l apporder-servicekubectl set resources会触发滚动更新--requests和--limits同时给避免出现 request 大于 limit 的非法配置。改完之后用kubectl top看实时 usage配合 Prometheus 看 throttle 速率。如果 throttle 明显上升说明 request 调得太低回滚即可。注意调整 request 会触发 Pod 重建务必避开业务高峰并且确认 PDBPodDisruptionBudget配置正确否则可能一次性重建过多副本导致服务不可用。4. 管理优化落地扩缩容、超卖与成本的三方平衡容量规划解决“给多少”管理优化解决“怎么动态调”。静态 request 再准也扛不住业务流量的潮汐变化。这一章讲三个最实用的优化手段HPA 精细调参、节点超卖、以及成本归因。4.1 HPA 的 3 个必调参数别让扩缩容变成震荡Horizontal Pod AutoscalerHPA默认配置在生产环境几乎一定会震荡——扩了又缩、缩了又扩。核心要调三个参数第一个是--horizontal-pod-autoscaler-sync-period默认 15 秒建议保持默认或调到 30 秒太短会放大指标毛刺。第二个是--horizontal-pod-autoscaler-downscale-stabilization默认 5 分钟建议调到 1015 分钟。缩容比扩容更需要谨慎因为缩容后如果流量反弹重新扩容需要时间。第三个是 HPA 对象里的behavior字段用stabilizationWindowSeconds和policies精确控制扩缩速率apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: order-service-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: order-service minReplicas: 3 maxReplicas: 30 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 # 目标利用率不是 request 的百分比 behavior: scaleUp: stabilizationWindowSeconds: 30 policies: - type: Percent value: 50 periodSeconds: 60 # 每分钟最多扩 50% scaleDown: stabilizationWindowSeconds: 600 policies: - type: Pods value: 2 periodSeconds: 120 # 每两分钟最多缩 2 个averageUtilization: 60表示当平均 CPU 使用率达到 request 的 60% 时触发扩容。这个值不要设太高比如 80%否则扩容来不及也不要太低比如 30%否则长期多跑副本浪费成本。60% 是我在多数在线服务上验证过的平衡点。4.2 节点超卖用 request 和 limit 的差值换密度节点超卖的本质是调度器按 request 算账但容器实际能用到 limit。如果一批服务的 usage 远低于 request就可以把节点的 request 总量配置得比实际资源高提升部署密度。K8s 节点超卖通过 kubelet 的--system-reserved和--kube-reserved参数控制但更常用的是在节点池层面设置不同的超卖比。比如在线服务节点池超卖比 1.5离线任务节点池超卖比 3.0。具体做法是给节点打标签然后用 nodeSelector 或 affinity 把不同业务调度到不同池子# 给节点打超卖比标签 kubectl label node node-01 node-poolonline-oversell-1.5 kubectl label node node-02 node-poolbatch-oversell-3.0 # Deployment 里指定节点池 # spec.template.spec.nodeSelector: # node-pool: online-oversell-1.5超卖比不是越高越好。CPU 超卖 3 倍以上一旦多个服务同时冲高节点会严重 throttle内存超卖超过 1.5 倍OOM 风险急剧上升。我的经验值在线服务 CPU 超卖 1.52.0、内存 1.01.2离线任务 CPU 可以到 3.04.0内存 1.52.0。4.3 成本归因把账单摊到每个命名空间管理优化最终要回答“钱花在哪了”。用 Prometheus 的kube_pod_container_resource_requests乘以节点单价就能算出每个命名空间的月度成本# 按命名空间估算 CPU 月度成本假设单核月成本 30 元 sum(kube_pod_container_resource_requests{resourcecpu}) by (namespace) * 30这个数字是“按 request 计费”的口径反映的是调度占用成本。再算一个“按 usage 计费”的口径两者对比就能看出哪个团队申请了资源却没用起来。我一般每月出一张表把两个口径的差值发给各业务线推动他们主动下调 request。这比运维单方面改配置有效得多因为成本压力直接传导到了业务方。5. 避坑与排查容量规划里最容易翻车的 5 个场景这一章全是踩过的坑每条按“现象 → 原因 → 解决”写照着排查能省不少时间。现象一节点显示 request 已满但实际 CPU 利用率不到 10%。原因大量 Pod 只配了 limit 没配 requestK8s 默认把 request 等于 limit调度器按 limit 算账。解决用kubectl get pods -o json批量检查resources.requests为空的 Pod补上合理的 request。可以用 LimitRange 在命名空间级别设默认值防止新 Pod 再出现这种情况。现象二HPA 频繁扩缩副本数像心电图。原因averageUtilization设得太低比如 40%或者指标采集窗口太短业务正常波动就触发扩缩。解决把目标利用率调到 60%70%同时把scaleDown.stabilizationWindowSeconds调到 600 秒以上。如果还是震荡检查是不是多个 HPA 同时管一个 Deployment。现象三调整 request 后服务大面积重启可用性掉底。原因直接改了 Deployment 的 request触发全量滚动更新而 PDB 没配或配得太宽松导致同时重建过多副本。解决改之前先确认 PDB 的minAvailable至少是副本数的 70%然后用kubectl rollout pause暂停分批手动恢复。灰度期间盯紧kube_deployment_status_replicas_available。现象四内存 request 按 P99 设了还是偶尔 OOM。原因P99 只覆盖了 99% 的时间点剩下 1% 的极端峰值没覆盖到而内存是不可压缩的一次峰值就 OOM。解决内存 request 在 P99 基础上再乘 1.21.3 的安全系数或者直接取max_over_time的峰值。同时检查是不是有内存泄漏用container_memory_working_set_bytes的长期趋势判断。现象五节点超卖后夜间批量任务把在线服务挤爆。原因在线和离线混部在同一个节点池离线任务夜间冲高抢占了在线服务的 CPU。解决用 nodeSelector 把在线和离线分到不同节点池或者用 K8s 的PriorityClass给在线服务设高优先级配合preemptionPolicy让离线任务可被抢占。超卖比也要分开设离线池可以更激进。6. 进阶技巧用 descheduler 做持续再平衡让容量规划“活”起来容量规划不是一次性项目集群跑久了必然出现碎片——有的节点 request 快满了但 usage 很低有的节点 Pod 很少却因为亲和性调不走。这时候需要 Descheduler 做持续再平衡。Descheduler 是一个周期性运行的组件它根据策略驱逐不合理的 Pod让调度器重新调度。最常用的三个策略apiVersion: descheduler/v1alpha2 kind: DeschedulerPolicy strategies: LowNodeUtilization: enabled: true params: nodeResourceUtilizationThresholds: thresholds: cpu: 20 # 低于 20% 视为低利用 memory: 20 targetThresholds: cpu: 70 # 高于 70% 视为高利用 memory: 70 RemoveDuplicates: enabled: true PodLifeTime: enabled: true params: maxPodLifeTimeSeconds: 604800 # 7 天LowNodeUtilization会把高利用节点上的 Pod 迁到低利用节点RemoveDuplicates打散同一 Deployment 集中在单节点的副本PodLifeTime定期重建长生命周期 Pod 让配置生效。参数上thresholds和targetThresholds之间要留足缓冲否则会来回迁移。我一般设 20/70中间 50 个百分点的缓冲带足够稳定。Descheduler 默认是DryRun模式先跑一周看它会驱逐哪些 Pod确认无误再改成实际执行。执行频率建议 1015 分钟一次太频繁会干扰正常调度。验证再平衡效果看两个指标节点间 CPU request 的标准差越小越均衡以及kube_pod_status_scheduled的 P99 延迟反映调度压力。标准差下降 30% 以上说明再平衡生效了。最后说个我自己的习惯每次调整容量配置前先在一个隔离的命名空间用同样的配置跑一遍压测确认 request/limit 组合在峰值下不 throttle、不 OOM再上生产。这个习惯帮我挡掉了至少三次可能的事故。容量规划没有一劳永逸只有持续观测、小步调整。希望帮到你。本文还有配套的精品资源点击获取