目录

nvidia-smi报错排查和解决

概述

排查一个 nvidia-docker 的问题。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img.png

官方issue

从 nvidia-docker 的官方 issue 中检索,大概发现了如下这些 issue ,大概的意思是目前 nvidia-docker 依靠 runc hook 在 containerd 背后进行 GPU 设备注入(这是现有nvidia-container-runtime的基本/架构缺陷),并且是所有这些问题的根本原因。

k8s-device-plugin的启动参数

从代码上看,pass-device-specs 会把具体的设备和权限配置好。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_2.png

从我们的集群中部署的 k8s-device-plugin 中可以看到 pass-device-specs 给的是默认的 false

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_1.png

确认问题

通过堡垒机登录宿主机查看一下具体环境,通过 nsenter 进入容器的命令空间通过 strace 来查看一下执行 nvidia-smi 报错的原因。

1
2
3
4
5
6
7
# 容器内没有strace,需要手动安装
strace -v -a 100 -s 1000 nvidia-smi
# 查看runc版本
# runc -v
runc version 1.0.0-rc10
commit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
spec: 1.0.1-dev

检查了两个挂载了 GPU 的容器,一个容器是可以正常执行 nvidia-smi 另一个则会报错。下面是宿主机下看到的设备。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_4.png

异常容器的 device.list 已经看不到 GPU 的设备了。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_3.png

而正常容器是可以看到的。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_5.png

strace 的结果上看,异常容器是没有权限使用 /dev/nvidiactl 的,所以执行结果就报错了。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_6.png

解决的方案

我们的情况跟 issue 从 device 的结果来说是一样的,虽然原因不一样,比如说我们没有使用 static cpu 以及没有执行过 systemctl reload 之类的操作。

issue 看,我们的 runc 版本是比 1.3 低的,可以在不动 runc 的情况下,通过比较简单的 workaround 来尝试解决,可以参考这个 comment,更新一下 k8s-device-plugin 的启动参数 pass-device-specs=true,然后再验证一下问题是否会复现。

cgroup和device

cgroupv1 和 cgroupv2 在对待 device(包括GPU)方面有所不同。

在 cgroupv1 中,设备控制是通过子系统的控制文件来实现的,其中包括 devices.allow 和 devices.deny 文件。可以使用 major:minor rwm 格式的条目来定义允许或拒绝访问某个设备。但是,这种方法不够灵活,无法实现细粒度的设备控制。

相比之下,cgroupv2 引入了一个名为 Devices 的新控制器,允许更细粒度地控制设备访问。使用 cgroupv2,您可以创建称为 slice 的层次结构,每个slice 都可以分配一组设备(包括GPU)。可以使用 cgroupv2 的 devices.allow 和 devices.deny 文件来定义哪些设备可以访问。还可以使用cgroupv2 的 cgroup.event_control 文件来实现在容器内运行的应用程序与设备之间的绑定

需要注意的是,cgroupv2 不完全兼容 cgroupv1,并且在实践中,许多 Linux 发行版仍然默认使用 cgroupv1。因此,在使用 GPU 时,需要确保在选择 cgroup 版本时考虑到设备控制的差异。因为目前公司环境主要还是 cgroupv1,短期应该不会有大规模的升级。

修复和验证

更新了 gd16-001 集群的 k8s-device-plugin DaemonSet,具体的修改如下。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_7.png

然后重启 gd16-001 中的其中一个 Pod。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_9.png

执行 nvdia-smi 查看结果,容器启动 1h 之后,都没有问题,再持续观察一下。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_8.png

另外就是 gd16-002 的 Pod 即使重启也无法运行 nvidia-smi 这也是个比较奇怪的点,这难道就是一直都用不上 GPU 的原因?

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_10.png

另外还有其他域是有类似的问题的,brand-img-gen-serving.ai.vip.com,comment-opinion-serving.ai.vip.com,再去验证一下。其中 gd16-001 中的 k8s-device-plugin 已经更新过了,但是 GPU 容器没有更新,因此上面说到的 GPU 设备以及 nvidia-smi 等命令的执行都是有问题的。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_12.png

之后通过重启 GPU 容器,让容器重新挂载宿主机的这些设备,再验证效果,测试的结果显示,这个域的 GPU 容器可以正确读取到 GPU 设备,基本就完成了这个问题的验证了,至于为什么会出现这种原因,后面在另外的集群 gd16-002 再去调查,先把大部分集群的问题修复好。

/nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_13.png /nvidia-smi%E6%8A%A5%E9%94%99%E6%8E%92%E6%9F%A5%E5%92%8C%E8%A7%A3%E5%86%B3/img_14.png

参考资料

  1. 记NVIDIA显卡A100在K8S POD中Failed to initialize NVML: Unknown Error问题解决
  2. Nvidia Container与Kubelet CPU Manager的格格不入
警告
本文最后更新于 2023年2月19日,文中内容可能已过时,请谨慎参考。