kubernetes安裝配置使用vGPU

牛奔發表於2024-04-26

前言

AI 落地時,在某些場景下 AI 模型在訓練或者是推理時,其算力要求不需要佔用整卡的 GPU,比如只需要0.5卡 GPU 即可滿足需求。

在這種情況下,可以使用 GPU 虛擬化技術來解決這個問題,將整卡的 GPU 虛擬化為兩個0.5卡的 GPU,這樣就可以在一張卡上同時跑兩個 AI 訓練或者 AI 推理應用服務,極大壓榨算力資源,降低成本。

vGPUNVIDIA 提供的一種 GPU 虛擬化的一種方案,同時也可以實現對多使用者的強 GPU 隔離方案

基本痛點:

  • 容器使用的單卡 GPU 利用率不夠高,特別是推理任務;
  • 為了提高 GPU 的利用率、避免算力浪費,需要在單個 GPU 上執行多個容器
  • vGPU 的使用需要額外從 NVIDIA 公司購買 license。年度訂閱和永久許可證

其他vGPU外掛

https://github.com/4paradigm/k8s-vgpu-scheduler

4paradigm 提供了 k8s-device-plugin,該外掛基於NVIDIA官方外掛( NVIDIA/k8s-device-plugin),在保留官方功能的基礎上,實現了對物理 GPU 進行切分,並對視訊記憶體和計算單元進行限制,從而模擬出多張小的 vGPU卡`。

k8s 叢集中,基於這些切分後的 vGPU 進行排程,使不同的容器可以安全的共享同一張物理 GPU,提高 GPU 的利用率。

此外,外掛還可以對視訊記憶體做虛擬化處理(使用到的視訊記憶體可以超過物理上的視訊記憶體),執行一些超大視訊記憶體需求的任務,或提高共享的任務數。

部署

配置docker

nvidia-smi命令,檢視當前顯示卡資訊

如果你使用了 docker,需要講將 nvidia runtime 設定為 docker runtime 預設值,此檔案通常在 /etc/docker/daemon.json 路徑:

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

docker 重新載入配置

systemctl daemon-reload && systemctl restart docker

配置containerd

你需要在節點上將 nvidia runtime 做為你的 containerd runtime 預設值。

我們將編輯 containerd daemon 的配置檔案,此檔案通常在 /etc/containerd/config.toml 路徑

version = 2
[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".containerd]
      default_runtime_name = "nvidia"

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
          privileged_without_host_devices = false
          runtime_engine = ""
          runtime_root = ""
          runtime_type = "io.containerd.runc.v2"
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
            BinaryName = "/usr/bin/nvidia-container-runtime"

containerd 重新載入配置

systemctl daemon-reload && systemctl restart containerd

檢視當前gpu分配情況

可以透過 kubectl describe node node1命令,檢視你指定節點的 gpu 個數情況:

Allocatable:
  cpu:                32
  ephemeral-storage:  94059137278
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             65738804Ki
  nvidia.com/gpu:     2
  pods:               110

關閉NVIDIA官方外掛

nvidia-device-plugin ds 描述檔案移除即可,為安全可以移動到其它目錄,如下移動到家目錄做備份儲存。

mv /etc/kubernetes/manifests/nvidia-device-plugin.yml .

啟用新的gpu裝置外掛

啟動 4paradigm 新的 k8s-device-plugin

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      priorityClassName: "system-node-critical"
      containers:
      - image: 4pdosc/k8s-device-plugin:latest
        imagePullPolicy: Always
        name: nvidia-device-plugin-ctr
        args: ["--fail-on-init-error=false", "--device-split-count=6", "--device-memory-scaling=2", "--device-cores-scaling=1"]
        env:
        - name: PCIBUSFILE
          value: "/usr/local/vgpu/pciinfo.vgpu"
        - name: NVIDIA_MIG_MONITOR_DEVICES
          value: all
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
            add: ["SYS_ADMIN"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
          - name: vgpu-dir
            mountPath: /usr/local/vgpu
          - mountPath: /tmp
            name: hosttmp
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
        - name: vgpu-dir
          hostPath:
            path: /usr/local/vgpu
        - hostPath:
            path: /tmp
          name: hosttmp
      nodeSelector: 
        nvidia-vgpu: "on"

將以上程式碼儲存為 vgpu-nvdp.yaml 檔案,然後安裝

kubectl apply -f vgpu-nvdp.yaml

打上gpu標籤

在需要進行虛擬化的節點打上標籤 nvidia-vgpu:"on" ,否則該節點不會被排程到,或者你打其他標籤也行,取決於你設定的 nodeSelector

kubectl label node {nodeid} nvdia-vgpu=on

等外掛部署完成後,再次執行 kubectl describe node node1命令,檢視節點的 gpu 個數情況

執行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.com/gpumem: 3000 # 每個vGPU申請3000m視訊記憶體 (可選,整數型別)
	  nvidia.com/gpucores: 30 # 每個vGPU的算力為30%實際顯示卡的算力 (可選,整數型別)

如果你的任務無法執行在任何一個節點上(例如任務的 nvidia.com/gpu 大於叢集中任意一個 GPU 節點的實際 GPU 數量),那麼任務會卡在 pending 狀態

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

監控vGPU使用情況

排程器部署成功後,監控預設自動開啟,你可以透過

http://{nodeip}:{monitorPort}/metrics

來獲取監控資料,其中 monitorPort 可以在 Values 中進行配置,預設為 31992

grafana dashboard 示例:https://github.com/4paradigm/k8s-vgpu-scheduler/blob/master/docs/dashboard_cn.md

注意 節點上的 vGPU 狀態只有在其使用 vGPU 後才會被統計 W

相關文章