☰
CentOS Stream 9安装NVIDIA驱动与CUDA Toolkit完整指南
2026/10/2 7:42:05 网站建设 项目流程

这个周末我又双叒叕给一台CentOS Stream 9工作站装NVIDIA驱动了。说实话,装过Ubuntu的人第一次摸CentOS Stream 9的N卡驱动,十有八九会懵:Ubuntu那种几条apt命令装好的体验在这里完全不存在,你需要面对的是内核头文件、nouveau、Secure Boot和DKMS这一整套东西,任何一个环节没处理干净,后面就是无穷无尽的报错和重启。这篇文章就是把我从裸机到nvcc -V跑通的完整流程、踩掉的坑、以及每个步骤背后的原因从头到尾记录下来,给同样要在CentOS Stream 9上装nvidia驱动和cuda-toolkit的人一个可以直接照抄的参考。

1. 开工前必须想清楚的三件事:版本、内核、安全启动

装N卡驱动不是打开官网下载一个.run文件双击就完事。在CentOS Stream 9这种滚动更新模型下,装之前不把三件事想清楚,后面基本注定要返工。

1.1 先锁定CUDA版本,再倒推驱动版本

很多人的第一反应是装最新驱动,结果后面装CUDA Toolkit时发现驱动版本和CUDA版本对不上,要么降级驱动,要么装一个和需求不匹配的CUDA版本,非常被动。

这里有个NVIDIA官方一直强调的基本对应关系:CUDA Toolkit每个版本都要求驱动版本不低于某个阈值,更高版本的驱动能向下兼容多个CUDA版本。举个例子,CUDA 12.x要求驱动不低于545系列(具体看小版本),而535系列的驱动最多只能配合CUDA 12.2以下使用。如果你跑的是PyTorch、TensorFlow,建议先查官方支持矩阵,确认你要用的CUDA版本,再反过来定驱动版本,而不是先装个最新的驱动再说。

我这次的选择是CUDA 12.4 + 550系列驱动。原因很简单:12.4是当前生态兼容面最广的版本之一,主流深度学习框架都跟得很紧;550系列驱动对多卡通信、DDP的支持也足够稳定,而且后续如果要升级到CUDA 12.6、12.8,550系列驱动依然在兼容范围内,留出了余量。

1.2 内核头文件必须和当前内核版本严格对齐

驱动编译不是凭空编译的,它要针对当前运行的内核生成内核模块。CentOS Stream 9默认内核是5.14系列,但系统更新后,/usr/src/kernels/下面可能会躺着好几个版本的内核头文件。

如果你吭哧吭哧装完驱动,发现nvidia-smi报Failed to initialize NVML: Driver/library version mismatch,十有八九是内核头文件版本和当前内核没对齐。这属于老生常谈,但每次总有人踩,因为CentOS Stream 9的滚动更新太容易把系统里的kernel和kernel-devel版本搞成不一致了。我后来养成了一个习惯:装依赖前先看uname -r,然后确保 kernel-devel、kernel-headers 的版本与之一一对应。

1.3 Secure Boot:装前不处理,装后悔断肠

这一点特别容易被忽略,尤其是新买的工作站和品牌机。新版主板默认开启Secure Boot,Linux内核模块如果没经过签名机制授权,系统直接拒绝加载或者加载后模块验证失败。NVIDIA闭源驱动不提供现成的签名模块,所以你在Secure Boot开启的状态下装好驱动,重启后大概率发现驱动根本没加载,要么黑屏要么卡在登录界面循环。

处理方案有两个:一是进BIOS关掉Secure Boot,个人开发机、测试机的常规做法;二是走完整的模块签名流程,生成Machine Owner Key,给NVIDIA驱动模块签上密钥,适合有安全合规要求的服务器环境。我这次因为机器是个人开发用的测试工作站,直接关了,省心。生产环境不建议这么干,但也不能不处理就硬装。

2. 基础环境准备:禁用Nouveau并装齐编译工具链

