Nvidia Device Plugin入门三之volume mount策略

1. 背景:原始的 envvar 模式

在前一篇文章里面提到最早的envvar实现里,NVIDIA Device Plugin 分配 GPU 的方式是:

  1. Pod 申请 GPU → kubelet 调用 Device Plugin 的 Allocate() 方法
  2. Device Plugin 返回一个环境变量:
ini 复制代码
    NVIDIA_VISIBLE_DEVICES=<GPU-UUID 或 index>
  1. 容器 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 模式的设计目标

目标:

  1. 防止非特权容器绕过 Device Plugin
    • 不再用环境变量传递 GPU 列表
    • 改成通过容器内的一个特殊目录 /var/run/nvidia-container-devices 传递
    • 这个目录由 kubelet 挂载,普通用户不能自己挂载
  2. 保持兼容性
    • runtime 仍然可以从这个目录读取 GPU 列表
    • 特权容器(如监控、Device Plugin 自身)仍然可以访问全部 GPU
  3. 简化实现
    • 不引入新的 CRI API
    • 只是把"传递 GPU 列表"的方式从 envvar → volume mount

4. volume-mounts 的工作方式

  1. Device Plugin 分配 GPU
    在 AllocateResponse 里返回挂载信息:

    javascript 复制代码
    hostPath=/dev/null
    containerPath=/var/run/nvidia-container-devices/<GPU-UUID>

    文件名部分 <GPU-UUID> 就是 GPU 身份标识。

  2. kubelet 写进 Pod spec
    生成容器的挂载配置。

  3. containerd/runc 启动容器
    在容器内创建 /var/run/nvidia-container-devices 目录,并挂载 /dev/null 到 <GPU-UUID> 文件。

  4. 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
相关推荐
wzq11_6667 小时前
Kubernetes集群——网络管理
云原生·容器·kubernetes
Nontee1 天前
K3s vs K8s:差的不是功能,是交付方式
云原生·容器·kubernetes
朱包林1 天前
iTerm2终端配置指南
linux·javascript·python·云原生·容器·kubernetes·云计算
小陈运维1 天前
使用kubeadm初始化IPV4/IPV6集群
linux·docker·云原生·容器·kubernetes
笑洋仟1 天前
k8s的Ingress配置问题
云原生·容器·kubernetes
垚垚学技术_聚焦云原生1 天前
K8s OpenEBS LVM 动态存储 PVC Pending 排查记
云原生·容器·kubernetes
sbjdhjd2 天前
云安全 | 从特权容器到旧版 runC:Docker 宿主机访问与运行时缺陷复盘
运维·网络安全·docker·云原生·kubernetes·云计算·云安全
谢亮_vipxieliang3 天前
Kubernetes 的“操作系统化”:从容器编排到 AI 基础设施控制平面
人工智能·平面·kubernetes
sbjdhjd3 天前
云安全 | Docker 容器逃逸复盘(三):docker.sock 挂载与 Docker-in-Docker 风险
经验分享·网络安全·docker·云原生·容器·kubernetes·云安全
热爱Liunx的丘丘人3 天前
1、什么是K8s
云原生·容器·kubernetes