vGPU (Virtual GPU) 為Nvidia推出的GPU虛擬化技術,能夠Linux上的一張GPU顯示卡分配給多個虛擬機使用,如此一來可提昇QEMU/KVM虛擬機的圖形效能。
圖例,Linux宿主機與Windows虛擬機共享GPU
圖例,Linux宿主機與Linux虛擬機共享GPU
「GPU虛擬化」跟「GPU直通」不一樣,後者是直接將Linux宿主機的GPU封印,透過VFIO分配給虛擬機使用,一次只能有一個虛擬機使用GPU,宿主機無法存取GPU。
若是採用GPU虛擬化的話,宿主機就能和虛擬機共享同一個GPU的資源了。宿主機的GPU可以分割給多個虛擬機使用,這樣就能讓多個虛擬機跑CUDA啦。
不過,目前Nvidia官方僅將vGPU功能開放給伺服器GPU使用,而且需要購買授權。一般消費級的Nvidia GPU雖然硬體支援vGPU,但是vGPU是無法使用的。故我們得使用第三方開發者製作的「vgpu_unlock」程式解鎖該功能,並用自架的「FastAPI-DLS」伺服器取得Nvidia vGPU的授權。
網路上有關這方面操作的教學多半是跑Proxmox,我參考了Nvidia和Ubuntu的官方文件,將其轉化為Ubuntu + QEMU/KVM + Libvirt的版本,可供Ubuntu桌面版用戶參考。
整個啟用過程有點麻煩,你需要很熟悉Linux Nivdia驅動的安裝與解除安裝方式,不然的話搞砸了可能得整個系統要重裝。
1. vgpu_unlock支援的GPU#
目前vgpu_unlock支援的GPU型號為:
- Maxwell架構 (GTX 9xx, Quadro Mxxxx, Tesla Mxx),GTX 970除外
- Pascal架構 (GTX 10xx, Quadro Pxxxx, Tesla Pxx)
- Turing架構 (GTX 16xx, RTX 20xx, Txxxx)
Ampere架構 (RTX30xx) 以上的GPU尚未支援。
2. 測試環境#
- 宿主機:Ubuntu 24.04 LTS
- Linux 核心版本:6.5.0-35-generic
- CPU:Intel® Core™ i5-7400
- GPU 1:Intel® UHD Graphics 630
- GPU 2:NVIDIA GeForce GTX 1050 Ti
- Nvidia vGPU驅動版本:535.183.04
- 虛擬機系統1:Ubuntu Server 24.04 LTS
- 虛擬機系統2:Windows Server 2022
由於vGPU啟用後可能會暫時讓電腦螢幕沒畫面,因此在啟用vGPU之後就要改成使用內顯或者SSH登入了。
3. 安裝QEMU/KVM與Libvirt#
請先設定好虛擬化套件。
參考: Ubuntu安裝QEMU/KVM和Virt Manager虛擬機管理員
4. 啟用IOMMU與VFIO#
- 編輯GRUB開機選項
sudo vim /etc/default/grub
- 針對Intel CPU,在
GRUB_CMDLINE_LINUX_DEFAULT
後面加入以下內容,啟用IOMMU
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on iommu=pt"
- 設定開機載入VFIO核心模組
echo -e "vfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd" | sudo tee -a /etc/modules
- 將Nvidia開源驅動加入黑名單
echo "blacklist nouveau" | sudo tee -a /etc/modprobe.d/blacklist.conf
- 刪除目前系統的全部Nvidia驅動
sudo apt purge *nvidia*
- 更新initramfs和GRUB並重開機
sudo update-initramfs -u -k all
sudo update-grub
sudo reboot
- 進入電腦的UEFI設定,設定為以內顯優先開機。
5. 設定vgpu_unlock解鎖服務#
Matthew Bilker的「vgpu_unlock-rs」為基於Jonathan Johansson的vgpu_unlock所開發的程式,它能夠將GPU偽裝成為支援vGPU的型號。
- 安裝Rust,編譯解鎖工具vgpu_unlock-rs
cd ~
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env
git clone https://github.com/mbilker/vgpu_unlock-rs.git
cd vgpu_unlock-rs
cargo build --release
cd ..
sudo mv gpu_unlock-rs /opt
- 建立vgpu_unlock-rs所需的檔案
sudo mkdir -p /etc/vgpu_unlock
sudo touch /etc/vgpu_unlock/profile_override.toml
- 建立開機自動啟動的Systemd服務
sudo mkdir /etc/systemd/system/{nvidia-vgpud.service.d,nvidia-vgpu-mgr.service.d}
echo -e "[Service]\nEnvironment=LD_PRELOAD=/opt/vgpu_unlock-rs/target/release/libvgpu_unlock_rs.so" | sudo tee -a /etc/systemd/system/nvidia-vgpud.service.d/vgpu_unlock.conf
echo -e "[Service]\nEnvironment=LD_PRELOAD=/opt/vgpu_unlock-rs/target/release/libvgpu_unlock_rs.so" | sudo tee -a /etc/systemd/system/nvidia-vgpu-mgr.service.d/vgpu_unlock.conf
6. Linux宿主機安裝vGPU驅動#
在此我們要取得特製版Nvidia vGPU的專有驅動,使用第三方提供的程式修補之後,再以執行.run
檔案的方式安裝驅動。
宿主機得安裝vGPU驅動(host driver),虛擬機內部也得安裝vGPU GRID驅動(guest driver)。虛擬機內部的驅動稱作「NVIDIA virtual GPU software」,所以版本命名規則與Nvidia驅動不同,但是二者版本建議要一樣。
到 NVIDIA Licensing Portal,用企業或組織的電子郵件註冊,即可取得評估版的驅動檔案。或者自己Google,找熱心網友分享的驅動(風險自負)。你還可以在 Google Cloud Compute找到部份vGPU GRID驅動。
下載後你應該會得到三個檔案,分為Linux宿主機使用的
-vgpu-kvm.run
和Linux虛擬機用的-grid.run
。Windows虛擬機的驅動則是_grid_win10_win11.exe
。這裡使用的驅動版本為
NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm.run
。因為我的GTX 1050Ti已經不受支援,所以使用16.x LTS分支的驅動,不使用17.x的最新版本。安裝編譯依賴套件
sudo apt install git build-essential dkms mdevctl linux-headers-$(uname -r)
- 取得vgpu-proxmox作者所提供的patch
cd ~
git clone https://gitlab.com/polloloco/vgpu-proxmox.git
- 將對應版本的patch套用到Nividia驅動
chmod +x NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm.run
./NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm.run --apply-patch ~/vgpu-proxmox/535.183.04.patch
- 執行新產生的檔案,以DKMS安裝Nvidia驅動
sudo ./NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm-custom.run --dkms -m=kernel
註:解除安裝使用此指令
sudo ./NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm-custom.run -uninstall
- 重開機
sudo reboot
- 確認Nvidia vGPU狀態:
nvidia-smi vgpu
- 確認mdev設定檔是否有出現:
sudo mdevctl types
7. 調整vGPU設定檔#
使用指令
sudo mdevctl types
查看預設的設定檔(profile),裡面規定了每個虛擬機的解析度編輯
profile_override.toml
,這個檔案用於覆寫Nvidia預設的設定檔
sudo vim /etc/vgpu_unlock/profile_override.toml
- 因為我的GTX 1050Ti只有4GB VRAM,上限也就兩個虛擬機吧,且Nvidia vGPU不能超賣(overcommit),就是說多個虛擬機執行的時候不能讓一個虛擬機吃光所有VRAM。所以我選取nvidia-52的設定檔,並且給每個虛擬機分配2GB VRAM。(更多VRAM配置詳見 PolloLoco / NVIDIA vGPU Guide的文章)
[profile.nvidia-52] # 針對nvidia-52設定檔所作的設定
num_displays = 1 # 螢幕數量
display_width = 1920 # 螢幕解析度
display_height = 1080 # 螢幕解析度
max_pixels = 2073600 # 螢幕解析度的乘積
cuda_enabled = 1 # 啟用CUDA
frl_enabled = 0 # 關閉60FPS限制
framebuffer = 0x74000000 # 分配2GB VRAM
framebuffer_reservation = 0xC000000 # 分配2GB VRAM
#[mdev.UUID] 還可以進一步針對個別UUID的medv裝置調整,限定使用這個mdev裝置的虛擬機所能分到的資源
- 取得NVIDIA GPU的PCI位址
lspci | grep NVIDIA
- 新增mdev裝置,後面依序填入UUID、PCI位址、vGPU設定檔,並設定開機自動啟動。
sudo mdevctl define --parent 0000:01:00.0 --type nvidia-52 --auto
sudo mdevctl start --uuid "填入上面生成的UUID" --parent "0000:01:00.0" --type "nvidia-52"
- mdev裝置可依照虛擬機數量新增多個,但必須使用同一個設定檔。像我這裡要給兩個虛擬機使用,就再生一個mdev裝置出來。
sudo mdevctl define --parent 0000:01:00.0 --type nvidia-52 --auto
sudo mdevctl start --uuid "填入上面生成的UUID" --parent "0000:01:00.0" --type "nvidia-52"
- 若要移除medv裝置請用此指令:
sudo mdevctl list --defined
sudo mdevctl undefine --uuid "填入UUID"
開啟Virt Manager,點選編輯虛擬機硬體,新增mdev裝置
編輯mdev裝置的XML,調整為以下內容
<hostdev mode="subsystem" type="mdev" managed="yes" model="vfio-pci" display="on" ramfb="on">
<source>
<address uuid="填入UUID"/>
</source>
<alias name="hostdev0"/>
<address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/>
</hostdev>
8. 架設vGPU授權伺服器#
「FastAPI-DLS」用於偽造Nvidia授權認證伺服器,使用Docker架設在宿主機或其他電腦,即可給虛擬機內的Nvidia驅動啟用授權。單次授權有效期間約是90天。
- 建立自簽SSL憑證
WORKING_DIR=/home/user/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 -subj '/CN=issuer' -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $WORKING_DIR/webserver.key -out $WORKING_DIR/webserver.crt
cd ../
- 新增
docker-compose.yml
version: '3.9'
x-dls-variables: &dls-variables
TZ: Asia/Taipei # 修改時區
DLS_URL: localhost # 修改IP
DLS_PORT: 443
LEASE_EXPIRE_DAYS: 90 # 90 days is maximum
DATABASE: sqlite:////app/database/db.sqlite
DEBUG: false
services:
dls:
image: collinwebdesigns/fastapi-dls:latest
restart: always
environment:
<<: *dls-variables
ports:
- "443:443"
volumes:
- /home/user/fastapi-dls/cert/:/app/cert
- dls-db:/app/database
logging:
driver: "json-file"
options:
max-file: 5
max-size: 10m
volumes:
dls-db:
- 啟動容器
sudo docker compose up -d
9. 在Linux虛擬機安裝vGPU GRID驅動#
註:我取得的GRID驅動版本跟宿主機的vGPU驅動不太一樣,但還是可以裝。
將GRID驅動傳送到Linux虛擬機內部,例如用scp指令傳
在虛擬機內安裝編譯依賴套件,將nouveau核心模組加入黑名單
sudo apt install git build-essential dkms mdevctl linux-headers-$(uname -r)
echo "blacklist nouveau" | sudo tee -a /etc/modprobe.d/blacklist.conf
sudo update-initramfs -k all -u
sudo reboot
- 安裝vGPU GRID驅動
chmod +x NVIDIA-Linux-x86_64-535.183.06-grid.run
sudo ./NVIDIA-Linux-x86_64-535.183.06-grid.run
- 設定跟宿主機一樣的時區
sudo timedatectl set-timezone Asia/Taipei
- 連線到自架的伺服器,取得授權碼
sudo curl --insecure -L -X GET https://宿主機IP:通訊埠/-/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok
sudo systemctl restart nvidia-gridd
- 確認授權狀態
nvidia-smi -q | grep License
- 如果要在Linux虛擬機裡面安裝CUDA,得用.run執行檔的方式安裝,不可以使用套件管理器。
另外,Linux宿主機依然可以安裝CUDA和使用NVENC,但是vGPU的驅動無法輸出螢幕畫面,也不能用Nvidia PRIME進行3D算繪,因此宿主機不能玩遊戲了。
10. 在Windows虛擬機安裝vGPU GRID驅動#
註:我取得的GRID驅動版本跟宿主機的vGPU驅動不太一樣,但還是可以裝。我在Windows 11安裝驅動會出現Error 43錯誤,可能是驅動不適合?或者與巢狀Hyper-V衝突?所以才用Windows Server。
使用Virt Manager 安裝Windows 11虛擬機。Windows Server 2022的安裝過程大致相同。
分配mdev裝置,將虛擬機開機。
確認Windows的裝置管理員出現GPU。
Nvidia vGPU的驅動不能用GeForce Experience安裝,需要手動將我們之前下載的
_grid.exe
傳到虛擬機內部安裝。安裝驅動
之後,裝置管理員應該就會顯示GPU型號。
在Windows以系統管理員開啟終端機,執行以下指令,連線到自架的認證伺服器,取得授權碼。若
"C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken\
資料夾不存在就手動新增。
curl.exe --insecure -L -X GET https://宿主機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
參考資料#
- NVIDIA Virtual GPU (vGPU) Software - NVIDIA Docs
- GPU virtualization with QEMU/KVM - Ubuntu Server tutorials
- NVIDIA vGPU on Proxmox VE - Proxmox VE Wiki
- PolloLoco / NVIDIA vGPU Guide - GitLab
- mbilker/vgpu_unlock-rs: Unlock vGPU functionality for consumer grade GPUs - Github
- FastAPI-DLS - Oscar Krause - GitLab
- 朵拉云 - Proxmox 7.4 使用vgpu_unlock,为GTX1060开启vGPU支持
- Linux解锁NVIDIA消费级显卡vGPU功能的入坑记录 - ByteHorizon
- 在Proxmox VE下开启vGPU - Tesla P4为例 - 雾时の森
- vGPU快速起步— Cloud Atlas beta 文档