LabHub
学习 学习路径 课程

闭网环境的 GPU 驱动搬入与安装

驱动包这一组东西的形状

在 LabHub 中继续学习

一句话总结

NVIDIA 驱动不是一个软件包,而是由内核模块、用户空间库、实用工具和显示驱动四条依赖链交织而成的一组软件包。

概念图: 内核模块、用户空间库、实用工具和显示驱动 · 元软件包 · 1. linux-headers 与内核版本绑定。 · 导入时的内核与安装目标的内核不同时,构建就会失败。

为什么需要它

看起来只要下载 nvidia-driver-550 就够了,但它是一个元软件包,自身不包含任何实际文件,只有依赖项列表。沿着该列表展开,会出现十多个软件包。

它如何工作

四条依赖链

nvidia-driver-550  (메타)
├─ nvidia-kernel-dkms-550        커널 모듈 소스 (DKMS 로 빌드)
│  ├─ dkms
│  ├─ nvidia-kernel-common-550
│  └─ linux-headers-*            <- 커널 버전에 묶인다
├─ nvidia-utils-550              nvidia-smi 등
│  ├─ nvidia-compute-utils-550
│  └─ libnvidia-compute-550      CUDA 런타임 (Provides: libcuda1)
│     └─ libnvidia-cfg1-550
├─ libnvidia-gl-550              OpenGL/GLX/EGL
└─ xserver-xorg-video-nvidia-550 X.Org 드라이버

从封闭网络的角度看,这里有三个陷阱。

**1. linux-headers 与内核版本绑定。**DKMS 构建内核模块时,需要正在运行的内核所对应的 header;而内核一旦升级,header 软件包的名称也会改变。**导入时的内核与安装目标的内核不同时,构建就会失败。**因此,导入前首先要确认目标服务器的 uname -r

2. 有些依赖通过 Provides 满足。libnvidia-compute-550 会 Provides libcuda1。因此,即使某个软件包依赖 libcuda1,仓库中也不存在名为 libcuda1 的软件包。不理解这种关系而四处寻找“缺失的 libcuda1”,是常见的情况。

3. 容器 toolkit 是另一组软件包。

nvidia-container-toolkit
├─ nvidia-container-toolkit-base     nvidia-ctk, 런타임 바이너리
└─ libnvidia-container-tools         nvidia-container-cli
   └─ libnvidia-container1           공용 라이브러리

驱动与 toolkit **不仅仓库不同,版本体系也不同。**驱动来自发行版仓库或 NVIDIA 仓库,toolkit 则来自 NVIDIA 的独立仓库。导入时只准备其中一侧,是常见错误。

如何解析依赖图

apt 侧的工具如下。

apt-get install --print-uris -y nvidia-driver-550     # 받을 URI 목록만
apt-get install --download-only -y nvidia-driver-550  # 받기만
apt-cache depends --recurse --no-recommends --no-suggests nvidia-driver-550
apt-rdepends nvidia-driver-550                         # 별도 패키지
dpkg-deb -f pkg.deb Depends                            # 파일에서 직접 읽기

关键在于检查闭包(closure):bundle 中每个软件包所需的全部依赖,是否也都在 bundle 中?只要有一个依赖指向外部,内部安装就会中断。建立仓库并运行 apt-get install -s(模拟)是最可靠的检查方法。

计算安装顺序

使用 dpkg -i 逐个安装时,必须先安装依赖项。这是一个拓扑排序(topological sort)问题。

libnvidia-cfg1-550
libnvidia-compute-550
nvidia-compute-utils-550
nvidia-utils-550
libnvidia-gl-550
xserver-xorg-video-nvidia-550
nvidia-kernel-common-550
dkms
linux-headers-...
nvidia-kernel-dkms-550
nvidia-driver-550

如果可以使用 apt,它会自动决定该顺序,因此只需准备列表。但能够计算顺序与把工作交给 apt 是两回事——apt 失败时,要读懂在哪里中断,仍然必须理解依赖图。

实际工作中的表现

**DKMS 构建失败。**导入成功后,安装期间的内核模块构建却失败。日志通常显示 header 缺失或编译器版本不匹配。因此,GPU 节点经常会 hold 内核升级——内核升级后必须重新构建驱动,而在封闭网络中,这又意味着新一轮导入。

**Secure Boot。**未签名的内核模块无法在启用 Secure Boot 的系统中加载,还需要额外执行 MOK 注册流程,并且该流程要求访问物理控制台。

下一项实践将做什么

在假定已经导入的源码树中直接构建 .deb,解析依赖图,找出无法在 bundle 内解决的依赖,再通过拓扑排序计算安装顺序。