在RHEL8上安装Nvidia Driver(CUDA)

发布时间 2023-06-15 16:12:42作者: **smartheye**

一般来说深度学习还是用Ubuntu比较好,安装的时候直接帮你把Nvidia驱动装好,非常方便。

但是国内大批公司还是RHEL(CentOS)的,至于我们公司那只能用RHEL了。

RHEL装CUDA较为麻烦,牵涉的知识较为广泛。我也卡了很久,百思不得其解。

过去如果遇到装不上CUDA的问题,那很可能是无解的问题。因为Nvidia过去对Linux的支持可谓极差,又不开源。常见问题例如:

  • 为旧硬件不提供新kernel的适配
  • 为旧kernel不提供新硬件的适配
  • bug无人修,也无处可以问等等

所以过去都要买主流硬件,比如1080/20系/30系等等。我目前手上是一块非常便宜的Geforce 730桌面显卡。过去这块显卡只有CUDA 8的驱动,而且只能适配特定版本的kernel。这次惊喜的发现,黄夹克居然为这款硬件更新驱动了,目前支持CUDA11。

这里写一下一般的安装方法。

硬件配置

一台Lenovo ThinkCenter台式机,附带730显卡(这块显卡居然还贴着精粤的标签),内存32G,一块512G固态硬盘,一块2T机械硬盘。

软件配置

RHEL 8.8

SELinux必须开启

需要安装vim这样的编辑工具

主要问题和预想的解决方案

历史背景是,N卡过去驱动并不开源,因为N卡也不是OpenGL的路子,社区没法像A卡那样给他做基于OpenGL的驱动。所以经历了漫长(最起码有10+年)的努力后,给N卡做了一款通用驱动叫nouveau。这款驱动神奇就是一个版本对应所有显卡,另外常常会无故花屏死机。但是目前如果不像Ubuntu那样自己给kernel做适配的话,Linux发行版默认都是用nouveau这款版本的驱动的。因为Linux内核的发行许可是GPL,这就意味着如果N社不做开源,Linux就无法把N社的驱动集成到自己内核里,GPL的license限制了这一点。所以就必须用户自己来装。

那方案其实一开始就是很明确的。

先在N社官方主页找到并下载驱动,然后进命令行界面把nouveau这款驱动禁了,再把N社驱动装上,再回到GUI界面,只要nvidia-smi命令执行完不报错即可。

实际步骤稍微有些不同。

需要再追加一些步骤。由于N社驱动是在本机编译代码然后生成内核模块添加进linux内核。所以首先要在BIOS里禁止安全启动(Secure Boot),在Linux里SELinux。然后要搞定内核签名的问题,不然BIOS里没法把安全启动再开起来。

解决步骤

1. 在BIOS里禁止安全启动

以Lenovo为例,开机按F2进入BIOS。然后在安全(Security)选项卡里找到安全启动(Secure Boot),选择关闭即可。没有鼠标的用上下方向键和回车/空格操作。

为何要禁止安全启动?安全启动本质上是让Linux校验内核模块的签名,拒绝自签名的内核模块。如果不禁止安全启动的话,内核就会无法加载下面编译完的nvidia驱动。换言之,在安装完成后,重新开启安全启动,也会造成内核无法加载nvidia驱动,导致进不了GNome/KDE等X Windows。

2. 在RHEL里临时禁止SELinux

编辑/etc/selinux/config

执行命令

sudo vim /etc/selinux/config

 

然后找到SELINUX=enforcing这行,改为SELINUX=disabled

禁止SELinux的资料还可以参考:链接

3. 安装必要软件

N卡驱动实际上是源代码,然后安装过程就是编译源代码生成内核模块。所以至少需要基础的编译和一些devel包。已知编译需要下列包(可能过多)

dkms kernel-devel libglvnd-devel libva-utils libva-vdpau-driver vdpauinfo

安装dkms后就可以让dkms每次在安装新kernel后自动编译驱动,但是代价就是内核签名用的公私钥找不到放哪里了。

然后RHEL(CentOS)需要开启epel-release。这方法网上很多这里就不写了。

所以执行过程是

3.1. 安装epel-release

方法略

3.2. 安装必要的软件包

执行下列命令

sudo yum update -y
sudo yum group install -y "Development Tools"
sudo yum install -y dkms kernel-devel libglvnd-devel libva-utils libva-vdpau-driver vdpauinfo

 

无需reboot,继续执行下一步。

4. 禁止nouveau

主要参考文档:Disabling Nouveau Drivers in RHEL 8

4.1. 修改grub参数

编辑/etc/default/grub文件

sudo vim /etc/default/grub

找到GRUB_CMDLINE_LINUX这行,在最后加入rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1

内核模块黑名单的解说可以看这里

nvidia-drm.modeset=1的含义是enable DRM (Direct Rendering Manager) kernel mode setting

然后执行

sudo echo "blacklist nouveau" > /etc/modprobe.d/denylist.conf
sudo echo "options nouveau modeset=0" >> /etc/modprobe.d/denylist.conf

因为已经禁止了显卡驱动,所以重启自然进不了X,然后执行下列命令把下次登陆改为命令行

sudo systemctl set-default multi-user.target

改回图形界面的命令是

sudo systemctl set-default graphical.target

4.2. 重新生成initramfs

sudo dracut --force

4.3. 重建grub

MBR
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
UFEI
sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg

4.4. 重启

sudo systemctl reboot

5. 生成Machine Owner Key

主要参考https://gist.github.com/lijikun/22be09ec9b178e745758a29c7a147cc9这篇文章

我们这次是使用dkms这个工具来自动编译nvidia驱动模块,所以希望把dkms用自己的key来签名,这样可以把这个证书加到安全启动里去。

首先我们已经在命令行界面了,执行sudo -i 切换到root用户。接下来均在root用户下操作

创建/root/mok目录

5.1. 生成MOK公私钥

生成公私钥命令
 openssl req -new -x509 \
    -newkey rsa:2048 -keyout /root/mok/mok.key \
    -outform DER -out /root/mok/mok.der \
    -nodes -days 36500 -subj "/CN=MOK"

​5.2. 用MOK导入内核

执行命令

mokutil --import /root/mok/mok.der

此时需要输入密码。密码是必须输入的,一定要记住这个密码。 

5.3. 重启系统

  • 选择 "Enroll MOK"
  • 选择 "Continue"
  • 选择 "Yes"
  • 输入上面输入的密码
  • 选择 "OK" 然后电脑会重启

5.4. 编辑/etc/dkms/framework.conf

把/root/mok/mok.key拷贝到/var/lib/dkms/mok.key,把/root/mok/mok.der拷贝到/var/lib/dkms/mok.der。权限不变。

在/etc/dkms/framework.conf最后加入(如果已经配置了mok_signing_key及mok_certificate则不适用)

mok_signing_key=/var/lib/dkms/mok.key
mok_certificate=/var/lib/dkms/mok.der

安全起见这里再重启一次。

 

6. 安装Nvidia驱动

将在Nvidia官方网站上下载的驱动标记成可执行文件

执行命令

chmod +x NVIDIA....run
sudo ./NVIDIA....run

 

问选择dkms管理的时候选择Yes

问是否要更新XOrg conf的时候选择No

然后就安装好了

 

7. 清理,重启

将SELinux改回最开始的状态。

安全启动还是关闭

执行sudo systemctl set-default graphical.target

然后重启系统

再进入系统后执行nvidia-smi

正常出结果即为安装正确