1. 背景:原始的 envvar 模式
在前一篇文章里面提到最早的envvar实现里,NVIDIA Device Plugin 分配 GPU 的方式是:
- Pod 申请 GPU → kubelet 调用 Device Plugin 的
Allocate()
方法 - Device Plugin 返回一个环境变量:
ini
NVIDIA_VISIBLE_DEVICES=<GPU-UUID 或 index>
- 容器 runtime(nvidia-container-runtime)启动时读取这个环境变量,决定注入哪些
/dev/nvidia*
设备
好处:
- 简单,runtime 无需改动 CRI API
- 跨 Docker / containerd / CRI-O / Podman 都能用
缺点:
- 安全漏洞 :任何 Pod 只要能设置
NVIDIA_VISIBLE_DEVICES=all
,就能访问所有 GPU,绕过 Device Plugin 的分配逻辑 - 默认镜像问题 :很多 NVIDIA 官方镜像(
nvidia/cuda:*
)默认就带NVIDIA_VISIBLE_DEVICES=all
,直接全卡开放 - 不受 Kubernetes 资源模型约束:K8s 无法阻止用户在 PodSpec 里手动设置这个 envvar
2. volume-mounts 模式的设计目标
目标:
- 防止非特权容器绕过 Device Plugin
- 不再用环境变量传递 GPU 列表
- 改成通过容器内的一个特殊目录
/var/run/nvidia-container-devices
传递 - 这个目录由 kubelet 挂载,普通用户不能自己挂载
- 保持兼容性
- runtime 仍然可以从这个目录读取 GPU 列表
- 特权容器(如监控、Device Plugin 自身)仍然可以访问全部 GPU
- 简化实现
- 不引入新的 CRI API
- 只是把"传递 GPU 列表"的方式从 envvar → volume mount
4. volume-mounts 的工作方式
-
Device Plugin 分配 GPU
在 AllocateResponse 里返回挂载信息:javascripthostPath=/dev/null containerPath=/var/run/nvidia-container-devices/<GPU-UUID>
文件名部分
<GPU-UUID>
就是 GPU 身份标识。 -
kubelet 写进 Pod spec
生成容器的挂载配置。 -
containerd/runc 启动容器
在容器内创建/var/run/nvidia-container-devices
目录,并挂载/dev/null
到<GPU-UUID>
文件。 -
nvidia-container-runtime 启动前解析
遍历/var/run/nvidia-container-devices
,读取文件名(UUID),决定注入哪些/dev/nvidia*
。
5. 解决的问题
5.1 安全性
- 非特权容器不能随便挂载
/var/run/nvidia-container-devices
,因此不能伪造 GPU 列表 - 即使用户在 PodSpec 里设置
NVIDIA_VISIBLE_DEVICES=all
,runtime 也会忽略(accept-nvidia-visible-devices-envvar-when-unprivileged=false
)
5.2 避免默认镜像全卡开放
- 即使镜像里有
NVIDIA_VISIBLE_DEVICES=all
,也不会生效 - 只有 Device Plugin 分配的 GPU 会被注入
5.3 与 Kubernetes 资源模型一致
- GPU 分配完全由 Device Plugin 控制
- 用户无法绕过调度器直接访问 GPU
6. 局限性
- 如果集群管理员没有禁用 hostPath 挂载,用户理论上可以自己挂载
/var/run/nvidia-container-devices
目录伪造 GPU 列表(所以生产环境应禁用 hostPath) - 和
envvar
模式一样,systemctl daemon-reload
会导致容器内失去GPU操作权限 - 这是 CDI(Container Device Interface)出现前的临时方案,在2020年提出后实现的,现已经被CDI模式取代
7. 总结一句话
volume-mounts 模式的用途:
用一个容器内的只读挂载目录
/var/run/nvidia-container-devices
代替环境变量传递 GPU 列表,防止非特权容器绕过 Kubernetes Device Plugin 直接访问 GPU,保证 GPU 分配的安全性和一致性。
8. 常见问题
该模式下启动容器报错
bash
Warning Failed 5s (x2 over 6s) kubelet Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error running prestart hook #0: exit status 1, stdout: , stderr: Auto-detected mode as 'legacy'
nvidia-container-cli: device error: /var/run/nvidia-container-devices: unknown device
这个模式需要调整节点上的nvidia容器运行时配置,/etc/nvidia-container-runtime/config.toml
中设置
ini
accept-nvidia-visible-devices-as-volume-mounts = true