跳转至

vGPU教程

准备工作

其实这部分主要参考前面的两个章节的配置完全就可以了:

下面默认大家是看过并配置过这两个章节内容的,所以就不详细解释了。

BIOS 设置

  • 开启 Intel VMX 虚拟化技术(PCIe 件直通必须)
  • 开启 VT-d (PCIe 件直通必须)
  • 开启 SR-IOV 网卡虚拟化技术 (高效先进的虚拟机网卡技术)
  • 开启 Above 4G Decoding(vGPU 方案需要开启这个选项)
  • 开启 Numa (多路 CPU 建议开启,提高多路 CPU 运行效率,合理分配负载)
  • 开启 x2APIC(PCIe 硬件直通需要)

依赖包安装

首先将可以升级的软件升级到最新版本:

Bash
apt update
apt dist-upgrade

然后安装相关的依赖包,以及升级最新的 PVE Linux 内核:

Bash
apt install -y build-essential dkms pve-headers mdevctl

配置内核

我们必须加载内核模块才能使 vGPU 工作:

Bash
echo vfio >> /etc/modules 
echo vfio_iommu_type1 >> /etc/modules 
echo vfio_pci >> /etc/modules 
echo vfio_virqfd >> /etc/modules

阻止 Proxmox 自带的 Nvidia GPU 的开源新驱动程序:

Bash
echo "blacklist nvidiafb" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nvidia" >> /etc/modprobe.d/blacklist.conf
echo "blacklist radeon" >> /etc/modprobe.d/blacklist.conf
echo "blacklist amdgpu" >> /etc/modprobe.d/blacklist.conf
echo "blacklist snd_hda_intel" >> /etc/modprobe.d/blacklist.conf
echo "blacklist snd_hda_codec_hdmi" >> /etc/modprobe.d/blacklist.conf
echo "blacklist i915" >> /etc/modprobe.d/blacklist.conf

应用我们的内核配置并重启:

Bash
update-initramfs -u -k all && reboot

驱动安装

首先需要 PVE 宿主机安装 NVIDIA 的驱动,但是 N 卡的计算卡只针对企业商业用户并不开放给普通个人用户下载,所以我们得注册 NVIDIA 的企业账号登录才可以下载,具体可以参考 NVIDIA 官网文档:

Quick Start Guide :: NVIDIA Virtual GPU Software Documentation

但是这个官方文档写的比较蛋疼,国内的用户大家直接看我下面的细节操作就行了。

企业账号

注册的时候尽量不要使用 gmail.com 或者 qq.com 等通用个人邮箱服务,人工审核大概率不通过。国光建议大家考虑使用域名邮箱或者其他企业的邮箱,这里我使用的是自己网站的域名邮箱: [email protected],总的来说国内申请注册 NVIDIA 企业账户还是比较繁琐的。

下面是国光我注册的时候填写的大概信息:

主要记住如下一些点:

  1. 选择台湾地区,国光认为这是 NVIDIA 的老家,成功率应该高一点
  2. 选择 IT Service 信息服务行业
  3. 职位选择:学生,毕竟我是学生记得多塞 200 块钱的梗,全世界基本上如此
  4. 服务器选择国内的:Lenovo、VDI 选择 RedHat 虚拟化,记得规模选择 1-99 越小越好,大规模可能真的会被电话核实
  5. 总之,低调一点,毕竟我们是白嫖,不要加装自己真的是个大的企业用户就行

注册申请提交后,可以看到大概需要 24-48 小时的时间:

实际上我们不需要等待 24-48 小时,顺利的话,1小时不到就可以接收到 NVIDIA 的邮件:

主要就是这个「NVIDIA Set Pasword」邮件, 我们点进去,选择 「SET PASSWORD」设置账户密码:

URL 里面会自带 Token 认证,然后我们可以直接设置我们 [email protected] 的密码:

接着使用我们的账号和密码登录:NVIDIA许可门户网站

直接打开「SOFTWARE DOWNLOADS」下载页面:https://ui.licensing.nvidia.com/software

但是筛选 VGPU 发现最新的只有 vGPU 14.4 版本的驱动,这个要吐槽一下,最新的没有直接展出出来,还需要我们手动筛选一下平台为「Linux KVM」,这就可看到最新的 v15.0 的驱动了,如果还没出现的话,我们再多添加几个条件筛选即可:

但是官网这个下载驱动包的链接应该是存在鉴权时间的,国光我贴到文章里面的话,后期链接失效就有的我改了:

那大家无法注册企业账号该怎么办呢?不要担心,我们继续往下看。

驱动分享

没有企业账号也没关系,网上很多热心网友也有分享过驱动的下载链接:

驱动安装

解压内容只要包含 Host 主机驱动和各个平台的客户端驱动:

这里我们将 Host 驱动 NVIDIA-Linux-x86_64-525.60.12-vGPU-kvm.run 上传到 PVE 上准备安装。

因为我们的 Tesla P4 是完全支持 vGPU 的:

显卡原生不支持 vGPU ? 不要慌,国光我会出手:

如果你的卡不在 NVIDIA® Virtual GPU 官方列表中的话:NVIDIA® Virtual GPU Software Supported GPUs,但是在下图中可以找到你的设备的话

也不要灰心,参考文章下面的参考链接:PolloLoco / NVIDIA vGPU Guide 也可完成。

安装门槛就降低了很多我们可以直接安装:

Bash
chmod +x NVIDIA-Linux-x86_64-525.60.12-vgpu-kvm.run 
./NVIDIA-Linux-x86_64-525.60.12-vgpu-kvm.run --dkms

因为国光我已经安装过了,这里提示了是否继续安装,我们选择继续安装就行了:

开始 Build 构建内核模块,等待完成:

解决安装报错:Unable to load the kernel module 'nvidia.ko'

参考上面的操作,我们大概率会遇到下面图上的这个报错:

不要慌,国光我会出手!经过多次测试,发现和 vfio.conf 文件里面的配置存在冲突,我们直接删掉即可:

Bash
rm /etc/modprobe.d/vfio.conf

如果构建没问题的话,后面基本上都会比较顺利,接着开始安装驱动:

驱动安装好后,提示:是否要注册 DKMS 模块,那肯定选择「Yes」了:

之后提示安装完成:

安装完成后重启即可生效。

验证驱动

通过检查内核加载模块列表中的 VFIO 驱动程序来验证 NVIDIA VGPU 软件包是否已正确安装和加载:

Bash
lsmod |grep vfio 

查看平台中所有 NVIDIA GPU的概览信息:

Bash
nvidia-smi

正常识别到了我们的 Tesla P4 下显卡:

因为上图还显示了我们的 RTX 3060 和 GT 630 显卡,我们还可以使用下面的精简命令单独查看 vGPU 相关的显卡:

Bash
nvidia-smi vgpu

查询我们 GPU 支持的 mdev 类型列表:

Bash
ls /sys/class/mdev_bus/*/mdev_supported_types 

以及这些类型可支持的 vGPU 数量:

Bash
cat /sys/class/mdev_bus/*/mdev_supported_types/*/available_instances

以上两个命令也可以使用下面一条命令查看:

Bash
mdevctl types

其实这块就正对应着 PVE Web UI 里面的现在这个界面:

下表是国光整理的对这各个Tesla P4 支持的 vGPU 的 MDev 类型的解释(共支持14种类型):

类别 代号 最大实例数 解释
GRID P4-1Q nvidia-63 8 1GB 显存,最大分辨率为:5120x2880
GRID P4-2Q nvidia-64 4 2GB 显存,最大分辨率为:7680x4320
GRID P4-4Q nvidia-65 2 4GB 显存,最大分辨率为:7680x4320
GRID P4-8Q nvidia-66 1 8GB 显存,最大分辨率为:7680x4320
GRID P4-1A nvidia-67 8 1GB 显存,最大分辨率为:1280x1084
GRID P4-2A nvidia-68 4 2GB 显存,最大分辨率为:1280x1084
GRID P4-4A nvidia-69 2 4GB 显存,最大分辨率为:1280x1084
GRID P4-8A nvidia-70 1 8GB 显存,最大分辨率为:1280x1084
GRID P4-1B nvidia-71 8 1GB 显存,最大分辨率为:5120x2880
GRID P4-1B4 nvidia-243 8 不推荐使用,未来可能会被移除
GRID P4-2B nvidia-157 4 2GB 显存,最大分辨率为:5120x2880
GRID P4-2B4 nvidia-214 4 不推荐使用,未来可能会被移除
GRID P4-4C nvidia-288 2 4GB 显存,最大分辨率为:4096x2440
GRID P4-8C nvidia-289 1 1GB 显存,最大分辨率为:4096x2440

其中我们注意到了类似里面的:1、2、4、8 这几个数字,这个表示这 vGPU 的显存,所以 1 开头的可用数量为 8,毕竟 Tesla 只有 8GB 显存,这个还是比较容易理解的。肯定还有小伙伴好奇这个:A、B、C、Q 是啥意思呢?这其实代表着 vGPU 的几个不通系列,下表是 NVIDIA 官方 PDF 里面的解释:

系列 最大帧数 解释说明
Q 60FPS 兼顾 Quadro 技术的性能和特点
C 60FPS 为计算密集型服务器提供高性能计算
B 45FPS 面向业务专员和知识工作者提供虚拟桌面
A 60FPS 提供针对虚拟机应用程序用户的应用程序流的会话相关解决方案
国光小课堂:vGPU 许可证相关

NVIDIA vGPU 需要软件许可证才能启用 Guest 来宾 VM 中的所有 vGPU 功能,许可证类型取决于 vGPU 类型。

  • Q 系列 vGPU 类型需要 vWS 许可证
  • C 系列的 vGPU 类型需要 NVIDIA 虚拟计算服务器 vCS 许可证,但也可以与 vWS 许可证一起使用
  • B 系列 vGPU 类型需要使用 vPC 许可证,但也可以与 vWS 许可证一起使用
  • A 系列 vGPU 类型需要 vApps 许可证

vGPU 添加

通过上面的章节,我们大概了解到了 vGPU 的 MDev 类型,我们直接像添加 PCI 设备那样,给 VM 添加对应的 MDev 类型的 VGPU 即可:

如果如果您的 PVE 服务器版本低于 7.2-4,则还得添加额外的参数到虚拟机的配置文件中才可以:

Bash
qm set VMID -args '-uuid <UUID-OF-THE-MDEV>' 

因为国光我的这个实验环境是 PVE 7.3 版本,所以这一步就展开说了,感兴趣的网友可以自行去谷歌一下。

此时打开我们的 VM 发现并没有识别到我们的 vGPU 显卡:

这是因为没有安装 Guest 驱动的原因,我们将 527.41_grid_win10_win11_server2019_server2022_dch_64bit_international.exe 传输到我们的 VM 里面:

等待驱动的安装完成即可,安装的过程可以看到已经识别到了我们的 Tesla P4 显卡了:

虽然我们的 P4 可以直接使用了,但是使用命令查看发现我们的 Lincense 依然是未激活的:

Text Only
nvidia-smi -q |findstr Lincese

使用一段时候 Windows 右下角也会弹窗提示:NVIDIA 许可证不存在

关于这块的限制有哪些,国光我单独放到了下一小节来叙述。

vGPU 限制

那么肯定有小伙伴们好奇 vGPU 不存在有哪些缺点和限制呢?这块国光我测试过很多,在配合 NVIDIA 官方 和群友的情况下,最终也找到了一点点规律。

如果不激活 vGPU 的话,随着开机运行时间的推移,帧数会逐渐下降,分为几个档位,从 60FPS 降到 15FPS 最终会非常卡顿只有 3FPS:

而且 CUDA 功能也无法使用,为了验证 CUDA 是否正常使用,我们首先安装 NVIDIA CUDA 工具包,虽然 GPU-Z 软件显示支持 CUDA,但是如果未激活长时间使用的话,通过 N 卡官方的 dmeo (注意自己版本的路径)测试并不能顺利运行:

Bash
"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\extras\demo_suite\bandwidthTest.exe"

如果最后都显示 Result = PASS 则说明 CUDA 安装成功且正常工作。

所以 demo 里面调用 CUDA 的 exe 测试小程序也无法正常运行:

Bash
"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\extras\demo_suite\oceanFFT.exe"

vGPU 激活

安装容器

vGPU 目前国外已经有成熟的 fastapi-dls 开源项目可以直接使用了,官方还贴心了封装了 docker 容器。

DockerHub 的 fastapi-dls 的容器地址是:https://hub.docker.com/r/collinwebdesigns/fastapi-dls

根据官方的 README 来创建容器:

Bash
# 设定工作目录并创建
WORKING_DIR=/opt/docker/fastapi-dls/cert
mkdir -p $WORKING_DIR

# 生成相关证书
cd $WORKING_DIR
openssl genrsa -out $WORKING_DIR/instance.private.pem 2048 
openssl rsa -in $WORKING_DIR/instance.private.pem -outform PEM -pubout -out $WORKING_DIR/instance.public.pem
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout  $WORKING_DIR/webserver.key -out $WORKING_DIR/webserver.crt

# 创建容器的官方建议命令
docker run -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/app/cert collinwebdesigns/fastapi-dls:latest
Docker 启动相关的其他相关的变量
变量 默认 用法
DEBUG false 切换调试模式 fastapi
DLS_URL localhost 客户端访问 dls 实例的 URL 地址
DLS_PORT 443 dls 实例的端口 192.168.1.6
LEASE_EXPIRE_DAYS 90 证书签发时间(天)
DATABASE sqlite:///db.sqlite 细节参考官方 SQLAlchemy 文档
CORS_ORIGINS https://{DLS_URL} 设置标头 Access-Control-Allow-Origin
SITE_KEY_XID 00000000-0000-0000-0000-000000000000 站点标识 uuid
INSTANCE_REF 00000000-0000-0000-0000-000000000000 实例标识 uuid
INSTANCE_KEY_RSA /cert/instance.private.pem JWT 相关的 RSA 密钥
INSTANCE_KEY_PUB /cert/instance.public.pem 站点范围的公钥

实际上我们主要关注一下 DLS_URL 参数,换成自己的 Guest 来宾客户端可以访问到的 IP 地址即可,然后改一下授权时间为 1825 天(5年),下面是国光我最终的创建容器的命令:

Bash
docker run -e LEASE_EXPIRE_DAYS=1825 -e DLS_URL=192.168.1.6 -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/app/cert collinwebdesigns/fastapi-dls:latest

容器接口

下表只列出了主要的接口,更详细的接口可以参考 /-/docs/-/redoc 的 PATH 接口文档。

请求方法 PATH 解释说明
GTE / 重定向到 /-/readme
GTE /-/health 用于运行状况检查,还显示当前版本和提交哈希。
GTE /-/readme HTML 页面展示 README.md
GTE /-/docs GET /-/openapi.json 展示 Swagger UI 页面的接口文档
GTE /-/redoc GET /-/openapi.json 展示 ReDoc 页面的接口文档
GTE /-/manage 显示用于删除源或租约的非常基本的 UI
GTE /-/origins?leases=false 列出注册的原产地,origin 参数指的是包括每个租约的引用源
DELETE /-/origins 删除所有源及其租约
GTE /-/leases?origin=false 列出当前租约,origin 参数指的是包括每个租约的引用源
DELETE /-/lease/{lease_ref} 删除租约
GTE /client-token 生成客户端令牌

续约授权

  • Windows

首先请求生成客户端令牌的接口 /client-token 拿到授权文件:

然后放入到下面的路径:

Bash
C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken

重启电脑即可看到我们的 Guest 来宾客户端已经正常拿到授权了:

也可以使用命令行查看授权细节:

Bash
nvidia-smi -q |findstr Lincese

  • Linux

Linux 使用下面命令下载授权文件到 /etc/nvidia/ClientConfigToken/ 下然后重启服务即可:

Bash
# 下载授权文件
curl --insecure -X GET https://<dls-hostname-or-ip>/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token.tok
service nvidia-gridd restart

# 查看授权细节
nvidia-smi -q | grep "License"

新的姿势

官方的 Docker 镜像好像有一点更新,重新补充一下新的方法和姿势。

Bash
# 拉取最新镜像
docker pull collinwebdesigns/fastapi-dls:latest

# 创建目录
mkdir -p /opt/docker/fastapi-dls/cert
cd /opt/docker/fastapi-dls/cert

# 为 JWT 签名生成公私钥
openssl genrsa -out /opt/docker/fastapi-dls/cert/instance.private.pem 2048 
openssl rsa -in /opt/docker/fastapi-dls/cert/instance.private.pem -outform PEM -pubout -out /opt/docker/fastapi-dls/cert/instance.public.pem

# 为 Web 服务器生成 SSL 证书
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout  /opt/docker/fastapi-dls/cert/webserver.key -out /opt/docker/fastapi-dls/cert/webserver.crt

# 配置创建容器 `hostname -i` 换成自己的 IP 即可
docker volume create dls-db
docker run -d --restart=always -e LEASE_EXPIRE_DAYS=1825 -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v /opt/docker/fastapi-dls/cert:/app/cert -v dls-db:/app/database collinwebdesigns/fastapi-dls:latest
  • Linux 客户端激活

然后 Linux 客户端使用下面命令下载导入许可到/etc/nvidia/ClientConfigToken 文件夹中:

Bash
curl --insecure -L -X GET https://<dls-hostname-or-ip>/-/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok
# 或者
wget --no-check-certificate -O /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok https://<dls-hostname-or-ip>/-/client-token

接着重启 nvidia-gridd service 服务:

Bash
service nvidia-gridd restart
  • Windows 客户端激活

使用管理员权限运行 Powershell,使用下面命令导入许可到 C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken文件夹中:

Text Only
curl.exe --insecure -L -X GET https://<dls-hostname-or-ip>/-/client-token -o "C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken\client_configuration_token_$($(Get-Date).tostring('dd-MM-yy-hh-mm-ss')).tok"

接着重启 NVDisplay.ContainerLocalSystem 服务:

Bash
Restart-Service NVDisplay.ContainerLocalSystem

参考链接


最后更新: 2023-03-06