前置条件想清楚后,动手前要把系统环境收拾干净。这一步骤决定了后续驱动安装会不会在半路翻车。

2.1 先确认GPU型号和内核版本

无论你之前是什么状态,先用三条命令确认硬件和内核:

lspci | grep -i nvidia uname -r gcc --version

lspci能看到显卡型号,比如我这边显示的是NVIDIA GA102 [GeForce RTX 3080]。这套流程对Ampere、Ada Lovelace以及更早的架构都适用;如果你手里的是特别老的卡,比如GTX 700系列甚至更早,那就得注意了,新版驱动已经不再支持,需要去NVIDIA官网翻legacy版本,安装逻辑虽然一致但版本选择思路完全不同。

uname -r输出的就是当前内核版本,记下来,后面很多地方都要对照它。gcc --version则用来确认系统里已经有可用的C编译器,没有的话后面编译内核模块会直接报错,尽早暴露问题比装到一半暴露要好。

2.2 禁用Nouveau:一步都不能省

CentOS Stream 9默认没有预装NVIDIA闭源驱动,但内核自带的nouveau开源驱动是存在的。nouveau虽然能点亮桌面,但在计算场景下性能和稳定性都不行,而且它一旦加载,NVIDIA官方驱动模块就无法绑定GPU,二者只能选一个共存。

禁用nouveau的正确姿势:

sudo tee /etc/modprobe.d/blacklist-nouveau.conf <<EOF blacklist nouveau options nouveau modeset=0 EOF sudo dracut --force

然后编辑/etc/default/grub,在GRUB_CMDLINE_LINUX这一行末尾加上rd.driver.blacklist=nouveau,再重新生成GRUB配置。这里要注意引导方式是BIOS还是UEFI,路径不一样:

# BIOS引导 sudo grub2-mkconfig -o /boot/grub2/grub.cfg # UEFI引导 sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

这里有个很多人会漏掉的点:写完blacklist文件后,执行dracut --force是必须的。因为CentOS Stream 9的initramfs里如果已经包含了nouveau模块,光写blacklist文件不重建initramfs,重启后nouveau照样会被加载。我第一次装的时候就是漏了这步,结果nvidia-smi一直提示找不到设备,查了半天才发现nouveau还在内核里。

2.3 装齐编译工具链和内核开发包

驱动安装过程中需要调用系统编译器生成内核模块,所以gcc、make、kernel-devel这些都是硬依赖:

sudo dnf install -y gcc make kernel-devel kernel-headers elfutils-libelf-devel dkms

kernel-devel提供内核源码树,DKMS则负责在内核升级时自动重新编译驱动模块。CentOS Stream 9的基础源里就有dkms,不需要额外添加EPEL,这点比老版本方便。

装完以后务必验证一下内核头文件版本与当前内核匹配:

ls /usr/src/kernels/$(uname -r)

如果这个目录不存在,说明kernel-devel版本不对或者没装上。出现这种情况,优先用精确指定版本的方式再装一次:sudo dnf install -y kernel-devel-$(uname -r)。

之所以反复强调匹配,是因为CentOS Stream 9的滚动更新很容易出现:系统里跑着5.14.0-362这个内核,头文件却是上一版5.14.0-284。这种情况驱动装得再对,模块编译出来也加载不到当前内核上,排错的时候会非常头大。

3. 驱动安装路线选择:为什么我最后选了CUDA官方仓库

CentOS Stream 9上装NVIDIA驱动有几种常见方式:NVIDIA官方runfile、RPM Fusion的非自由仓库、以及NVIDIA CUDA仓库。我这次三种都实际试了一遍,最后长期使用的是CUDA官方仓库,下面把三者的差异和选择逻辑讲清楚。

3.1 三条路线的优缺点对比

为了让你少走弯路,我把三者的本质区别先讲透:

