Proxmox使用LXC共享宿主机GPU

发布于 2024-09-02  219 次阅读


背景介绍

由于最近在给实验室的算力机重装系统进行资产管理,需要能对单张显卡算力进行共享,但是由于实验室中的显卡多为消费级显卡,唯二的两张A6000支持vGPU,但是Nvidia的vGPU需要购买授权,因此vGPU这条路走不通,KVM方式虚拟化算例方案也被放弃

LXC本质上是宿主机的一个命名空间,没有独立的内核,也就不存在设备需要被虚拟化直通进虚拟机的问题,因此使用LXC可以通过映射宿主机设备文件的方式让LXC得到GPU加速。同时,可以将一个显卡的设备文件映射给多个LXC算例,本质上相当于宿主机运行多个GPU程序,不需要GPU支持虚拟化的情况下,能够让多个用户共享显卡算力,理论上A卡,N卡甚至摩尔线程卡均支持此种方法

同时,LXC相比KVM,宿主机拥有更多的管理权,如能通过pct直接进入LXC执行命令而无需LXC密码;可以很方便的调控LXC的内存和使用CPU和核数而无需重启;可以直接增减网卡、配置网卡的IP而无需配置cloud-init或通知用户来修改

因此最终的方案选择LXC配合映射设备文件实现共享GPU

已知的问题

Proxmox的LXC对单一网络栈多网关可能有异常,当把单一网络栈的不同网关配置在不同的网络接口上时,LXC的网络可能会失效,表现为几乎ping不通

LXC与宿主机的Nvidia驱动版本需要一致,要同时更新LXC和宿主机驱动,需要重启宿主机才能完成更新

PVE8安装器对N卡驱动可能存在问题,加载时会卡住,可以尝试先安装Debian12,再安装PVE

虽然GPU是直通的,但是终归和宿主机有区别,使用nvidia-smi在LXC中不会看到任何进程,即使是LXC自己的,但是在宿主机可以看到

操作步骤

禁用Nouveau驱动

nouveau是N卡的开源驱动,由Nvidia对开源驱动的不贡献,我们需要安装nvidia专有驱动,因此我们要先禁用PVE自带的nouveau的驱动


echo "blacklist nouveau" >> /etc/modprobe.d/blacklist-nouveau.conf
echo "options nouveau modeset=0" >> /etc/modprobe.d/blacklist-nouveau.conf
sudo update-initramfs -u
reboot

系统重启后即禁用了Nouveau驱动

安装Nvidia驱动

通过下列命令来安装适合当前PVE版本的内核头和相关的软件包,内核头文件包含源代码编译并与特定内核版本正确配合使用所需的必要头文件和符号,Nvidia驱动程序使用 C/C++ 代码(GNU 编译器集合)和 Vulkan 图形(用于 3D 图形和渲染的跨平台 API)

apt install pve-headers-$(uname -r) make gcc libvulkan1 pkg-config dkms

安装完成后,从https://www.nvidia.com/download/index.aspx下载最新的 Nvidia 驱动程序,截止本文攥写时,本文所在环境的最新驱动文件名为NVIDIA-Linux-x86_64-550.107.02.run,使用任何方法将驱动程序上传到PVE磁盘中,本文上传路径为/root/NVIDIA-Linux-x86_64-550.107.02.run

chmod +x NVIDIA-Linux-x86_64-550.107.02.run
./NVIDIA-Linux-x86_64-550.107.02.run --no-questions --disable-nouveau

此命令将使用安静模式安装,不会提示不必要的问题:(跳过辅助卡、无 32 位、无 X),一路回车即可,注意将驱动注册为DKMS,这样在更新PVE内核时能够自动重新编译Nvidia内核模块

使用 udev 规则启用 NVIDIA 驱动程序

为了使系统启动时加载正确的驱动程序,我们需要使用udev规则

echo "nvidia" >> /etc/modules-load.d/modules.conf
echo "nvidia_uvm" >> /etc/modules-load.d/modules.conf
echo "nvidia-drm" >> /etc/modules-load.d/modules.conf
echo "nvidia-uvm" >> /etc/modules-load.d/modules.conf
sudo update-initramfs -u -k all

上述命令将指导内核在启动时加载nvidia驱动

新建udev规则

vim /etc/udev/rules.d/70-nvidia.rules

在此文件中添加以下行

KERNEL=="nvidia", RUN+="/bin/bash -c '/usr/bin/nvidia-smi -L && /bin/chmod 666 /dev/nvidia*'"
KERNEL=="nvidia_uvm", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -u && /bin/chmod 0666 /dev/nvidia-uvm*'"
SUBSYSTEM=="module", ACTION=="add", DEVPATH=="/module/nvidia", RUN+="/usr/bin/nvidia-modprobe -m"

为了防止 Nvidia 驱动程序/内核文件在 GPU 未使用时停止,我们还要安装Nvidia持久性服务

sudo cp /usr/share/doc/NVIDIA_GLX-1.0/samples/nvidia-persistenced-init.tar.bz2 .
tar -xjf nvidia-persistenced-init.tar.bz2
rm /etc/systemd/system/nvidia-persistenced.service
sudo ./nvidia-persistenced-init/install.sh
systemctl status nvidia-persistenced.service
rm -rf nvidia-persistenced-init*

如果持久性服务安装正确,内核更新正确,我们可以重启PVE,此时输出nvidia-smi应该能够看到类似

