快轉到主要內容

Ubuntu使用vgpu_unlock解鎖NVIDIA vGPU,給QEMU/KVM虛擬機啟用GPU虛擬化

分類   資訊科技 虛擬機與容器技術
標籤   GPU Virtualization Nvidia Ubuntu QEMU-KVM Libvirt
🗓️ 民國113年 甲辰年
✍ 切換正體/簡體字
目錄

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啦。

vGPU原理圖

不過,目前Nvidia官方僅將vGPU功能開放給伺服器GPU使用,而且需要購買授權。一般消費級的Nvidia GPU雖然硬體支援vGPU,但是vGPU是無法使用的。故我們得使用第三方開發者製作的「vgpu unlock」程式解鎖該功能,並用自架的「FastAPI-DLS」伺服器取得Nvidia vGPU的授權。

網路上有關這方面操作的教學多半是跑Proxmox,我參考了Nvidia和Ubuntu的官方文件,將其轉化為Ubuntu + QEMU/KVM的版本,可供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
#

  1. 編輯GRUB開機選項
sudo vim /etc/default/grub
  1. 針對Intel CPU,在GRUB_CMDLINE_LINUX_DEFAULT後面加入以下內容,啟用IOMMU
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on iommu=pt"
  1. 設定開機載入VFIO核心模組
echo -e "vfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd" | sudo tee -a  /etc/modules
  1. 將Nvidia開源驅動加入黑名單
echo "blacklist nouveau" | sudo tee -a /etc/modprobe.d/blacklist.conf
  1. 刪除目前系統的全部Nvidia驅動
sudo apt purge *nvidia*
  1. 更新initramfs和GRUB並重開機
sudo update-initramfs -u -k all

sudo update-grub

sudo reboot
  1. 進入電腦的UEFI設定,設定為以內顯優先開機。

5. 設定vgpu_unlock解鎖服務
#

Matthew Bilker的「vgpu_unlock-rs」為基於Jonathan Johansson的vgpu_unlock所開發的程式,它能夠將GPU偽裝成為支援vGPU的型號。

  1. 安裝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
  1. 建立vgpu_unlock-rs所需的檔案
sudo mkdir -p /etc/vgpu_unlock

sudo touch /etc/vgpu_unlock/profile_override.toml
  1. 建立開機自動啟動的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驅動不同,但是二者版本建議要一樣。

  1. NVIDIA Licensing Portal,用企業或組織的電子郵件註冊,即可取得評估版的驅動檔案。或者自己Google,找熱心網友分享的驅動(風險自負)。你還可以在 Google Cloud Compute找到部份vGPU GRID驅動。

  2. 下載後你應該會得到三個檔案,分為Linux宿主機使用的-vgpu-kvm.run和Linux虛擬機用的-grid.run。Windows虛擬機的驅動則是_grid_win10_win11.exe

  3. 這裡使用的驅動版本為NVIDIA-Linux-x86_64-535.183.04-vgpu-kvm.run。因為我的GTX 1050Ti已經不受支援,所以使用16.x LTS分支的驅動,不使用17.x的最新版本。

  4. 安裝編譯依賴套件

sudo apt install git build-essential dkms mdevctl linux-headers-$(uname -r)
  1. 取得vgpu-proxmox作者所提供的patch
cd ~

git clone https://gitlab.com/polloloco/vgpu-proxmox.git
  1. 將對應版本的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
  1. 執行新產生的檔案,以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
  1. 重開機
sudo reboot
  1. 確認Nvidia vGPU狀態:
nvidia-smi vgpu
  1. 確認mdev設定檔是否有出現:
sudo mdevctl types

7. 調整vGPU設定檔
#

  1. 使用指令sudo mdevctl types查看預設的設定檔(profile),裡面規定了每個虛擬機的解析度

  2. 編輯profile_override.toml,這個檔案用於覆寫Nvidia預設的設定檔

