gpu-manager 架构:Device Plugin、vCUDA 与迁移边界
复盘 tkestack/gpu-manager 的 Device Plugin、vCUDA 资源模型、库注入和拓扑分配,并说明旧 CUDA 兼容边界与现代迁移方案。
状态说明(2026-09-03):
tkestack/gpu-manager公开仓库的最新 Release 仍是 2020 年 5 月发布的v1.1.0;配套vcuda-controller文档声明支持 CUDA 11.5.1 及以前版本。这里把它当作 GPU 虚拟化架构案例,不建议直接用于 2026 年新集群选型。
gpu-manager 的价值不在“还能不能原样部署”,而在它把 Kubernetes GPU 共享拆成了几个至今仍有效的问题:调度器如何表达分数资源,kubelet 如何向容器交付虚拟设备,运行时如何限制显存和计算,以及节点重启后如何恢复分配状态。
先看它解决的三个问题
- 资源表达:把整张 GPU 拆成
vcuda-core与vcuda-memory两种可调度扩展资源。 - 容器交付:通过 Device Plugin 的
Allocate响应向容器注入设备、目录、环境变量和控制库。 - 运行时约束:通过 vCUDA 库拦截 CUDA 调用,执行配额检查、设备视图重写和使用量采集。
这三层必须同时成立。只有调度记账,没有运行时约束,Pod 仍可能超额使用;只有拦截库,没有调度器账本,平台又不知道该把任务放到哪张卡。
组件边界
Pod / Extended Resources
|
v
gpu-admission / scheduler integration
|
v
gpu-manager DaemonSet
- GPU discovery
- topology and allocation state
- Device Plugin registration
- Allocate response
|
v
vCUDA controller library in container
|
v
NVIDIA driver and physical GPU
- gpu-manager 运行在 GPU 节点,发现设备、维护分配状态并向 kubelet 注册 Device Plugin。
- gpu-admission / 调度集成 处理分数资源的节点选择和拓扑约束。
- vcuda-controller 提供容器内 CUDA 拦截库,让调度结果在运行时可执行。
- checkpoint 与指标服务 用于恢复节点分配状态、暴露设备和任务使用信息。
这是一个强耦合系统:gpu-manager、vCUDA 库、NVIDIA 驱动、CUDA Runtime 与容器运行时必须形成经过验证的兼容矩阵。
启动链路:从节点发现到 Device Plugin 注册
启动过程可以压缩成七步:
- 读取节点配置、设备白名单、资源粒度与调度策略。
- 通过 NVML/驱动接口发现 GPU、显存与拓扑关系。
- 初始化本地分配状态,必要时加载 checkpoint。
- 准备容器需要挂载的驱动库与 vCUDA 控制库。
- 启动
vcuda-core、vcuda-memory等 Device Plugin 服务。 - 向 kubelet 注册扩展资源,并通过
ListAndWatch持续报告健康状态。 - 收到
Allocate请求后,返回设备节点、Mount、环境变量和运行时配置。
Kubernetes Device Plugin 只定义资源注册与分配接口,不理解“20% GPU”具体如何执行。gpu-manager 必须在插件之外维护物理 GPU、虚拟份额与容器之间的映射。
vCUDA 资源模型
项目定义两个主要扩展资源:
tencent.com/vcuda-core:计算份额;100表示一张完整 GPU,20表示约 20% 计算份额。tencent.com/vcuda-memory:显存份额;一个单位表示 256 MiB,因此32表示 8 GiB。
vcuda-core 小于 100 时表示单卡分数份额,大于等于 100 时通常要求使用 100 的整数倍。它不是 Kubernetes 原生 GPU 百分比,语义完全由 gpu-manager 与 vCUDA 运行时共同实现。
示例只展示资源契约,不代表当前集群可以直接运行:
apiVersion: v1
kind: Pod
metadata:
name: vcuda-demo
annotations:
tencent.com/vcuda-core-limit: "50"
spec:
restartPolicy: Never
containers:
- name: workload
image: <your-registry>/cuda-workload:<pinned-version>
resources:
requests:
tencent.com/vcuda-core: "20"
tencent.com/vcuda-memory: "32"
limits:
tencent.com/vcuda-core: "20"
tencent.com/vcuda-memory: "32"
这里申请约 20% 计算份额和 8 GiB 显存,vcuda-core-limit 把运行上限设为 50%。实际字段行为以你锁定的 gpu-manager 版本为准。
Allocate 为什么是关键接口
Device Plugin 的 Allocate 响应可以向容器交付:
- 设备节点
- HostPath Mount
- 环境变量
- CDI Device
- 其他运行时需要的信息
gpu-manager 利用这一步把虚拟设备状态和控制库放进容器。容器启动后,动态链接器优先加载 vCUDA 库,再由它转发或限制底层 CUDA 调用。
这比“只上报多个虚拟设备 ID”复杂,但也暴露出最重要的兼容风险:只要库路径、符号版本、Driver API 覆盖或容器运行时行为变化,Pod 可能成功调度却在 CUDA 初始化阶段失败。
CUDA 拦截能控制什么,不能控制什么
vCUDA 这类方案通常在用户态处理:
- 设备枚举与可见性
cudaMalloc/cuMemAlloc等显存分配- Context、Stream 与 Kernel Launch 相关调用
- 使用量采集和配额判断
它的边界同样明确:
- 未覆盖的新 CUDA API 可能绕过限制。
- 静态链接、显式
dlopen、自定义 Driver API 路径会增加兼容风险。 - 用户态拦截不是 MIG 级硬件隔离,PCIe、显存带宽、缓存和故障域仍可能共享。
- CUDA、驱动和控制库的 ABI 变化必须逐版本回归。
因此,“Pod 能看到 GPU”不是验收结束。必须证明分配、超额失败、并发干扰、故障恢复和指标链路都符合预期。
拓扑感知为什么重要
多卡任务不能只数 GPU 数量。GPU 与 CPU NUMA、PCIe Switch、NVLink/NVSwitch 的距离会影响 Host-to-Device、Peer-to-Peer 和集合通信性能。
调度和分配至少要回答:
- 多卡任务是否落在同一高速互联域。
- CPU 与内存是否靠近目标 GPU 的 NUMA Node。
- 分数任务是否把同一张卡切得过碎,阻塞后续整卡任务。
- 节点重启后恢复的虚拟份额是否仍指向同一物理设备。
这些原则仍适用于今天的 GPU 调度器,但具体拓扑 API 和设备标识不能照搬旧项目代码。
2026 年新集群该看什么
| 方案 | 主要能力 | 隔离边界 | 适用场景 |
|---|---|---|---|
| NVIDIA GPU Operator Time-Slicing | 把一张卡作为多个共享副本暴露 | 无显存硬边界,故障域共享 | 可信任务、低成本并发 |
| NVIDIA MPS | 多进程并发执行、部分资源限制能力 | 依赖 GPU 架构和 MPS 配置 | 同机推理或 HPC 并发 |
| NVIDIA MIG | 硬件分区与独立资源实例 | 最强,但规格固定且只支持部分 GPU | 多租户、强故障隔离 |
| HAMi | Device Plugin + CUDA API 层限制 | 强于应用自限,弱于硬件分区 | 异构 GPU 共享平台 |
| KAI-Scheduler GPU Sharing | Reservation Pod 与调度记账 | 默认不强制显存边界 | 调度侧分数 GPU 与队列治理 |
进一步选型可参考站内文章:
维护旧 gpu-manager 集群的最低检查线
- 锁定 Linux Kernel、NVIDIA Driver、CUDA、gpu-manager 与 vcuda-controller 版本。
- 保留金丝雀节点,驱动或容器运行时升级先跑兼容回归。
- 验证 kubelet 重启、gpu-manager 重启和节点重启后的注册与 checkpoint 恢复。
- 检查
vcuda-core、vcuda-memory的 Capacity、Allocatable 与 Pod 分配结果。 - 在容器内确认实际加载的控制库路径和符号版本。
- 跑显存上限、计算配额、并发干扰、CUDA 错误传播和 OOM 测试。
- 采集物理 GPU、虚拟份额和 Pod 三个层级的指标,并能对应到同一时间线。
kubectl get node <gpu-node> \
-o jsonpath='{.status.capacity.tencent\.com/vcuda-core}{"\t"}{.status.capacity.tencent\.com/vcuda-memory}{"\n"}'
kubectl describe pod -n <ns> <pod>
kubectl logs -n <gpu-manager-namespace> <gpu-manager-pod>
不要把旧 README 中的宽权限示例原样搬进生产。按当前 Kubernetes 版本收紧 ServiceAccount、HostPath、HostPID 和设备访问权限。
迁移建议
- 盘点所有 workload 的
vcuda-core、vcuda-memory、显存峰值和计算利用率。 - 把旧资源单位转换为目标方案的资源模型,不能只替换资源名。
- 新旧节点池并行,先迁移可重试、低优先级任务。
- 对同一模型比较吞吐、P95/P99 延迟、显存峰值、失败率和节点密度。
- 为 CUDA 初始化失败、性能回退和配额失效准备快速回滚。
- 最后迁移在线核心服务,并删除旧 Admission、Device Plugin 和控制库注入链路。
gpu-manager 仍值得读,因为它完整展示了“调度账本 + Device Plugin 交付 + 用户态约束”的工程组合。它不再适合作为新部署默认答案,真正可复用的是组件边界、兼容矩阵和验证方法。