如何解决在容器中执行 nvidia-smi 的系列问题

字数 1596,阅读大约需 8 分钟
如何解决在容器中执行 nvidia-smi 的系列问题
容器中查看不到 GPU 进程信息
问题:我们在容器中使用 GPU 之后,执行 nvidia-smi
却查看不到进程;这个问题到目前依然没有官方解决办法。
原因我认为有两点:
• 我们都知道容器使用了
namespace
技术,它其中有一个叫pid namespace
;Nvidia 的内核模块因为感知不到Pid
的隔离,所以它不能处理这种容器Pid
到主机Pid
的转换。•
nvidia-smi
命令执行的时候在获取进程信息的时候会直接和内核进行交互;这个我们通过执行strace nvidia-smi
命令可以分析出来。导致没有办法从nvml
的api
中进行拦截和处理。
下面提出了三种替代方案来解决这个问题,具体使用根据个人情况来决定。
方案一:设置 hostPid
知道原因之后,第一想到的方案肯定是让容器使用宿主机的 pid namespace
,不要进行隔离。
• 在
Pod
的Yaml
文件中添加如下内容:
• 使用
docker
命令启动的时候指定--pid==host
这个方案的优点就是使用简单,没有添加新的组件,不会对系统产生新的问题
;
缺点就是它能看到宿主机上的所有 GPU 进程
,这要是在算力云 Pass
产品里面是不能接受的,这样就没有安全性可言了。
方案二:使用内核拦截处理
因为上述问题是 nvidia
在内核中进行限制的,所以还有一种办法就是写一个内核模块来处理。下面是市面上存在的几个项目:
• https://github.com/gh2o/nvidia-pidns
• https://github.com/matpool/mpu
• https://github.com/gpues/nvidia-pidns
这个内核模块的主要目的是通过拦截 nvidiactl
设备的 ioctl
调用,对进程 PID
在不同 PID
命名空间之间进行转换,从而确保 NVIDIA GPU
在容器化环境或多 PID
命名空间系统中能够正确识别和管理进程。以下是代码的核心功能:
1. 拦截
ioctl
调用:
• 模块通过替换
nvidiactl
文件操作中的unlocked_ioctl
和compat_ioctl
函数指针,插入自定义的 PID 转换逻辑。• 自定义函数
nvidia_pidns_unlocked_ioctl
和nvidia_pidns_compat_ioctl
在调用原始ioctl
前后执行额外的处理。
PID
转换逻辑:
• 通过
fixer_0x0ee4
、fixer_0x1f48
、fixer_0x2588
和fixer_0x3848
等函数,根据不同的NVIDIA
驱动版本(通过arg.tag
区分)对PID
进行转换。• 使用内核函数如
find_vpid
和find_pid_ns
在命名空间之间映射PID
。
3. 模块生命周期:
•
nvidia_pidns_init
:初始化模块,找到nvidiactl
设备,保存原始ioctl
函数指针并替换为自定义函数。•
nvidia_pidns_exit
:退出模块,恢复原始ioctl
函数指针并释放资源。
重点
上面这些项目使用都不太方便,而且年久失修,在高内核版本已经编译不通过了,我在我的的代码仓库[1]中进行了调整:
• 我把它修改了可以通过
helm
部署就能把这个内核驱动安装上去的项目。• 修复了之前项目里面说的在内核
5.7+
上运行不了的问题。
使用步骤:
1. 只需要执行如下的命令安装到
kubernetes
集群中即可。
使用有问题请提交 issue
.
现在要求节点能联网,因为它需要去执行 apt 的动作,会动态编译内核模块,然后把它安装到内核中去;更多具体的使用可以参考我的 github
项目中文档。
方案三:使用 nvitop
命令
nvitop
是一款交互式 NVIDIA 设备和进程监控工具。它可以实现在容器中查看 GPU
进程信息,坏处是它会查看到整个主机上所有的进程信息,而不是当前容器的。

• 安装:
pip3 install --upgrade nvitop
• 使用:
python3 -m nvitop
使用 gpu-operator 安装驱动后宿主机执行不了 nvidia-smi
使用 gpu-operator
安装驱动又很多好处,可以快速的进行版本升级和测试,并且整个集群中节点上的驱动升级是自动化的。
但是使用它安装驱动之后假如想在宿主机上执行 nvidia-smi
命令查看 GPU
的信息就会发现提示没有这个命令。
那其实 gpu-driver
这个 Pod
在安装好驱动之后同时也会把 nvidia-smi
命令安装到宿主机上,只是和我们的 root
用户不在同一个 namespace
下,导致我们不能访问它的文件系统。
知道原因之后想要访问就比较简单了,使用如下命令就可以解决这个问题。
下面是一个简单的 pytorch
的测试脚本,主要是持续消耗 GPU
:
往期推荐
使用 GPU DVFS 来优化GPU效率CUDA Fatbin动态解压缩揭开Nvidia GPU显存超分的面纱GPU探针:使用 eBPF 来实现 CUDA 内存泄露监控Kubernetes 中使用 CRIU 实现 GPU进程实时迁移:进阶篇Kubernetes 中使用 CRIU 实现 GPU进程实时迁移:基础篇Nvidia 显存缺斤少两?Nvidia MPS深入浅出GPU远程调用—代码实践篇GPU远程调用—原理篇GPU远程调用—代码入门篇GPU远程调用—入门篇GPU虚拟化GPU内核虚拟化-基础篇GPU内核虚拟化-原理篇GPU 设备动态挂载到 Pod 原理分析Nvidia MIG深入浅出
引用链接
[1]
我的的代码仓库: https://github.com/lengrongfu/mpu
版权声明: 本文为 InfoQ 作者【Infra研习社】的原创文章。
原文链接:【http://xie.infoq.cn/article/fde50d32d1383487a0072858b】。文章转载请联系作者。
评论