4. GPU资源管理与调度

在Kubernetes集群中,GPU是一种“扩展资源”,它不像CPU和内存那样由kubelet原生管理,而是通过设备插件(Device Plugin)机制接入。理解GPU调度的关键,是把它拆成一条从“物理卡被识别”到“容器拿到可用算力”的链路:nvidia-device-plugin负责注册与分配,MIG负责物理切分,时间片负责共享复用,拓扑感知与NUMA绑定负责性能一致性,多卡任务分配则决定一次申请多张卡时如何落到同一台机器上。

一、nvidia-device-plugin:GPU进入调度体系的入口

nvidia-device-plugin以DaemonSet形式运行在每个GPU节点上,它通过NVIDIA驱动和NVML发现节点上的GPU,然后向kubelet的Device Plugin Manager注册资源名,例如nvidia.com/gpu。注册成功后,节点可分配资源中会出现该资源数量,Pod只要在resources.limits中声明nvidia.com/gpu: 1,调度器就会把它当作一种不可压缩资源参与调度。

设备插件的工作可以概括为四步:发现设备、注册资源、上报健康状态、响应分配请求。分配时,kubelet把选中的设备ID通过Allocate接口返回给容器运行时,运行时据此把对应的/dev/nvidia*设备节点和驱动库挂载进容器。需要注意,GPU数量必须写在limits里,requests可以省略;如果只写requests不写limits,调度器不会把它当作GPU请求处理。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-demo
spec:
  containers:
  - name: cuda
    image: nvcr.io/nvidia/cuda:12.4.0-base
    resources:
      limits:
        nvidia.com/gpu: 1

二、MIG:把一张物理卡切成多份隔离实例

MIG(Multi-Instance GPU)是A100、H100等卡支持的硬件级切分能力。它把一张GPU的SM、显存、L2缓存和内存带宽切成若干独立实例,每个实例拥有自己的计算单元和显存,彼此之间具有故障隔离和性能隔离。MIG适合“多个小任务共享一张卡,但要求互不干扰”的场景,例如推理服务、小规模微调、开发测试环境。

MIG的配置分两步:先在节点上用nvidia-smi mig创建GI(GPU Instance)和CI(Compute Instance),再让device-plugin以MIG模式暴露资源。此时资源名会变成类似nvidia.com/mig-1g.5gb的形式,调度器按实例规格而不是整卡来分配。MIG的代价是切分粒度固定、实例数量有限,且不是所有GPU型号都支持;一旦切分,整卡就不能再作为完整GPU分配给需要全卡的任务。

三、时间片:让多个容器共享同一张卡

当任务对算力需求不高、但数量较多时,可以用时间片(time-slicing)让多个容器共享同一张物理GPU。它的原理是CUDA上下文在时间维度上轮流占用GPU,每个容器看到的是同一张卡,但实际执行是交替的。时间片不提供显存隔离,一个容器显存溢出可能影响同卡其他容器,因此更适合推理、开发、批处理等对隔离要求不高的场景。

配置方式是在device-plugin的ConfigMap中声明共享策略,例如把nvidia.com/gpu的replicas设为4,表示一张卡可被4个Pod共享。此时节点上报的GPU数量会变成物理卡数乘以副本数,调度器按逻辑副本分配。时间片提升的是并发密度,不是单任务性能;如果多个任务同时打满算力,每个任务的实际吞吐会下降。

四、拓扑感知调度与NUMA绑定

多卡训练中,GPU之间的通信带宽差异很大。同一台服务器内,GPU可能通过NVLink、PCIe Switch或PCIe Root Complex连接,跨NUMA节点的GPU通信延迟明显高于同NUMA节点。拓扑感知调度的目标,是让一次申请的多张GPU尽量落在通信代价最低的拓扑域内,同时让GPU与网卡、CPU、内存保持在同一NUMA节点附近。

在Kubernetes中,这通常由拓扑管理器(Topology Manager)配合CPU Manager、Memory Manager和设备插件共同完成。拓扑管理器策略可设为none、best-effort、restricted或single-numa-node。对于延迟敏感的多卡训练,常用single-numa-node,要求Pod的所有资源都来自同一个NUMA节点;如果无法满足,Pod会进入TopologyAffinityError,调度失败而不是降级运行。

GPU资源管理与调度链路 GPU 节点(Node) NUMA Node 0 GPU 0 MIG 1g.5gb ×2 GPU 1 时间片 ×4 CPU 核心组 + 本地内存 NUMA 绑定:CPU / 内存 / GPU 同域 NVLink / PCIe Switch GPU 0 ↔ GPU 1 高带宽互联 RDMA 网卡(同 NUMA 域) NUMA Node 1 GPU 2 整卡独占 GPU 3 整卡独占 CPU 核心组 + 本地内存 NUMA 绑定:CPU / 内存 / GPU 同域 NVLink / PCIe Switch GPU 2 ↔ GPU 3 高带宽互联 RDMA 网卡(同 NUMA 域) 跨 NUMA nvidia-device-plugin Topology Manager kubelet / 调度器

五、多卡任务分配:一次申请多张卡时怎么落

多卡任务在Kubernetes中通过nvidia.com/gpu: N声明。调度器只保证这N张卡在同一节点上,不保证它们之间的拓扑关系。要控制拓扑,需要结合节点标签、污点容忍、拓扑管理器策略,或者使用支持拓扑感知的调度器插件(如Volcano、Koordinator)。

一个常见的做法是给节点打上拓扑标签,例如topology.nvidia.com/nvlink-group=0,再通过nodeAffinity把需要NVLink通信的任务约束到同一组。对于NCCL训练任务,还可以通过环境变量NCCL_TOPO_FILE或NCCL_IB_HCA指定通信路径,让NCCL优先使用NVLink和同NUMA网卡。

判断多卡任务是否真正“拓扑友好”,可以看三个信号:Pod是否被调度到同一NUMA节点、NCCL日志中是否出现NVLink通道、以及nvidia-smi topo -m中GPU之间的连接类型是否为NVLink。如果出现跨NUMA的SYS连接,通信带宽会明显下降。

六、选型与组合建议

场景推荐机制关键约束
小推理、多租户共享时间片无显存隔离,需限制显存
多任务强隔离MIG需A100/H100等支持,切分粒度固定
单卡训练/推理整卡独占资源名nvidia.com/gpu
多卡训练拓扑感知 + NUMA绑定single-numa-node策略,NVLink优先

实际落地时,建议先明确任务对隔离、显存、通信带宽的要求,再决定用MIG、时间片还是整卡。MIG和时间片可以共存,但同一张卡不能既切MIG又做时间片。拓扑感知和NUMA绑定属于“性能优化项”,开启后可能降低调度成功率,需要在资源利用率和性能之间做权衡。最后,所有GPU资源都应通过limits声明,并配合节点标签、污点和亲和性,避免普通任务误占GPU节点。