Proxmox 7.4 GPU Passthrough 显卡直通
近期AI题材火爆,看着家里一堆闲置吃灰的显卡,想想也应该让他们起来干活了,于是想起来组建一个新的PVE服务器,把显卡用上。又因为显卡虚拟化的支持目前应该还是不太稳定的状态(想来老黄是不可能给消费级显卡官方虚拟化的能力的),而且即使服务器端驱动搞定了,License的问题应该还是会成为绊脚石,所以还是选择了更为稳妥的直通方案。计划是直通显卡给一个Ubuntu server,然后在其上通过Docker部署一些简单的应用。
之前在PVE 7.1以及更早的版本上面已经尝试过显卡直通,而且运行稳定,本以为这次应该是手拿把攥,结果却翻了车。特此记录一下翻车和修正过程。
PVE 7.1以及之前版本的显卡直通步骤
参考:目前最靠谱的帖子,比PVE官方文档清晰很多的reddit reference post
-
先确认BIOS里面已经打开了所有跟虚拟化有关的选项,比如 vt-d,以及IOMMU分组之类的。
-
然后需要确定服务器的启动的Boot loader是使用的 GRUB 还是 System Boot。这方面 PVE 官方有文档 doc。但是解释的不算非常清楚。总结一下:
- 如果启动的时候有看到GRUB的界面让你选择启动的项目,则肯定是 GRUB。
- 如果启动BIOS没有开启UEFI,而且PVE安装的时候选择的是EXT4的文件系统,则基本上肯定是GRUB
- 如果PVE安装时选择的是ZFS的文件系统,则基本上肯定是System Boot
-
确定了Boot loader之后,需要修改对应的文件:
- 如果是GRUB,需要修改文件为 /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT
原本应该是只有 "quite"。- 现在需要改为:
"quiet amd_iommu=on iommu=pt pcie_acs_override=downstream,multifunction nofb nomodeseti video=vesafb:off,efifb:off"
nofb video=vesafb:off,efifb:off
应该是关闭 Framebuffer。不确定是不是必须的。pcie_acs_override=downstream,multifunction
应该是针对消费级主板通病:“稀烂的IOMMU分组”所做的妥协。相当于打开Kernel里面的一个flag,让kernel根据情况override主板上面的IOMMU分组,强行根据功能分组。很多消费级主板上面的IOMMU分组非常糟糕,比如板载的网卡声卡以及一些PCIE借口都在一个分组里。而PCI直通实际都是以组为单位,所以直通的时候,本意是直通一个PCIE插槽,结果把板载网卡通过去了,而HOST母机直接就没有网卡了,这对于服务器来讲基本就挂了。需要注意的是,有时即使有了这个override,也不一定就能成功,之前在ASUS B460M Prime 这个主板上就发生过这个情况,后来发现需要修改并重新编译内核才能解决。- 注意这个不可以代替BIOS设置里面需要打开的IOMMU分组。
amd_iommu=on
这个跟平台有关,如果是Intel的CPU,需要改为intel_iommu=on
才行。- 双引号不可以省略,所有Argument必须在同一行,不要分行。
- 如果是 System Boot,则为 /etc/kernel/cmdline
- 这个文件里面应该只有一行:root=ZFS=rpool/ROOT/pve-1 boot=zfs quite
- 添加的内容跟上面 GRUB 的添加的 CMDLINE 内容一样,但是不要加双引号。同时一样不要换行。
- 如果是GRUB,需要修改文件为 /etc/default/grub
-
更新 grub 或者 system boot 的 image 参考 pve doc reference
- GRUB:
$ update-grub
- System boot:
$ proxmox-boot-tool refresh
- GRUB:
-
添加VFIO模块 (VFIO Modules)
- 添加以下内容到 /etc/modules
- IOMMU的中断映射
-
把GPU添加到VFIO里面
- 这一步需要首先找到GPU确切的Vendor ID
- 首先运行
$ lspci -v | less
,在里面找到VGA的段落。肯定有个类似 01:00.0 这种格式的号。 - 然后利用这个号码列出详情
$ lspci -n -s 01:00
,这次不会输出很多,只会输出01:00相关设备的设备号。 - 之后要把这个设备号添加进VFIO
-
查询所有PCI设备
- 列出01:00所有设备号(通常显卡都在01:00)
- 添加GPU设备到VFIO
- 更新 initramfs 并重启
- 确认IOMMU分组可以用这个script将所有的IOMMU分组全部打印出来。
-
指定GPU给虚拟机,并修改虚拟机配置文件来保证虚拟机里面使用显卡的时候,不会被驱动识别出当前是虚拟机环境进而停止工作
- 通过UI改:虚拟机的machine type应该为Q35。否则在指定PCI设备的时候无法选中PCI-E选项。
- 这个需要在创建虚拟机的时候调,印象中在创建之后就不能改了。
- 配置文件位置为
/etc/pve/qemu-server/<vmid>.conf
:cpu: host,hidden=1,flags=+pcid
args: -cpu 'host,+kvm_pv_unhalt,+kvm_pv_eoi,hv_vendor_id=NV43FIX,kvm=off'
- 之后就在WEB UI:虚拟机Hardware tab下,添加PCI设备,这个时候应该是可以找到GPU设备进行分配的。
- 如果出现
No IOMMU detected, please activate it.
的警告,说明BIOS上面的IOMMU分组没开,或者kernel cmdline上面没有添加amd_iommu=on
或者intel_iommu=on
,或者干脆就是缺一次重启。
- 如果出现
- 在指定GPU给虚拟机的时候,大体如下(这里也可以选择 all function,只不过就是会同时把GPU上面的那个音频设备同时直通进去;另外如果不链接显示器作游戏机的话,没有太大必要把Primary GPU选上,一旦选上之后,虚拟机的主显示输出就改为了这个GPU,此时如果系统是桌面系统,那么在Proxmox的WebUI的console里面就看不到桌面了)
- 通过UI改:虚拟机的machine type应该为Q35。否则在指定PCI设备的时候无法选中PCI-E选项。
-
ROM相关 参考Reddit上面的步骤
- 这部分因为没有用到过,所以没有尝试过,所以省略过去。
-
验证
- 在VM里面(我用的是Ubuntu 22.04),应该是可以直接安装Nvidia的驱动的。
$ sudo apt-get install nvidia-driver-525
- Test result:
$ nvidia-smi
(可能需要重启)
- 如果是 Debian (tested on debian 11 aka bullseye)
- Add
non-free
package sources to in/etc/apt/sources.list
- By default the content should be like:
deb http://ftp.ca.debian.org/debian bullseye main contrib
- Change it to
deb http://ftp.ca.debian.org/debian bullseye main contrib non-free
- Do the same for both
bullseye
andbullseye-updates
- By default the content should be like:
- Add
$ apt update && apt install nvidia-detect && nvidia-detect
。通常来讲输出会说让你安装nvidia-driver
,至于版本应该是自动选择的。$ apt install nvidia-driver
。之后可能需要重启然后用nvidia-smi
验证。
- 在VM里面(我用的是Ubuntu 22.04),应该是可以直接安装Nvidia的驱动的。
升级到PVE 7.2之后的翻车
(实测在7.4的版本上是翻车了,没有实地验证是不是7.2也会翻车)
按照之前的步骤,在虚拟机里面也确定了nvidia-smi
可以输出正确的内容。但是,尝试使用Jellyfin硬解,结果是hang。一番折腾之后发现应该还是直通出现了问题。
我这里是用Jellyfin的ffmpeg试图进行硬解的时候发现了,检测的方法是:
- 安装 Jellyfin
- 使用Jellyfin的FFmpeg测试CUDA硬件加速
- 同样在尝试其他使用CUDA的app也会卡死。
之所以发现是Passthrough的问题,是因为Debug的时候尝试在PVE母机(Debian)上面直接安装Jellyfin,同样的ffmpeg测试就顺利通过。至此确定是GPU Passthrough的问题。