vGPU device plugin for Kubernetes

語言: CN / TW / HK

vGPU device plugin基於NVIDIA官方外掛(NVIDIA/k8s-device-plugin),在保留官方功能的基礎上,實現了對物理GPU進行切分,並對視訊記憶體和計算單元進行限制,從而模擬出多張小的vGPU卡。在k8s叢集中,基於這些切分後的vGPU進行排程,使不同的容器可以安全的共享同一張物理GPU,提高GPU的利用率。此外,外掛還可以對視訊記憶體做虛擬化處理(使用到的視訊記憶體可以超過物理上的視訊記憶體),執行一些超大視訊記憶體需求的任務,或提高共享的任務數,可參考效能測試報告

GitHub地址: https://github.com/4paradigm/k8s-device-plugin

使用場景

  1. 視訊記憶體、計算單元利用率低的情況,如在一張GPU卡上執行10個tf-serving。
  2. 需要大量小顯示卡的情況,如教學場景把一張GPU提供給多個學生使用、雲平臺提供小GPU例項。
  3. 物理視訊記憶體不足的情況,可以開啟虛擬視訊記憶體,如大batch、大模型的訓練。

效能測試

在測試報告中,我們一共在下面五種場景都執行了ai-benchmark 測試指令碼,並彙總最終結果:

測試環境 環境描述
Kubernetes version v1.12.9
Docker version 18.09.1
GPU Type Tesla V100
GPU Num 2
測試名稱 測試用例
Nvidia-device-plugin k8s + nvidia官方k8s-device-plugin
vGPU-device-plugin k8s + VGPU k8s-device-plugin,無虛擬視訊記憶體
vGPU-device-plugin(virtual device memory) k8s + VGPU k8s-device-plugin,高負載,開啟虛擬視訊記憶體

測試內容

test id 名稱 型別 引數
1.1 Resnet-V2-50 inference batch=50,size=346*346
1.2 Resnet-V2-50 training batch=20,size=346*346
2.1 Resnet-V2-152 inference batch=10,size=256*256
2.2 Resnet-V2-152 training batch=10,size=256*256
3.1 VGG-16 inference batch=20,size=224*224
3.2 VGG-16 training batch=2,size=224*224
4.1 DeepLab inference batch=2,size=512*512
4.2 DeepLab training batch=1,size=384*384
5.1 LSTM inference batch=100,size=1024*300
5.2 LSTM training batch=10,size=1024*300

測試結果:img

img

測試步驟:

  1. 安裝nvidia-device-plugin,並配置相應的引數
  2. 執行benchmark任務
$ kubectl apply -f benchmarks/ai-benchmark/ai-benchmark.yml

  1. 通過kubctl logs 檢視結果
$ kubectl logs [pod id]

功能

  • 指定每張物理GPU切分的vGPU的數量
  • 限制vGPU的視訊記憶體
  • 限制vGPU的計算單元
  • 對已有程式零改動

實驗性功能

  • 虛擬視訊記憶體

    vGPU的視訊記憶體總和可以超過GPU實際的視訊記憶體,這時候超過的部分會放到記憶體裡,對效能有一定的影響。

產品限制

  • 分配到節點上任務所需要的vGPU數量,不能大於節點實際GPU數量

已知問題

  • 開啟虛擬視訊記憶體時,如果某張物理GPU的視訊記憶體已用滿,而這張GPU上還有空餘的vGPU,此時分配到這些vGPU上的任務會失敗。
  • 目前僅支援計算任務,不支援影片編解碼處理。

開發計劃

  • 支援影片編解碼處理
  • 支援Multi-Instance GPUs (MIG)

安裝要求

  • NVIDIA drivers >= 384.81
  • nvidia-docker version > 2.0
  • docker已配置nvidia作為預設runtime
  • Kubernetes version >= 1.10

快速入門

GPU節點準備

以下步驟要在所有GPU節點執行。這份README文件假定GPU節點已經安裝NVIDIA驅動和nvidia-docker套件。

注意你需要安裝的是nvidia-docker2而非nvidia-container-toolkit。因為新的--gpus選項kubernetes尚不支援。安裝步驟舉例:

# 加入套件倉庫
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

$ sudo apt-get update && sudo apt-get install -y nvidia-docker2
$ sudo systemctl restart docker

你需要在節點上將nvidia runtime做為你的docker runtime預設值。我們將編輯docker daemon的配置檔案,此檔案通常在/etc/docker/daemon.json路徑:

