CentOS 超算 GPU 节点内核与 NVIDIA 驱动升级记录:从 535 到 595.80
背景
这次维护的目标是升级超算 GPU 节点 gpu2 的 NVIDIA 驱动,以满足某些 CUDA 二进制库对新版 NVIDIA kernel driver 的要求。
原始环境大致如下:
系统:CentOS 7 |
这次升级过程中踩到的坑比较典型:
新驱动需要新内核,新内核需要新 GCC,驱动编译又牵涉到 RDMA/IB 模块,最后还因为存储网络没起来导致共享 home 丢失。
最终成功组合是:
Kernel: 5.4.278-1.el7.elrepo.x86_64 |
维护前准备:先保护调度环境
升级 GPU 驱动和内核前,第一步不是安装软件,而是保护正在运行的作业和 Slurm 调度状态。
先查看 gpu2 上是否有作业:
squeue -w gpu2 |
如果有作业,需要等待结束或由管理员确认后取消:
sudo /opt/gridview/slurm/bin/scancel <jobid> |
然后将节点置为维护状态:
sudo /opt/gridview/slurm/bin/scontrol update NodeName=gpu2 State=DRAIN Reason="kernel/driver upgrade" |
确认节点进入 drain:
/opt/gridview/slurm/bin/sinfo -N -l | grep gpu2 |
这一点非常重要。不要在节点仍可接收作业时升级内核和驱动。
为什么不能只用 Docker 或虚拟机解决
一开始也考虑过 Docker 或虚拟机。结论是:
Docker 不能绕过宿主机 NVIDIA kernel driver。
容器可以换 CUDA runtime、用户态库、PyTorch 版本,但实际和 GPU 通信的内核驱动仍然来自宿主机。
如果某个二进制库要求宿主机驱动版本达到 595+,那么容器内装再新的 CUDA runtime 也无效。
虚拟机 GPU passthrough 也不是优先方案,因为它要求 IOMMU 正常启用,还会牵涉 Slurm/GRES、GPU 隔离、性能和运维复杂度。最终选择直接升级 gpu2 宿主机内核和驱动。
内核选择:不要盲目追新
最开始尝试过 ELRepo 的 kernel-ml 6.9.7。这个内核可以正常启动,但后续编译 NVIDIA 595.80 时遇到 Module.symvers parse error 和 nvidia-uvm 构建失败。
最终选择了更保守的 ELRepo kernel-lt 5.4.278。
原因是:
- NVIDIA 595 需要比 CentOS 7 默认 3.10 更新的内核;
- 但超算节点不需要最新主线内核;
- CentOS 7 老用户态和太新的 6.x 内核组合容易触发兼容性问题;
kernel-lt更适合作为生产环境折中方案。
在 admin1 上下载:
mkdir -p /tmp/gpu2-kernel-lt |
传到 gpu2:
ssh gpu2 'mkdir -p /tmp/gpu2-kernel-lt' |
在 gpu2 上安装:
cd /tmp/gpu2-kernel-lt |
确认 GRUB 条目:
sudo grubby --info=ALL | egrep -i '^(index|kernel|title)=' |
当时看到:
index=0 |
为了保留回退能力,先把默认内核仍设为旧的 3.10,只让下一次临时启动 5.4:
sudo grubby --set-default /boot/vmlinuz-3.10.0-957.el7.x86_64 |
重启后验证:
uname -r |
输出为:
5.4.278-1.el7.elrepo.x86_64 |
GCC 工具链:CentOS 7 默认 GCC 太旧
NVIDIA 595 在新内核上编译内核模块时,CentOS 7 默认 GCC 4.8.5 不够用。
之前在 6.9 内核上已经遇到过:
gcc: error: unrecognized command line option '-fpatchable-function-entry=16,16' |
因此需要安装 devtoolset-9。
在 admin1 上下载 devtoolset-9 相关 RPM 后,传到 gpu2 并离线安装:
cd /tmp/gpu2-devtoolset9 |
验证:
source /opt/rh/devtoolset-9/enable |
应看到:
gcc (GCC) 9.3.1 |
后续运行 NVIDIA 安装器时显式指定 GCC:
sudo env \ |
NVIDIA 595.80 安装:最终使用 --no-peermem
在 5.4.278 内核下安装 NVIDIA 595.80。
先确认 nouveau 没有加载:
lsmod | grep nouveau |
然后安装:
cd /tmp |
安装器选项:
Kernel module type: NVIDIA Proprietary |
这里使用了 --no-peermem。原因是 nvidia-peermem 编译失败,但它不是普通 CUDA 必需模块,而是 GPUDirect RDMA 相关模块。
普通 CUDA 更关键的是:
nvidia |
安装成功后不要立刻随意重启。因为之前默认内核仍是 3.10,需要再次指定下一次进入 5.4:
sudo grubby --set-default /boot/vmlinuz-3.10.0-957.el7.x86_64 |
重启后验证:
uname -r |
结果:
uname -r -> 5.4.278-1.el7.elrepo.x86_64 |
确认成功后,将 5.4 固定为默认内核:
sudo grubby --set-default /boot/vmlinuz-5.4.278-1.el7.elrepo.x86_64 |
意外问题:共享 home 丢失
驱动升级成功后,发现 SSH 到 gpu2 时 starship、zsh、个人配置都没了,登录提示也变成普通 bash:
[dingrui@gpu2 ~]$ |
同时登录时曾出现:
Creating home directory for dingrui. |
检查后发现:
df -hT $HOME |
在 gpu2 上显示:
/dev/sda3 ext4 ... / |
而在正常的 gpu1 上:
istorage1:/public nfs4 ... /public |
这说明 gpu2 的 /public 没有挂载 NFS,共享 home 丢失,系统在本地根分区下临时创建了一个“影子 home”。
这时不要复制配置文件来修。正确做法是恢复 /public 挂载。
根因:InfiniBand/IPoIB 存储网络没起来
在 gpu2 上检查:
ping -c 3 istorage1 |
结果:
getent hosts istorage1 -> 12.12.12.250 |
说明 DNS 没问题,但到存储网段没有路由。
对比 gpu1:
ip -br addr |
gpu1 正常:
ib0 UP 12.12.12.201/24 |
gpu2 异常:
没有 ib0 |
检查硬件:
lspci | grep -Ei 'mellanox|infiniband|network|ethernet' |
看到:
Infiniband controller: Mellanox Technologies MT28908 Family [ConnectX-6] |
说明硬件在,但 IPoIB 接口没起来。
加载模块:
sudo modprobe mlx5_core |
然后 ib0 出现,但状态为 DOWN:
ip -br addr |
启动接口:
sudo ifup ib0 |
验证:
ip -br addr | grep ib0 |
结果:
ib0 UP 12.12.12.202/24 |
恢复 /public NFS 挂载
存储网络恢复后,手动挂载:
sudo mount -t nfs4 \ |
验证:
df -hT /public /public/home /public/home/dingrui |
结果:
12.12.12.250:/public nfs4 ... /public |
重新 SSH 后,starship prompt 恢复:
dingrui in 🌐 gpu2 in ~ |
让 IB 和 NFS 重启后自动恢复
这一步很关键,否则下一次重启后 /public 可能再次丢失。
写入自动加载模块:
sudo tee /etc/modules-load.d/ipoib.conf >/dev/null <<'EOF' |
添加 /etc/fstab:
sudo cp /etc/fstab /etc/fstab.bak.$(date +%F_%H%M%S) |
测试:
sudo mount -a |
为了闭环,又做了一次受控重启测试。重启后检查:
uname -r |
全部正常:
Kernel: 5.4.278 |
恢复 Slurm 调度
确认系统、GPU、NFS、IB 都正常后,恢复节点:
sudo /opt/gridview/slurm/bin/scontrol update NodeName=gpu2 State=RESUME |
验证:
/opt/gridview/slurm/bin/sinfo -N -l | grep gpu2 |
结果:
gpu2 ... idle ... |
sinfo 中也显示:
gpu up infinite 1 idle gpu2 |
Slurm GPU 测试作业
测试脚本:
cat > ~/test_gpu2.sh <<'EOF' |
提交:
sbatch -A dingrui ~/test_gpu2.sh |
查看输出:
cat ~/test_gpu2.<jobid>.out |
结果显示:
gpu2 |
因为脚本里申请的是:
#SBATCH --gres=gpu:1 |
所以作业环境里只看到 1 张 GPU 是正常的,说明 Slurm GRES 隔离生效。
关于 nvidia-peermem
这次安装使用了:
--no-peermem |
原因是 nvidia-peermem 模块构建失败。
nvidia-peermem 主要用于:
GPUDirect RDMA |
普通 CUDA 计算依赖的核心模块是:
nvidia |
当前这些模块都已正常加载:
lsmod | grep -E 'nvidia|uvm' |
所以普通 CUDA、PyTorch、TensorFlow、自定义 CUDA 二进制库通常不受影响。
不过,nvidia-peermem 失败可能与当时 RDMA/IB 栈没有完整加载有关。升级后最初只有 mlx5_core,没有完整的:
mlx5_ib |
因此如果后续确实需要 GPUDirect RDMA,可以在维护窗口重新尝试安装 peermem:
sudo /opt/gridview/slurm/bin/scontrol update NodeName=gpu2 State=DRAIN Reason="try nvidia-peermem" |
如果失败,再回到已知成功方案:
sudo env \ |
回退方案
整个过程中始终保留旧内核,这是非常重要的。
查看内核:
sudo grubby --info=ALL | egrep -i '^(index|kernel|title)=' |
如果需要回退到旧内核:
sudo grubby --set-default /boot/vmlinuz-3.10.0-957.el7.x86_64 |
如果只是下一次临时启动某个内核,可以使用:
sudo grub2-reboot <index> |
这次实践中,“默认旧内核 + 下一次临时启动新内核”的方式非常有用。
它可以避免新内核启动失败后节点长期卡在不可用状态。
最终检查清单
升级完成后,应至少检查以下项目:
uname -r |
建议记录成功状态:
mkdir -p ~/gpu2-driver-upgrade-record |
经验总结
这次维护最大的经验是:GPU 驱动升级不是单独的 NVIDIA 问题,而是内核、编译器、网络、存储、Slurm 权限共同作用的问题。
几个关键注意事项:
先 Drain 节点,再维护。
不要让用户作业在维护过程中进入节点。不要盲目追最新内核。
对 CentOS 7 来说,kernel-lt 5.4比kernel-ml 6.9更稳。保留旧内核回退。
使用grub2-reboot做一次性启动,比直接改默认内核更安全。新内核需要匹配的新 GCC。
CentOS 7 默认 GCC 4.8.5 很容易无法编译新版 NVIDIA 模块。普通 CUDA 不一定需要
nvidia-peermem。
没有 GPUDirect RDMA 需求时,可以使用--no-peermem。不要忽略共享存储。
登录后配置丢失、starship 消失,不一定是 shell 配置问题,可能是/public没挂上。IB/IPoIB 要随内核一起检查。
新内核启动后,mlx5_ib、ib_ipoib可能没有自动加载,导致 NFS 存储网络不可达。Slurm 测试必须通过真实作业完成。
nvidia-smi在 SSH 中正常不等于 Slurm 作业环境正常。临时修改 Slurm 分区权限要写回配置。
scontrol update PartitionName=...只是运行时状态,长期生效需要改slurm.conf。每一步都要验证,而不是假设成功。
这次问题能排完,靠的就是每一步都对比gpu1和gpu2的实际状态。
最终状态
最终 gpu2 已恢复为:
Node: gpu2 |
到这里,gpu2 的内核、驱动、共享存储、IB 网络和 Slurm 作业验证全部闭环。