如何解决在容器中执行 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】。文章转载请联系作者。








 
    
 
				 
				 
			


评论