对于 Proxmox VE 8,需要使用16.0+版本的 vGPU 驱动程序,低版本的驱动程序不支持 Linux 6.x 内核

最近我刚升级了我的 NAS 主机,并且购买了一块 Tesla P4 显卡。我想把 vGPU 分配给虚拟机上的 Jellyfin 容器硬解使用,经过几天的研究,我简单总结了使用方法。关于如何使用硬解,我会在下一篇文章中进行说明。

术语说明

简单介绍后面内容中的几个术语:

  • vGPU

    vGPU 技术通过将硬件 GPU 分割成多个虚拟 GPU 以支持多个虚拟机。每个虚拟 GPU 可以被分配给不同的虚拟机,从而使多个虚拟机拥有“独显”。

  • vGPU-unlock

    从硬件上来看,同代的数据中心显卡和消费者显卡 GPU 架构是一样的,只是驱动层限制了支持的特性。通过修改型号与宿主驱动等方式,将消费级显卡伪装成具有相同核心型号的专业卡,使得普通消费者显卡也可以支持虚拟化;对于虚拟机,同时在 vGPU 启动前后进行 hook,绕过特定检查、汇报虚假结果等,使得虚拟机的 vGPU 能正常启动。目前支持的消费卡型号可以参考此文章。

  • vGPU 授权机制

    在宿主机上,驱动无需授权。不过,只有企业级 GPU 能够被 vGPU 宿主机驱动所识别,消费级显卡无法合法地用于 vGPU 硬件。

    在虚拟机上,使用 vGPU 客户端驱动需要获得 NVIDIA 授权。不同能力的 vGPU 子设备被分为 A、B、C、Q 四类,并对应不同的授权费用。未获得授权的驱动会逐渐降低 vGPU 子设备的性能,最终导致无法使用。

    在几种 vGPU 类型中,覆盖应用场景最广的是 Q 型 vGPU,授权为 vWS。

安装流程

关于 PVE 使用 GPU 有三种方法:

  • 显卡直通
  • 普通显卡 + vGPU-unlock
  • 数据中心显卡 vGPU

Tesla P4 是数据中心卡,原生支持 vGPU 功能,所以本文不涉及 vGPU-unlock,如需了解可以参考 PolloLoco 的 NVIDIA vGPU Guide。

宿主机

  1. 主板 BIOS 配置

    需要开启 IOMMU / VT-d、Above 4G Decoding、SR-IOV,不同的主板选项所在位置可能不同,需要自行查找。

    IOMMU 是一种地址映射技术,而 VT-d 是 Intel 对该技术的别称;Above 4G Decoding 关系到 PCI-E 设备 RAM 的 64 位寻址能力,通常用于需要让 CPU 访问全部显存的场景,使用 vGPU 时推荐开启;SR-IOV 允许一个 PCI-E 设备被多个虚拟机使用,常用于网卡等设备共享。

  2. PVE 宿主机配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 把下面几行追加到 /etc/modules 里,用于加载所需的内核模块
    vfio
    vfio_iommu_type1
    vfio_pci
    vfio_virqfd

    # 屏蔽开源驱动
    echo "blacklist nouveau" >> /etc/modprobe.d/pve-blacklist.conf

    # 开启IOMMU,参考:https://foxi.buduanwang.vip/yj/561.html
    ## AMD主板可能需要修改为:quiet amd_iommu=on iommu=pt pcie_acs_override=downstream,否则部分PCI设备可能会在同一个分组内,直通时会直通整个设备

    # 安装依赖包
    apt install build-essential dkms mdevctl pve-headers-$(uname -r)

    # 重启机器
    reboot
  3. 安装 NVIDIA Host 驱动

    NVIDIA 官网的驱动是非公开的,你需要注册 NVIDIA 商业账户才可访问;当然你也可以去网上寻找驱动包,比如:APQA 网盘、GitHub 等

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 本次安装环境:PVE版本7.4-3,Linux内核版本5.15.107-2,驱动版本15.1
    chmod +x NVIDIA-Linux-x86_64-430.67-vgpu-kvm.run
    ./NVIDIA-Linux-x86_64-430.67-vgpu-kvm.run

    # 安装过程完成后可以使用以下命令验证
    $ dkms status
    nvidia, 525.85.07, 5.15.107-2-pve, x86_64: installed
    $ nvidia-smi
    +-----------------------------------------------------------------------------+
    | NVIDIA-SMI 525.85.07 Driver Version: 525.85.07 CUDA Version: N/A |
    |-------------------------------+----------------------+----------------------+
    | 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 Tesla P4 On | 00000000:81:00.0 Off | 0 |
    | N/A 53C P8 12W / 75W | 1899MiB / 7680MiB | 0% Default |
    | | | N/A |
    +-------------------------------+----------------------+----------------------+

  4. 划分 PCI-E 设备给虚拟机

    通过 mdevctl types | grep '^[^ ]*$' 查看所有生成了 mdev 的 PCI 设备 ID,然后通过 PVE 网页控制台给虚拟机分配 PCI 设备,设备选择刚才查到的设备 ID。该处的 MDev 字段,后面半段的数字为显存容量,字母为 vGPU 类型,这里选 Q 全能型即可,显存按需分配。

    img