sudo vim /etc/vgpu_unlock/profile_override.toml
  1. 因為我的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裝置的虛擬機所能分到的資源
  1. 取得NVIDIA GPU的PCI位址
lspci | grep NVIDIA
  1. 新增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"
  1. 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"
  1. 若要移除medv裝置請用此指令:
sudo mdevctl list --defined

sudo mdevctl undefine --uuid "填入UUID"
  1. 開啟Virt Manager,點選編輯虛擬機硬體,新增mdev裝置

  2. 編輯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天。

  1. 建立自簽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 ../
  1. 新增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:
  1. 啟動容器
sudo docker compose up -d

9. 在Linux虛擬機安裝vGPU GRID驅動
#

註:我取得的GRID驅動版本跟宿主機的vGPU驅動不太一樣,但還是可以裝。

  1. 將GRID驅動傳送到Linux虛擬機內部,例如用scp指令傳

  2. 在虛擬機內安裝編譯依賴套件,將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
  1. 安裝vGPU GRID驅動
chmod +x NVIDIA-Linux-x86_64-535.183.06-grid.run

sudo ./NVIDIA-Linux-x86_64-535.183.06-grid.run
  1. 設定跟宿主機一樣的時區
sudo timedatectl set-timezone Asia/Taipei
  1. 連線到自架的伺服器,取得授權碼
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
  1. 確認授權狀態
nvidia-smi -q | grep License
  1. 如果要在Linux虛擬機裡面安裝CUDA,得用.run執行檔的方式安裝,不可以使用套件管理器。

另外,Linux宿主機依然可以安裝CUDA和使用NVENC,但是vGPU的驅動無法輸出畫面,也不能用Nvidia PRIME進行3D算繪,因此宿主機不能玩遊戲了。

10. 在Windows虛擬機安裝vGPU GRID驅動
#

註:我取得的GRID驅動版本跟宿主機的vGPU驅動不太一樣,但還是可以裝。我在Windows 11安裝驅動會出現Error 43錯誤(可能是驅動不適合?或者與巢狀Hyper-V衝突?),所以才用Windows Server。

  1. 使用Virt Manager 安裝Windows 11虛擬機。Windows Server 2022的安裝過程大致相同。

  2. 分配mdev裝置,將虛擬機開機。

  3. 確認Windows的裝置管理員出現GPU。

  4. Nvidia vGPU的驅動不能用GeForce Experience安裝,需要手動將我們之前下載的_grid.exe傳到虛擬機內部安裝。

  5. 安裝驅動

  6. 之後,裝置管理員應該就會顯示GPU型號。

  7. 在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
  1. 確認授權狀態
nvidia-smi.exe -q | Select-String License

參考資料
#

相關文章

Ubuntu安裝QEMU/KVM和Virt Manager虛擬機管理員
分類   資訊科技 虛擬機與容器技術
標籤   Libvirt Ubuntu QEMU-KVM
Ubuntu單GPU直通方法,Nvidia顯示卡直通給Windows 11 QEMU/KVM虛擬機
分類   資訊科技 虛擬機與容器技術
標籤   GPU Passthrough PCI Passthrough Ubuntu QEMU-KVM Libvirt
VirtIO-Balloon:伸縮自在的RAM,QEMU/KVM虛擬機動態分配記憶體
分類   資訊科技 虛擬機與容器技術
標籤   QEMU-KVM VirtIO Libvirt

留言板

此處提供二種留言板。點選按鈕,選擇您覺得方便的留言板。要討論程式碼請用Giscus,匿名討論請用Disqus。

這是Giscus留言板,需要Github帳號才能留言。支援markdown語法,若要上傳圖片請貼Imgur或Postimages。您的留言會在Github Discussions向所有人公開。

這是Disqus留言板,您可能會看到Disqus強制投放的廣告。為防止垃圾內容,有時留言可能會被系統判定需審核,導致延遲顯示,請見諒。若要上傳圖片請善用圖床網站。