+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.107.02             Driver Version: 550.107.02     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 RTX A6000               Off |   00000000:01:00.0 Off |                  Off |
| 30%   59C    P0             N/A /  300W |       1MiB /  49140MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

输入systemctl status nvidia-persistenced

● nvidia-persistenced.service - NVIDIA Persistence Daemon
     Loaded: loaded (/lib/systemd/system/nvidia-persistenced.service; enabled; preset: enabled)
     Active: active (running) since Mon 2024-09-02 15:42:09 CST; 1min 36s ago
    Process: 3930961 ExecStart=/usr/bin/nvidia-persistenced --user nvidia-persistenced (code=exited, status=0/SUCCESS)
   Main PID: 3930962 (nvidia-persiste)
      Tasks: 1 (limit: 76805)
     Memory: 324.0K
        CPU: 803ms
     CGroup: /system.slice/nvidia-persistenced.service
             └─3930962 /usr/bin/nvidia-persistenced --user nvidia-persistenced

Sep 02 15:42:08 Server-10-191-72-108 systemd[1]: Starting nvidia-persistenced.service - NVIDIA Persistence Daemon...
Sep 02 15:42:08 Server-10-191-72-108 nvidia-persistenced[3930962]: Started (3930962)
Sep 02 15:42:09 Server-10-191-72-108 systemd[1]: Started nvidia-persistenced.service - NVIDIA Persistence Daemon.

输入ls -alh /dev/nvidia*,如果正确安装了驱动,则会显示类似

crw-rw-rw- 1 root root 195,   0 Jul 14 23:58 /dev/nvidia0
crw-rw-rw- 1 root root 195, 255 Jul 14 23:58 /dev/nvidiactl
crw-rw-rw- 1 root root 195, 254 Sep  2 15:42 /dev/nvidia-modeset
crw-rw-rw- 1 root root 508,   0 Jul 14 23:58 /dev/nvidia-uvm
crw-rw-rw- 1 root root 508,   1 Jul 14 23:58 /dev/nvidia-uvm-tools

/dev/nvidia-caps:
total 0
drwxr-xr-x  2 root root     80 Jul 14 23:58 .
drwxr-xr-x 21 root root   4.8K Sep  2 15:42 ..
cr--------  1 root root 511, 1 Jul 14 23:58 nvidia-cap1
cr--r--r--  1 root root 511, 2 Jul 14 23:58 nvidia-cap2

其中/dev/nvidia0是你的显卡设备文件

至此我们完成了Nvidia驱动及相关准备工作

配置LXC

本文不再赘述LXC新建流程,假定目标LXC的VM ID为101

vim /etc/pve/lxc/101.conf

在文末加入下列代码

lxc.cgroup2.devices.allow: c 195:* rwm
lxc.cgroup2.devices.allow: c 508:* 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

注意到其中有两个cgroup,末尾分别为195:* rwm和508:* rwm,其中的数字为ls -alh /dev/nvidia*中/dev/nvidia-caps之前的内容的第五列,本文中为195和508,你要是喜欢可以把nvidia-cap的511也加入到LXC配置中,这些数字每台机器都不一样,注意根据自己实际情况填写,添加不存在的数字并不会让LXC报错

lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file指将GPU ID为0的nvidia显卡映射到LXC的dev/nvidia0,也就是和宿主机一样的设备文件目录下,如果有多个GPU,可以依次添加如nvidia1,nvidia2等

至此,我们可以尝试启动LXC

为LXC安装nvidia驱动

LXC安装过程与宿主机稍有区别,由于LXC没有独立内核,共享宿主机内核(此时宿主机内核已有Nvidia内核模块),我们不需要驱动安装程序安装内核文件

使用pct命令将宿主机驱动安装包推送至LXC

pct push 101 NVIDIA-Linux-x86_64-550.107.02.run  /root/NVIDIA-Linux-x86_64-550.107.02.run

在LXC中运行下列命令,使用pct exec 101 bash进入LXC命令行

chmod +x NVIDIA-Linux-x86_64-550.107.02.run
./NVIDIA-Linux-x86_64-550.107.02.run --no-kernel-module --no-questions

仍然一路回车即可,安装完成后重启LXC,并在LXC执行ls -alh /dev/nvidia*,查看设备文件是否直通成功

crw-rw-rw- 1 nobody nogroup 195, 254 Sep  1 10:47 /dev/nvidia-modeset
crw-rw-rw- 1 nobody nogroup 508,   0 Sep  1 10:47 /dev/nvidia-uvm
crw-rw-rw- 1 nobody nogroup 508,   1 Sep  1 10:47 /dev/nvidia-uvm-tools
crw-rw-rw- 1 nobody nogroup 195,   0 Sep  1 10:47 /dev/nvidia0
crw-rw-rw- 1 nobody nogroup 195, 255 Sep  1 10:47 /dev/nvidiactl

/dev/nvidia-caps:
total 0
drwxr-xr-x 2 root root  40 Sep  1 10:49 .
drwxr-xr-x 7 root root 600 Sep  1 10:49 ..

执行nvidia-smi

Mon Sep  2 08:07:53 2024       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.107.02             Driver Version: 550.107.02     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 RTX A6000               Off |   00000000:01:00.0 Off |                  Off |
| 30%   31C    P8             16W /  300W |       2MiB /  49140MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

结语

如果至此您没有遇到任何问题,说明本文内容还没有失效,您已成功配置了使用LXC共享显卡算力,您可以依次创建多个LXC并将它们分给不同的用户使用