最近经常在网上看到各种关于AI工具的讨论,包括但不限于常见的 stable-diffusion-webui, llama3和各种大语言模型等。然而想要自己实际落实,部署这些工具往往也避不开N卡和其独占的CUDA。很幸运的是近几日我有一台空闲出来的30系N卡笔记本空闲了下来。为了更充分运用和合理的分配这台笔记本的计算资源,我便在上面安装了Proxmox VE。

比起常见的虚拟机PCIE透传显卡的方式,我选择了LXC容器的方案,多个容器可以共用一张显卡,实现算力的最大利用化。一番谷歌后我找到了来自其他博主的一篇记录 PVE LXC 容器直通 Nvidia 显卡 - 自说Me话 。并配合自己浅薄的知识储备成功照猫画虎的完成了显卡透传。

以下主要是记录安装过程和步骤,供自己后续参考。

宿主机配置

准备安装驱动

原文作者使用的是Debian源里的 nvidia-driver 包,缺点是没有那么新,我是自己在 /etc/apt/sources.list.d 下创建了 cuda.list ,使用NVIDIA的源。

接下来我们要导入NVIDIA源的公钥(请确保您已经在这之前安装了 curl gpg

curl -fsSL https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/3bf863cc.pub | gpg --dearmor -o /usr/share/keyrings/nvidia-cuda-archive-keyring.gpg

以下是 cuda.list 的内容

deb [arch=amd64 signed-by=/usr/share/keyrings/nvidia-cuda-archive-keyring.gpg] http://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/ /

以下是我的 /etc/apt/sources.list (可选步骤,如果您要使用我的 sources.list 请在编辑该文件之前记得安装 apt-transport-https ca-certificates )
我使用的是PVE8.1(基于Debian 12/Bookworm),而非原文作者在使用的PVE7.4(基于Debian 11/Bullseye)同时我还使用了南方科技大源,所以看起来会和原文作者的有些不同。

deb https://mirrors.sustech.edu.cn/debian/ bookworm main contrib non-free non-free-firmware
deb-src https://mirrors.sustech.edu.cn/debian/ bookworm main contrib non-free non-free-firmware

deb https://mirrors.sustech.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware
deb-src https://mirrors.sustech.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware

deb https://mirrors.sustech.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src https://mirrors.sustech.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware
安装驱动

把软件都保持最新,随后的驱动安装要用到编译且依赖 pve-headers ,但是其并没有被标为驱动依赖,故需要手动安装

apt update && apt upgrade -y && apt install pve-headers dkms -y && apt install nvidia-kernel-dkms cuda -y

接下来就是确认驱动及对应模块配置是否正确。和原文作者一样,我的 /etc/modules-load.d/nvidia.conf 中也只有 nvidia-drm 。所以请确保你的 /etc/modules-load.d/nvidia.conf 的内容和下面完全一样

nvidia-drm
nvidia
nvidia_uvm

检查其他文件

/etc/modprobe.d/pve-blacklist.conf

blacklist nvidiafb

/etc/modprobe.d/nvidia-blacklists-nouveau.conf

blacklist nouveau

由于在 /etc/modules-load.d/nvidia.conf 中添加了 nvidia 以及 nvidia_uvm 模块,所以需要对内核模块进行更新。使用如下命令

update-initramfs -u

重启,并检查对应的设备及显卡运行情况(比如使用 nvidia-smi

检查驱动是否正常工作
root@pve:~# nvidia-smi
Thu Apr 25 22:28:29 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.15              Driver Version: 550.54.15      CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3060 ...    On  |   00000000:01:00.0 Off |                  N/A |
| N/A   42C    P8             13W /   80W |       1MiB /   6144MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+
root@pve:~#

ls -al /dev/nvidia* 内容如下

crw-rw-rw- 1 root root 195,   0 Apr 25 16:57 /dev/nvidia0
crw-rw-rw- 1 root root 195, 255 Apr 25 16:57 /dev/nvidiactl
crw-rw-rw- 1 root root 195, 254 Apr 25 16:57 /dev/nvidia-modeset
crw-rw-rw- 1 root root 511,   0 Apr 25 17:50 /dev/nvidia-uvm
crw-rw-rw- 1 root root 511,   1 Apr 25 17:50 /dev/nvidia-uvm-tools

/dev/nvidia-caps:
total 0
drwxr-xr-x  2 root root     80 Apr 25 17:50 .
drwxr-xr-x 19 root root   4480 Apr 25 17:50 ..
cr--------  1 root root 237, 1 Apr 25 17:50 nvidia-cap1
cr--r--r--  1 root root 237, 2 Apr 25 17:50 nvidia-cap2

ls -al /dev/dri 内容如下

total 0
drwxr-xr-x  3 root root        100 Apr 25 16:57 .
drwxr-xr-x 19 root root       4480 Apr 25 17:50 ..
drwxr-xr-x  2 root root         80 Apr 25 16:57 by-path
crw-rw----  1 root video  226,   0 Apr 25 16:57 card0
crw-rw----  1 root render 226, 128 Apr 25 16:57 renderD128

和原文一样,注意上面出现的数字(195、511、237),这些是之后LXC中需要的,所以先记录下来。

注意: 上述设备缺一不可至少包含:nvidia0、nvidiactl、nvidia-modeset、nvidia-uvm、nvidia-uvm-tools; 少了说明驱动有组件没有安装成功,需要详细检查.

对 LXC 容器进行配置

为了保持容器和宿主机的驱动版本一致,我的容器选用了Debian 12的rootfs,以宿主机一样的方式安装了NVIDIA驱动。

创建好容器后记住容器编号,关闭容器,编辑 /etc/pve/lxc/xxx.conf

我的配置文件内容是这样的

arch: amd64
cores: 8
features: nesting=1
hostname: 3060L
memory: 8192
nameserver: 223.5.5.5
net0: name=eth0,bridge=vmbr0,gw=192.168.145.1,hwaddr=XX:XX:XX:XX:XX:XX,ip=192.168.145.14/24,type=veth
ostype: debian
rootfs: Samsung-980:112/vm-112-disk-0.raw,size=150G
searchdomain: localhost
swap: 8192
unprivileged: 1
添加透传显卡的参数
lxc.cgroup2.devices.allow: c 195:* rwm
lxc.cgroup2.devices.allow: c 511:* rwm
lxc.cgroup2.devices.allow: c 226:* rwm
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
添加tun权限的参数(可选,我要用mihomo的tun全局接管流量,故开启)
lxc.cgroup.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir
检查驱动是否正常工作

运行 nvidia-smi

root@3060L:~# nvidia-smi
Thu Apr 25 14:47:57 2024   
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.15              Driver Version: 550.54.15      CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3060 ...    On  |   00000000:01:00.0 Off |                  N/A |
| N/A   41C    P8             14W /   80W |       1MiB /   6144MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                             
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

如果你的输出也和我上面的一样正常输出了,那么证明你已经成功透传显卡了!恭喜!!!至此,PVE LXC 容器直通显卡工作就圆满结束了!