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
相关推荐
Kendra9191 天前
Kubernetes 常用命令
云原生·容器·kubernetes
2501_939909051 天前
k8s基础与安装部署
云原生·容器·kubernetes
谷隐凡二1 天前
Kubernetes Route控制器简单介绍
java·容器·kubernetes
李少兄2 天前
Kubernetes 日志管理
docker·容器·kubernetes
秋饼2 天前
【K8S测试程序--git地址】
git·容器·kubernetes
oMcLin2 天前
如何在RHEL 9上配置并优化Kubernetes 1.23高可用集群,提升大规模容器化应用的自动化部署与管理?
kubernetes·自动化·php
ghostwritten2 天前
Kubernetes 网络模式深入解析?
网络·容器·kubernetes
原神启动12 天前
K8S(七)—— Kubernetes Pod 基础概念与实战配置
云原生·容器·kubernetes
不想画图2 天前
Kubernetes(五)——rancher部署和Pod详解
linux·kubernetes·rancher
大都督老师2 天前
配置 containerd 使用镜像加速器拉取 Docker Hub 镜像
容器·kubernetes·k8s