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
相关推荐
KubeSphere 云原生3 小时前
云原生周刊:在 Kubernetes 上运行机器学习
云原生·容器·kubernetes
企鹅侠客10 小时前
k8s-dashboard-v2.0.0-beta6部署
云原生·容器·kubernetes
奋斗的蛋黄10 小时前
SRE 进阶:AI 驱动的集群全自动化排查指南(零人工干预版)
运维·人工智能·kubernetes·自动化
戮戮12 小时前
一次深入排查:Spring Cloud Gateway TCP 连接复用导致 K8s 负载均衡失效
tcp/ip·spring cloud·kubernetes·gateway·负载均衡·netty
能不能别报错13 小时前
K8s学习笔记(二十四) ingress
笔记·学习·kubernetes
能不能别报错14 小时前
K8s学习笔记(二十三) 网络策略 NetworkPolicy
笔记·学习·kubernetes
suknna15 小时前
记一次 Kubebuilder Operator 开发中的 CRD 注解超限问题
kubernetes
victory043117 小时前
K8S 安装 部署 文档
算法·贪心算法·kubernetes
能不能别报错1 天前
K8s学习笔记(二十二) 网络组件 Flannel与Calico
笔记·学习·kubernetes
lijun_xiao20091 天前
DevOps(devops/k8s/docker/Linux)学习笔记
docker·kubernetes·devops