虚拟机

下面来到虚拟机的部分,从下载的驱动包内,找到文件名包含 grid 的对应系统驱动包,上传至虚拟机。

  1. Windows

    双击运行直接根据引导安装即可,安装完成后打开 PowerShell,输入命令:

    1
    2
    nvidia-smi.exe # 验证是否安装成功
    nvidia-smi.exe -q | Select-String License # 查看授权,Unlicensed (Unrestricted) 表示未授权

    至此驱动安装已经完成,下一节再来解决授权的问题。

  2. Linux

    此处以 Debian 系统演示,理论兼容 Ubuntu。其他发行版的用户请酌情微调命令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 和宿主安装驱动相似,禁用 nouveau 并安装必须软件包
    echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
    apt install build-essential gcc-multilib dkms mdevctl
    update-initramfs -k all -u
    reboot

    # 重启完成后安装 Guest 驱动
    chmod +x NVIDIA-Linux-x86_64-430.63-grid.run
    ./NVIDIA-Linux-x86_64-430.63-grid.run

    # 验证安装是否成功
    dkms status
    nvidia-smi
    nvidia-smi -q | grep License # 查看授权,Unlicensed (Unrestricted) 表示未授权

    img

至此驱动方面的安装已经完成,下面来获取授权。

授权流程

授权方法分为如下几种方式:

  1. 向 NVIDIA 申请 90 天 free license(NVIDIA 中国只面向企业用户发放免费授权,个人可以尝试去海外官网申请),到期后购买 license
  2. Rust-based vgpu_unlock,通过 vGPU 伪装,从而可以在虚拟机使用不需要授权的消费级显卡驱动,此方式是唯一支持消费级显卡的方式
  3. vGPU_LicenseBypass,此方式将不限制性能的时间从 20 分钟延长为一天,并且每天定时重启驱动,以达成一直不受限的目地,但不适合需要长时间运行 GPU 的场景
  4. FastAPI-DLS,此方式通过模拟正规流程的激活服务器,对虚拟机进行许可证授权,支持容器部署

对于原生支持 vGPU 的显卡而言,使用 FastAPI-DLS 为最优解,整套方案除授权服务器虚假外与正规流程无异。而且只要不更新虚拟机驱动,证书验证算法不变,理论具有等同于正规授权的稳定性。

搭建授权服务器

  1. 首先安装容器环境,此步略过。

  2. 启动容器,原项目需要自行创建证书,这里使用一个二次封装的免证书容器镜像。

    1
    2
    # 此处的DLS_URL与DLS_PORT是后续生成授权文件,告知Guest如何访问授权容器IP地址和端口
    docker run -d -e DLS_URL=10.0.0.6 -e DLS_PORT=443 -p 443:443 makedie/fastapi-dls

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 站点范围的公钥

安装容器 collinwebdesigns/fastapi-dls

1
2
3
4
5
6
7
8
9
10
11
12
# 设定工作目录并创建
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
1
2
# 设定5年证书
docker run -e LEASE_EXPIRE_DAYS=1825 -e DLS_URL=192.168.6.1 -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 生成客户端令牌

获取授权

  1. Windows

    使用管理员身份启动 PowerShell 执行如下命令

    1
    2
    3
    4
    5
    # <ls-hostname-or-ip>为你的授权服务IP端口
    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"

    Restart-Service NVDisplay.ContainerLocalSystem
    nvidia-smi.exe -q | Select-String License # 查看授权状态
  2. Linux

    root 执行如下命令

    1
    2
    3
    4
    5
    # <ls-hostname-or-ip>为你的授权服务IP端口
    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

    service nvidia-gridd restart
    nvidia-smi -q | grep License # 查看授权状态

    img

现在 vGPU 已经可以正常使用了,只要确保授权服务容器正常运行,grid 驱动就会自动续期。

参考文章