4. Pod与资源模型
在 Kubernetes 上跑 AI 任务,最先遇到的不是调度算法,而是“资源怎么声明”。Pod 是调度和资源分配的最小单位,而容器里的 resources 字段决定了调度器如何为它找节点、kubelet 如何限制它、以及节点资源紧张时谁先被驱逐。理解 requests/limits、QoS、扩展资源和 GPU 设备插件,是后续所有 AI 调度策略的基础。
requests 与 limits:调度依据与运行边界
每个容器可以声明两类资源:requests 是调度器用来筛选节点的“保底需求”,limits 是容器运行时施加的“上限”。调度器只看 requests,不看 limits;kubelet 和 cgroup 则按 limits 做限制。CPU 和内存的行为并不相同:
- CPU 是可压缩资源。超过 limit 时容器被限流(throttle),不会被杀死。requests 决定 CPU 权重(cpu.shares),影响竞争时的相对份额。
- 内存 是不可压缩资源。超过 limit 会触发 OOM Kill,容器被终止并按重启策略重启。
一个典型的 AI 推理容器声明如下(示例参数,非实测值):
resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "4"
memory: "16Gi"
这里 requests 与 limits 不等,属于 Burstable。若把两者写成相等,则成为 Guaranteed。若完全不写,则成为 BestEffort。这三种组合正是 QoS 分类的来源。
QoS 类别:资源紧张时的优先级
QoS 不是手动指定的字段,而是由 requests/limits 的写法自动推导出来的,它决定了节点内存压力下的驱逐顺序:
| QoS | 判定条件 | 驱逐优先级 |
|---|---|---|
| Guaranteed | 所有容器都设置了 CPU 和内存的 requests 与 limits,且对应值相等 | 最低(最后被驱逐) |
| Burstable | 至少一个容器设置了 requests 或 limits,但不满足 Guaranteed | 中等 |
| BestEffort | 所有容器都没有设置任何 requests 和 limits | 最高(最先被驱逐) |
对 AI 工作负载而言,训练任务通常希望 Guaranteed 或高配 Burstable,避免被无关负载挤掉;而短时的数据预处理、日志采集等可以接受 BestEffort。需要注意的是,QoS 只影响驱逐顺序,不改变调度器对 requests 的判断。
扩展资源:把 GPU 等设备纳入调度
CPU 和内存是 Kubernetes 的内置可计量资源,而 GPU、FPGA、高速网卡等属于扩展资源(Extended Resource)。扩展资源有两条硬性规则:
- 只能声明
requests,不能声明limits;若同时写 limits,必须与 requests 相等。 - 资源值必须是整数,不支持小数,因为设备不可分割。
扩展资源的名称形如 vendor-domain/resource,例如 nvidia.com/gpu。它不能由用户随意声明,必须由设备插件(Device Plugin)向 kubelet 注册后,节点才会暴露该资源的可分配数量。调度器据此把 Pod 绑定到有足够 GPU 的节点上。
GPU 设备插件的工作方式
设备插件以 DaemonSet 形式运行在每个 GPU 节点上,通过 kubelet 的 Device Plugin API 注册资源。以 NVIDIA 为例,插件启动后会:
- 发现节点上的 GPU 数量与型号,向 kubelet 注册
nvidia.com/gpu资源及健康状态。 - kubelet 将该资源纳入 Node 的 Allocatable,并上报给 API Server。
- 当 Pod 请求 GPU 时,调度器按 Allocatable 匹配节点;kubelet 在创建容器前调用插件的
Allocate,插件返回设备路径(如/dev/nvidia0)和环境变量,注入容器。
因此,如果节点没有安装设备插件,即使物理上有 GPU,nvidia.com/gpu 也不会出现在可分配资源里,Pod 会一直 Pending。排查 GPU 调度失败时,第一步就是确认节点是否暴露了该扩展资源。
AI 工作负载的资源声明方式
不同 AI 负载对资源的诉求差异很大,声明策略也应不同:
- 训练任务:通常需要多卡甚至多机。单容器声明
nvidia.com/gpu: N,并配合 Guaranteed 或高配 Burstable,避免被抢占。CPU/内存 requests 要覆盖数据加载与预处理开销,否则 GPU 会因数据供给不足而空转。 - 在线推理:延迟敏感,CPU 与内存建议 requests=limits 以获得稳定份额;GPU 按并发量声明,可结合 HPA 按利用率扩缩。
- 批处理/离线推理:可接受 BestEffort 或低配 Burstable,利用空闲资源,但需容忍被驱逐并支持重试。
一个多卡训练 Pod 的声明示例(示例参数):
resources:
requests:
cpu: "8"
memory: "64Gi"
nvidia.com/gpu: "4"
limits:
cpu: "8"
memory: "64Gi"
nvidia.com/gpu: "4"
由于 GPU 的 requests 与 limits 相等,且 CPU、内存也相等,该 Pod 为 Guaranteed。注意扩展资源不能只写 limits 不写 requests,否则 API 校验会报错。
0.5。总结来看,requests 决定“调度到哪”,limits 决定“能跑多大”,QoS 决定“紧张时谁先走”,扩展资源与设备插件决定“GPU 能不能被看见和分配”。把这四层关系理清,AI 工作负载的资源声明才不会成为后续调度优化的隐患。