{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
    "default-shm-size": "2G"
}

如果runtimes欄位沒有出現, 前往的安裝頁面執行安裝操作nvidia-docker

Kubernetes開啟vGPU支援

當你在所有GPU節點完成前面提到的準備動作,如果Kubernetes有已經存在的NVIDIA裝置外掛,需要先將它移除。然後,你能通過下面指令下載我們的Daemonset yaml檔案:

$ wget https://raw.githubusercontent.com/4paradigm/k8s-device-plugin/master/nvidia-device-plugin.yml

在這個DaemonSet檔案中, 你能發現nvidia-device-plugin-ctr容器有一共4個vGPU的客製化引數:

  • fail-on-init-error:布林型別, 預設值是true。當這個引數被設定為true時,如果裝置外掛在初始化過程遇到錯誤時程式會返回失敗,當這個引數被設定為false時,遇到錯誤它會列印資訊並且持續阻塞外掛。持續阻塞外掛能讓裝置外掛即使部署在沒有GPU的節點(也不應該有GPU)也不會丟擲錯誤。這樣你在部署裝置外掛在你的叢集時就不需要考慮節點是否有GPU,不會遇到報錯的問題。然而,這麼做的缺點是如果GPU節點的裝置外掛因為一些原因執行失敗,將不容易察覺。現在預設值為當初始化遇到錯誤時程式返回失敗,這個做法應該被所有全新的部署採納。
  • device-split-count:整數型別,預設值是2。NVIDIA裝置的分割數。對於一個總共包含_N_張NVIDIA GPU的Kubernetes叢集,如果我們將device-split-count引數配置為_K_,這個Kubernetes叢集將有_K * N_個可分配的vGPU資源。注意,我們不建議將NVIDIA 1080 ti/NVIDIA 2080 tidevice-split-count引數配置超過5,將NVIDIA T4配置超過7,將NVIDIA A100配置超過15。
  • device-memory-scaling:浮點數型別,預設值是1。NVIDIA裝置視訊記憶體使用比例,可以大於1(啟用虛擬視訊記憶體,實驗功能)。對於有_M​_視訊記憶體大小的NVIDIA GPU,如果我們配置device-memory-scaling引數為_S_,在部署了我們裝置外掛的Kubenetes叢集中,這張GPU分出的vGPU將總共包含_S * M_視訊記憶體。每張vGPU的視訊記憶體大小也受device-split-count引數影響。在先前的例子中,如果device-split-count引數配置為_K_,那每一張vGPU最後會取得_S * M / K_大小的視訊記憶體。
  • device-cores-scaling:浮點數型別,預設值是1。NVIDIA裝置算力使用比例,可以大於1。如果device-cores-scaling​引數配置為_S​_device-split-count引數配置為_K_,那每一張vGPU對應的一段時間內sm 利用率平均上限為_S / K_。屬於同一張物理GPU上的所有vGPU sm利用率總和不超過1。
  • enable-legacy-preferred:布林型別,預設值是false。對於不支援 PreferredAllocation 的kublet(<1.19)可以設定為true,更好的選擇合適的device,開啟時,本外掛需要有對pod的讀取許可權,可參看 legacy-preferred-nvidia-device-plugin.yml。對於 kubelet >= 1.9 時,建議關閉。

完成這些可選引數的配置後,你能透過下面命令開啟vGPU的支援:

$ kubectl apply -f nvidia-device-plugin.yml

執行GPU任務

NVIDIA vGPUs 現在能透過資源型別nvidia.com/gpu被容器請求:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu:18.04
      command: ["bash", "-c", "sleep 86400"]
      resources:
        limits:
          nvidia.com/gpu: 2 # 請求2個vGPUs

現在你可以在容器執行nvidia-smi命令,然後比較vGPU和實際GPU視訊記憶體大小的不同。

**注意:**如果你使用外掛裝置時,如果沒有請求vGPU資源,那容器所在機器的所有vGPU都將暴露給容器。

測試

  • TensorFlow 1.14.0-1.15.0/2.2.0-2.6.2
  • torch1.1.0-1.8.0
  • mxnet 1.4.0
  • mindspore 1.1.1
  • xgboost 1.0-1.4
  • nccl 2.4.8-2.9.9

以上框架均通過測試。

日誌

啟動日誌:在使用vGPU功能的pod中新增環境變數

LIBCUDA_LOG_LEVEL=5

獲取vGPU相關的日誌:

kubectl logs xxx | grep libvgpu.so

反饋和參與