集群容量规划(计算器)
「我们要 100 张卡的集群」到底需要几台机器、控制面多大、能跑多少 Pod —— 这一节把账算出来。
学完这节你能做到
- 从节点规格推出真正可分配的 CPU、内存与 Pod 数
- 按集群规模选出控制面规格与 etcd 配置
- 识别第一个撞上的限制:CPU、内存、Pod 密度还是 IP 段
"我们要建一套 100 张卡的训练集群" —— 这句话到能交给采购的配置单之间,有一串账要算。
这一节把账算清楚。核心结论会有点反直觉:决定集群能跑多少 Pod 的,往往不是 CPU 和内存。
第一刀:可分配不等于容量
一台 64 核 512 GiB 的机器,调度器看到的不是 64 核 512 GiB。中间被切掉三刀:
节点容量 Capacity
├─ system-reserved 留给 sshd、systemd 这些系统进程
├─ kube-reserved 留给 kubelet、容器运行时
├─ eviction-threshold 留给驱逐缓冲,默认 memory.available<100Mi
└─ Allocatable ← 调度器真正能分配的只有这一块
# 亲眼看一下这两个数的差距
kubectl get node <node> -o jsonpath='{.status.capacity}'
kubectl get node <node> -o jsonpath='{.status.allocatable}'
云厂商普遍采用一套分段公式来定预留量 —— 越大的机器预留比例越低,因为系统开销并不随规格线性增长:
| 内存区间 | 预留比例 |
|---|---|
| 前 4 GiB | 25% |
| 4–8 GiB | 20% |
| 8–16 GiB | 10% |
| 16–128 GiB | 6% |
| 128 GiB 以上 | 2% |
| CPU 区间 | 预留比例 |
|---|---|
| 第 1 核 | 6% |
| 第 2 核 | 1% |
| 第 3–4 核 | 0.5% |
| 4 核以上 | 0.25% |
按这套公式算一下:
- 4 GiB 的节点:预留 1 GiB,可分配约 2.9 GiB —— 四分之一多被系统吃掉了
- 512 GiB 的节点:预留约 15 GiB,可分配约 497 GiB —— 只切掉 3%
这就是为什么用一堆 2C4G 的小规格节点凑集群非常不划算:光是固定开销就吃掉四分之一。反过来,超大节点的资源效率高,但爆炸半径也大 —— 单机故障会带走集群相当比例的算力。中等规格通常是最优解。
第二刀:四条限制,最小的那条说话
算出单节点可分配资源之后,能跑多少 Pod 由四条限制里最小的那条决定:
| 限制 | 怎么算 | 什么时候撞上 |
|---|---|---|
| CPU 可分配 | 可分配 CPU ÷ 单 Pod CPU request | Pod request 填得偏大时 |
| 内存可分配 | 可分配内存 ÷ 单 Pod 内存 request | 内存核比不匹配业务时 |
kubelet maxPods | 直接就是这个值,默认 110 | 大量轻量 Pod 时 |
| 节点子网 IP 数 | 2^(32−掩码) − 2 | 网段规划偏紧时 |
这四条里,后两条是规划失误才会撞上的,而它们恰恰是最难改的:maxPods 要重启 kubelet,节点子网掩码改不了。
L0 的《集群规划》里算过一个例子:Pod CIDR /16 配每节点 /26,每节点只有 62 个可用 IP。
而 kubelet 的 maxPods 默认是 110。这时候真正的密度上限是 62,不是 110 —— 你按 110 做的容量规划,从第一天起就有 44% 的账是假的。
更麻烦的是这个问题在小规模测试时完全看不出来:20 台机器、每台跑 30 个 Pod,一切正常。等业务密度上来才发现节点上明明还剩一半资源,Pod 却调度不进去了。
第三刀:控制面要多大
控制面的压力不来自业务流量,而来自节点数与对象数 —— apiserver 要缓存所有对象,etcd 要承受所有写入。
| 计算节点数 | 控制面建议 | 关注点 |
|---|---|---|
| ≤ 10 | 3 × 4C8G | 3 节点是 HA 的最低要求 |
| ≤ 50 | 3 × 8C16G | etcd 独占 NVMe |
| ≤ 250 | 3 × 16C32G | 开始关注谁在疯狂 list |
| ≤ 500 | 5 × 16C64G | 必须配 APF 保护关键请求 |
| > 500 | 5 × 32C128G | 认真评估拆成多集群 |
用计算器把账走一遍
下面这个计算器把上面三刀都实现了。左边改参数,右边会直接告诉你第一个撞上的限制是哪条 —— 这比总数更有用。
三个预设值得都点一遍,它们各自暴露一类典型问题:
- 通用业务集群 —— 常规配置,看看可分配比例
- GPU 训练集群 —— 注意每卡摊到多少 CPU,这个数决定数据加载会不会成为瓶颈
- 高密度小 Pod —— 资源还剩一大半,但
maxPods已经封顶
- CPU 可分配量127 Pod
- 内存可分配量247 Pod
- ▸ kubelet maxPods 上限110 Pod
- 节点子网 IP 数254 Pod
资源还剩不少,但 kubelet 的 maxPods 已经封顶。可以调高 maxPods,但要同步确认节点子网 IP 数、conntrack 与 kube-proxy 规则数扛得住。
- 单节点 CPU 可分配
- 63.77 核(预留 0.23 核,99.6%)
- 单节点内存可分配
- 494.9 GiB(预留 17.0 GiB,96.7%)
- 集群可分配 CPU
- 1,275.4 核
- 集群可分配内存
- 9,898.0 GiB
- 节点子网可用 IP
- 254 个 / 节点
- Pod CIDR 可容纳节点
- 256 台
常规生产集群,etcd 建议独占 NVMe
GPU 集群的额外一笔账
GPU 集群有个容易漏的数:每张卡摊到多少 CPU 和内存。
训练任务里 GPU 负责算,但数据的读取、解码、增强都在 CPU 上。CPU 不够,GPU 就在等数据 —— 表现是 GPU 利用率上不去,而所有人第一反应都是去查网络和存储。
经验区间:
| 场景 | 每卡 CPU | 每卡内存 |
|---|---|---|
| LLM 训练(数据预处理轻) | 8–12 核 | 96–128 GiB |
| CV 训练(大量图像解码) | 12–16 核 | 128–256 GiB |
| 推理服务 | 4–8 核 | 32–64 GiB |
八卡 A100/H100 的机器,如果配的是 2×32 核 CPU(共 64 核),每卡只摊到 8 核 —— 而且要减掉系统预留,实际不到 7.9 核。跑 CV 训练时 GPU 会明显等数据。
同规格机器配到 2×64 核(共 128 核)通常只贵一点,但每卡 16 核,数据管道就不再是瓶颈。这笔账在采购阶段算,成本是零;在集群跑起来之后算,成本是换 CPU。
一台 32 核 128 GiB 的节点,典型 Pod 的 request 是 100m CPU / 256 MiB 内存,maxPods 保持默认 110,节点子网是 /24。第一个撞上的限制是哪个?
关于节点规格的选择,下面哪些说法是对的?
交付一份容量方案要写清的几件事
- 节点规格与数量,以及可分配资源(不是容量)
- 单节点 Pod 密度,以及它受限于哪一条 —— 这句话必须写出来
- Pod CIDR 与每节点掩码,以及这套网段的规模上限和余量
- 控制面规格,以及 etcd 盘的验收结论
- GPU 集群补充:每卡摊到的 CPU 与内存
- 扩容路径:加到多少台会撞上网段上限,撞上之后怎么办
延伸资料
- ·k8s-in-action
k8s/plan/README.md - ·Storpath 存储工程师成长路径 ↗