前言

最近把實驗室的電腦安裝成 Proxmox VE(以下簡稱PVE),原本記憶體、CPU 等等的資源分享給每台虛擬機(以下簡稱 VM)都好好的,直到有同學需要用到 GPU 才發現 GPU 沒辦法共享。PVE 官方有 GPU passthrough 給 VM 的教學,但是好像一顆 GPU 只能指派給一台 VM,突發奇想 PVE 本身支援 LXC Container,那是不是可以利用 container 來共享 GPU 資源?

作法

先在 PVE 的主機上安裝 GPU 驅動程式,建立完 LXC Container 後把 GPU 對應的硬體 cgroup 編號寫進 LXC Container 的設定檔中,最後在 LXC Container 中再裝一次驅動程式,注意需要加上 --no-kernel-module 參數,就可以在 container 中使用顯卡囉。

步驟

  1. 更新 PVE 本身的 Sourcelist
    參考:https://pve.proxmox.com/wiki/Package_Repositories

  2. 更新 kernel

    1
    2
    apt-get update
    apt-get dist-upgrade
  3. 安裝 PVE headers

    1
    2
    apt-get update
    apt-get install pve-headers
  4. 利用 lspci | grep -i nvidia 取得顯卡資訊並從 Nvidia 官網找到對應顯卡驅動。
    舉例:./NVIDIA-Linux-x86_64-470.63.01.run
    安裝完之後應該會在 /dev 底下看到 Nvidia 顯卡對應的裝置。

    利用 nvidia-smi 確認一下顯卡有沒有被驅動程式讀到。

  5. 創建 /etc/udev/rules.d/70-nvidia.rules 並寫入以下內容,主要是更改 Nvidia 相關裝置的權限,方便 LXC Container 做使用,重開機之後這個檔案的內容就會被執行,不想重新開機也可以複製貼上指令即可。

    1
    2
    3
    4
    5
    6
    7
    # Create /nvidia0, /dev/nvidia1 … and /nvidiactl when nvidia module is loaded

    KERNEL=="nvidia", RUN+="/bin/bash -c '/usr/bin/nvidia-smi -L && /bin/chmod 666 /dev/nvidia*'"

    # Create the CUDA node when nvidia_uvm CUDA module is loaded

    KERNEL=="nvidia_uvm", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -u && /bin/chmod 0666 /dev/nvidia-uvm*'"
  6. 取得 Nvidia 裝置 cgroup number 並寫入 LXC Container 設定檔中。
    利用 ls -al /dev/nvidia*ls -al /dev/dri/* 可以看到 Nvidia 相關的裝置前面都有 cgroup number,這裡我拿到的是 195, 506, 509, 226。

  7. 建立 LXC Container 並把對應的裝置跟 cgroup number 寫進設定檔。
    以下是我寫入的內容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    lxc.cgroup.devices.allow: c 195:* rwm
    lxc.cgroup.devices.allow: c 506:* rwm
    lxc.cgroup.devices.allow: c 509:* rwm
    lxc.cgroup.devices.allow: c 226:* rwm

    lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
    lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
    lxc.mount.entry: /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file
    lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
    lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
    lxc.mount.entry: /dev/nvidia-caps/nvidia-cap1 dev/nvidia-caps/nvidia-cap1 none bind,optional,create=file
    lxc.mount.entry: /dev/nvidia-caps/nvidia-cap2 dev/nvidia-caps/nvidia-cap2 none bind,optional,create=file
    lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file
    lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file

    結果會長這樣

  8. LXC Container 中再去官網抓同樣的驅動,安裝的時候加上 --no-kernel-module 參數。
    舉例:./NVIDIA-Linux-x86_64-470.63.01.run --no-kernel-module
    成功囉!

附註

如果 /dev 底下沒有出現 nvidia-modeset 可以用 nvidia-modprobe --modeset 來載入。

參考