路线安装方式优点缺点
NVIDIA runfile下载NVIDIA-Linux-x86_64-xxx.run后手动执行版本选择自由、不依赖第三方仓库每次内核升级都要手动重装;需要在init 3文本模式下关闭图形界面;残留进程会导致安装失败
RPM Fusion akmod-nvidiadnf install akmod-nvidia集成DKMS,内核升级自动重建模块仓库更新节奏滞后于NVIDIA官方新驱动;对CentOS Stream 9的适配有时会慢半拍
NVIDIA CUDA仓库配置cuda-rhel9.repo后dnf module install驱动版本和CUDA版本由官方一并维护,组合不打架;支持parallel-install多个CUDA版本仓库体积大,首次拉包时间稍长

很多教程推荐runfile,因为看起来最官方。但我个人在CentOS Stream 9上更推荐CUDA仓库,原因有两个:一是它通过dnf module管理nvidia-driver,能直接搞定驱动和CUDA之间的版本匹配问题;二是后续升级只用dnf update,不需要每次都进文本模式重装,对于长期跑训练的工作站来说省心太多了。runfile方式在内核更新之后如果不手动重装一次,驱动就处于半残状态,这对生产机来说是无法接受的。

3.2 配置CUDA仓库并安装驱动

具体操作如下:

sudo dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo sudo dnf clean all sudo dnf -y module install nvidia-driver:latest-dkms

注意这里的nvidia-driver:latest-dkms是module流,它包含驱动本体和DKMS钩子。安装完成后重启,再用nvidia-smi确认驱动和CUDA driver版本。

对于纯计算节点,我个人建议装完驱动后直接把默认运行级别切到multi-user:

sudo systemctl set-default multi-user.target sudo reboot

如果之后想切回图形界面,再执行systemctl set-default graphical.target重启即可。对一台要做深度学习或科学计算的主机来说,长期保持在multi-user下反而是最稳的,既避免了Xorg和NVIDIA驱动的兼容性冲突,也减少了一大块内存占用。

3.3 验证内核模块是否正常加载

重启后跑:

lsmod | grep nvidia nvidia-smi

如果lsmod能看到 nvidia 开头的几个模块,nvidia-smi能输出GPU温度、显存、驱动版本,说明驱动层已经OK。常见的nvidia-smi报错如No devices were found,原因基本集中在三种:nouveau没有禁干净、内核头文件不匹配、Secure Boot拦截了模块加载。

如果模块确实没有被加载,去看/var/log/messages或执行dmesg | tail -50,重点搜索nvidia和module verification failed关键字。我之前遇到过module verification failed: signature not found的报错,那就是Secure Boot没关导致的,进BIOS关掉再重启就好了。你也可以先用mokutil --sb-state查看Secure Boot的状态,省得盲猜。

4. CUDA Toolkit安装与环境变量配置

驱动层搞定后,CUDA Toolkit的安装反而简单了,因为我们已经走了CUDA官方仓库,仓库里包含各种版本的cuda包,不用再单独去官网下载runfile。

4.1 安装指定大版本的CUDA

我这里是CUDA 12.4:

sudo dnf -y install cuda-toolkit-12-4

这里要说明一下:如果之前没有单独装驱动,也可以直接执行sudo dnf -y install cuda-12-4,这个metapackage会连带把驱动和toolkit一起装上。我这次因为已经在3.2节用module方式装好了驱动,所以只需要装toolkit部分,避免重复拉取驱动包。

仓库方式安装还有一个巨大的好处:可以同时安装多个CUDA大版本。比如我需要跑的某个旧框架依赖CUDA 11.8,可以再执行:

sudo dnf -y install cuda-toolkit-11-8

两个版本共存,后面通过切换PATH环境变量来决定用哪一套。这一点是runfile方式非常难做到的,runfile装完一套再装第二套,很容易把/usr/local/cuda软链接搞乱。而仓库安装包的目录都是干净的/usr/local/cuda-12.4、/usr/local/cuda-11.8,互不冲突。

安装完成后会有一个/usr/local/cuda软链接指向最新版本。如果你需要固定到某个版本,手动调整软链接:

sudo rm -f /usr/local/cuda sudo ln -s /usr/local/cuda-12.4 /usr/local/cuda

4.2 配置环境变量:PATH和LD_LIBRARY_PATH

这一步看似简单,但很多人装完nvcc -V跑不出来,十有八九是环境变量没配或者没source。

我把配置写到/etc/profile.d/cuda.sh,这样所有用户登录后都能直接用:

export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH

保存后执行source /etc/profile.d/cuda.sh或者重新登录终端。

注意CUDA 12.x版本的lib64目录里有一堆libcuda.so.1等运行时链接库。某些程序会直接依赖libcuda.so这个不带版本号的软链接,如果启动时报缺少共享库,可以先看下/usr/local/cuda/lib64/里的软链接是否齐全。用仓库安装的话这个问题很少见,但如果是手动拷贝CUDA目录或者卸载不干净导致的问题,这个方向值得排查一遍。

4.3 编译运行官方样例验证

环境变量配好还不算完,真正验证CUDA编译器能不能用,最好的办法是编译官方samples里的deviceQuery:

sudo dnf -y install gcc-c++ cp -r /usr/local/cuda/samples ~/cuda-samples cd ~/cuda-samples/1_Utilities/deviceQuery make ./deviceQuery

输出末尾如果看到Result = PASS,说明驱动、CUDA Toolkit、编译器链路全部正常。顺手再跑一下bandwidthTest:

cd ~/cuda-samples/1_Utilities/bandwidthTest make && ./bandwidthTest

这个工具主要测显存带宽,跑出来的数值一般会接近官方标称值。如果带宽明显偏低,先怀疑GPU是否降频、PCIe链路是否跑在低速档位,用nvidia-smi -q -d PERFORMANCE或lspci -vv | grep LnkSta查一下当前链路状态。这些都属于装好之后才可能暴露的硬件层面问题,早发现早处理。

5. 实测验证与典型报错排查面板

装完不是终点,能不能持续稳定使用才是重点。这一节我把自己实测中遇到过的几个典型报错和排查思路整理出来,每一个都是实打实踩过的坑。

5.1 Driver/library version mismatch 的真相

这是N卡驱动最出名的神坑。症状是:nvidia-smi报Failed to initialize NVML: Driver/library version mismatch,而dmesg里能看到nvidia模块已经加载。

这个问题的本质是:内核里加载的nvidia内核模块版本,和/usr/lib64下运行时库libnvidia-ml.so的版本不一致。常见诱因是之前用runfile方式装过旧驱动,后来又用dnf装了新驱动,但旧的内核模块还挂在内存里;另一种情况是GPU进程没退干净,驱动无法正常卸载。

排查和解决:

# 看看当前驱动版本 cat /proc/drivers/nvidia/version # 查找占用GPU设备的进程 sudo fuser -v /dev/nvidia* # 强制卸载nvidia模块再重新加载 sudo rmmod nvidia_drm nvidia_modeset nvidia_uvm nvidia sudo modprobe nvidia

如果在rmmod时报Module nvidia is in use,说明还有进程占用,找到对应的PID杀掉再执行。这一招对多数mismatch问题都管用。如果rmmod还是卸不干净,最好的办法就是彻底重启,开发机上重启一次五分钟,比在模块状态里折腾一小时划算。

5.2 DKMS模块与内核升级的配合

仓库方式安装的nvidia-driver:latest-dkms自带DKMS,内核升级后模块会自动重建,理论上不用操心。但DKMS自动重建有一个前提:新内核对应的kernel-devel包已经装好。

所以CentOS Stream 9升级内核后,我建议按这个顺序操作:

sudo dnf update -y sudo dnf install -y kernel-devel-$(uname -r)

然后重启,重启后系统会跑一遍DKMS的rebuild流程。如果重启后发现驱动没加载,检查一下:

dkms status

输出里应该能看到类似nvidia/550.xx, 5.14.0-xxx, x86_64: installed的记录。如果状态不是installed而是failed,去/var/lib/dkms/nvidia/xxx/build/make.log看编译日志,十有八九是gcc版本换新导致的编译报错,或者是新内核头文件缺了某个include。这里有个小技巧:升级内核前先把开发包装好再重启,比重启后发现驱动没了再补包要稳得多。

5.3 nvcc找不到的诡异局面

还有一种特别气人的情况:驱动正常、nvidia-smi正常,但nvcc -V提示command not found。

这种一般是CUDA的bin目录没进PATH。如果你已经写了/etc/profile.d/cuda.sh但还没生效,多半是当前shell没重新source。这里有个小细节容易被忽略:bash的命令哈希缓存。有时候PATH里明明已经有了nvcc,但因为之前出现过一次command not found,bash把失败结果缓存了,导致再次执行依然提示找不到。解决方法是执行hash -r清一下缓存,或者直接新开一个终端。这个不起眼的小问题卡过我十分钟,写出来给后来人排个雷。

6. 迭代维护:内核升级与驱动重装的经验总结

装好一次不算完,CentOS Stream 9是滚动更新模型,内核更新频繁,驱动跟上内核节奏才是长期稳定使用的关键,最后这部分说说维护层面的经验。

6.1 我的一套日常更新顺序

现在我自己固定的更新顺序是:

  1. 先更新系统但先不重启:sudo dnf update -y
  2. 检查是否有新版内核:rpm -q kernel | tail -3
  3. 如果有新内核,确认对应的kernel-devel同步装上:sudo dnf install -y kernel-devel-$(uname -r)
  4. 重启进新内核
  5. 重启后查dkms status,确保nvidia模块状态是installed
  6. 跑一次nvidia-smi确认驱动还在

这套顺序执行下来,我几乎没有遇到过内核升级后驱动失效的问题。反而容易踩坑的是:update之后没装对应kernel-devel,重启后DKMS编译失败,驱动直接变成空白。所以我在第3步上从不偷懒,新内核只要确认更新,对应的devel包一定是同时装的。

6.2 什么时候需要手动清理旧CUDA版本

仓库方式安装的多个CUDA版本并存时,/usr/local下会有多个cuda目录。长期不动的话,/usr/local/cuda这个软链接始终指向最新版本,而老版本占用的磁盘空间也不少。

我每隔两三个大版本会清理一次不再用的老版本:

sudo dnf remove cuda-toolkit-11-8 sudo rm -rf /usr/local/cuda-11.8

清理前先确认没有项目依赖这个版本。最稳妥的做法是先改环境变量指向新版本,重新编译几个核心项目跑通验证,再回来删旧版本。有些人图省事直接删目录,结果dnf metadata里还留着记录,下次update又给你装回来,反而更麻烦。

6.3 日志与版本记录的习惯

很多人忽略了对驱动和CUDA版本做记录。我建议装完驱动后把下面这些信息记到一个文件里:驱动版本、CUDA版本、内核版本、安装方式、当天踩过的坑和解决方式。等到半年后系统出了奇怪问题,回头翻这份记录,比去论坛查半天帖子高效得多。

另外再分享一个细节:NVIDIA驱动包在系统里的痕迹不只在/usr/lib64,还有/usr/share/doc/nvidia-driver、/etc/X11/xorg.conf.d/下的配置文件。手动折腾驱动时,这些位置容易留下旧配置,最彻底的清理方式是dnf remove '*nvidia*'之后手动检查这些目录。保留太多的残留配置文件,是换了新版本驱动后出现莫名其妙兼容问题的主要源头之一。

在我自己的CentOS Stream 9工作站上,这套组合已经稳定跑了半年多,中间经历了三轮内核更新,驱动模块全靠DKMS自动重建,一次都没有在升级后掉链子。希望这篇记录也能帮你少走几天弯路,一次把驱动和CUDA Toolkit都装利索。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询