Kubernetes 教程:在 Containerd 容器中使用 GPU
原文鏈接://fuckcloudnative.io/posts/add-nvidia-gpu-support-to-k8s-with-containerd/
前兩天鬧得沸沸揚揚的事件不知道大家有沒有聽說,Google 竟然將 Docker
踢出了 Kubernetes
的群聊,不帶它玩了。。。
具體的解釋請看《聽說 K8s 要甩了 Docker 了》,我這裡簡單描述下,Kubernetes 是通過 CRI 來對接容器運行時的,而 Docker 本身是沒有實現 CRI 的,所以 Kubernetes 內置了一個 「為 Docker 提供 CRI 支援」 的 dockershim
組件。現在 Kubernetes 宣布不再維護這個組件了,大概的意思就是:Docker 雖然好用,但那是對人來說的,Kubernetes 又不是人,不需要那些花里胡哨的東西!
Kubernetes 這是話裡有話,說白了就是:我特么以前為了兼容你,我集成在我自己這裡,現在我就想自己單純一點,要麼你自己寫 CRI 的介面 要麼就再見。
眾 YAML 工程師直呼 Containerd 真香!
下面進入今天的主題,Kubernetes 具有對機器的資源進行分配和使用的能力,比如可以指定容器最多使用多少記憶體以及使用多少 CPU 計算資源。那麼問題來了,一般來說容器就是使用 CPU 和記憶體資源,那麼對於需要使用顯示卡的 Pod,Kubernetes 也能夠支援嗎?答案當然是可以啦!目前 Kubernetes 不僅支援容器請求 GPU
資源,還支援請求幾塊顯示卡的 GPU 資源,這使得 Kubernetes 在深度學習和區塊鏈等場景下也有了用武之地。
關於 Kubernetes 集群中 Docker 如何使用 GPU,Kubernetes 的官方文檔已經說的很清楚了,網上也有鋪天蓋地的部落格手把手教你怎麼做。至於以 Containerd 作為容器運行時的集群如何使用 GPU,網上還找不到一篇像樣的文檔來告訴大家怎麼做,今天我就來做吃螃蟹的第一人。
要想在容器里使用 GPU,本質上就是我們要在容器里能看到並且使用宿主機上的顯示卡,所有的步驟都是圍繞這個來做的。當然,本文不會涉及如何安裝 Containerd,也不會涉及如何安裝 Kubernetes,如果這些都搞不定,建議不要往下看。
1. Nvidia 驅動
某些命令以 Ubuntu 作為示例。 首先宿主機上必現安裝 Nvidia 驅動。這裡推薦從 Nvidia 官網下載腳本安裝,安裝和卸載都比較方便並且適用於任何 Linux 發行版,包括 CentOS,Ubuntu 等。 NVIDIA Telsa GPU 的 Linux 驅動在安裝過程中需要編譯 kernel module,系統需提前安裝 gcc 和編譯 Linux Kernel Module 所依賴的包,例如 kernel-devel-$(uname -r) 等。
-
安裝 gcc 和 kernel-dev(如果沒有)
sudo apt install gcc kernel-dev -y
。 -
訪問官網下載。
-
選擇作業系統和安裝包,並單擊【SEARCH】搜尋驅動,選擇要下載的驅動版本
-
下載對應版本安裝腳本 在宿主機上執行:
$ wget //www.nvidia.com/content/DriverDownload-March2009/confirmation.php?url=/tesla/450.80.02/NVIDIA-Linux-x86_64-450.80.02.run&lang=us&type=Tesla
-
安裝 執行腳本安裝:
$ chmod +x NVIDIA-Linux-x86_64-450.80.02.run && ./NVIDIA-Linux-x86_64-450.80.02.run
-
驗證 使用如下命令驗證是否安裝成功
nvidia-smi
如果輸出類似下圖則驅動安裝成功。
2. CUDA 驅動
CUDA(Compute Unified Device Architecture)是顯示卡廠商 NVIDIA 推出的運算平台。CUDA™ 是一種由 NVIDIA 推出的通用並行計算架構,該架構使 GPU 能夠解決複雜的計算問題。它包含了 CUDA 指令集架構(ISA)以及 GPU 內部的並行計算引擎。 這裡安裝的方式和顯示卡驅動安裝類似。
-
訪問官網下載
-
下載對應版本如下圖
-
配置環境變數
$ echo 'export PATH=/usr/local/cuda/bin:$PATH' | sudo tee /etc/profile.d/cuda.sh $ source /etc/profile
3. nvidia-container-runtime
nvidia-container-runtime 是在 runc 基礎上多實現了 nvidia-container-runime-hook(現在叫 nvidia-container-toolkit),該 hook 是在容器啟動後(Namespace已創建完成),容器自定義命令(Entrypoint)啟動前執行。當檢測到 NVIDIA_VISIBLE_DEVICES 環境變數時,會調用 libnvidia-container 掛載 GPU Device 和 CUDA Driver。如果沒有檢測到 NVIDIA_VISIBLE_DEVICES 就會執行默認的 runc。
下面分兩步安裝:
先設置 repository 和 GPG key:
$ curl -s -L //nvidia.github.io/nvidia-container-runtime/gpgkey | sudo apt-key add - $ curl -s -L //nvidia.github.io/nvidia-container-runtime/$(. /etc/os-release;echo $ID$VERSION_ID)/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
安裝:
$ apt install nvidia-container-runtime -y
配置 Containerd 使用 Nvidia container runtime
如果
/etc/containerd
目錄不存在,就先創建它:$ mkdir /etc/containerd
生成默認配置:
$ containerd config default > /etc/containerd/config.toml
Kubernetes 使用設備插件(Device Plugins) 來允許 Pod 訪問類似 GPU 這類特殊的硬體功能特性,但前提是默認的 OCI runtime 必須改成
nvidia-container-runtime
,需要修改的內容如下:/etc/containerd/config.toml
... [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "overlayfs" default_runtime_name = "runc" no_pivot = false ... [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runtime.v1.linux" # 將此處 runtime_type 的值改成 io.containerd.runtime.v1.linux ... [plugins."io.containerd.runtime.v1.linux"] shim = "containerd-shim" runtime = "nvidia-container-runtime" # 將此處 runtime 的值改成 nvidia-container-runtime ...
重啟 containerd 服務:
$ systemctl restart containerd
4. 部署 NVIDIA GPU 設備插件
一條命令解決戰鬥:
$ kubectl apply -f //raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.7.1/nvidia-device-plugin.yml
查看日誌:
$ kubectl -n kube-system logs nvidia-device-plugin-daemonset-xxx 2020/12/04 06:30:28 Loading NVML 2020/12/04 06:30:28 Starting FS watcher. 2020/12/04 06:30:28 Starting OS watcher. 2020/12/04 06:30:28 Retreiving plugins. 2020/12/04 06:30:28 Starting GRPC server for 'nvidia.com/gpu' 2020/12/04 06:30:28 Starting to serve 'nvidia.com/gpu' on /var/lib/kubelet/device-plugins/nvidia-gpu.sock 2020/12/04 06:30:28 Registered device plugin for 'nvidia.com/gpu' with Kubelet
可以看到設備插件部署成功了。在 Node 上面可以看到設備插件目錄下的 socket:
$ ll /var/lib/kubelet/device-plugins/ total 12 drwxr-xr-x 2 root root 4096 Dec 4 01:30 ./ drwxr-xr-x 8 root root 4096 Dec 3 05:05 ../ -rw-r--r-- 1 root root 0 Dec 4 01:11 DEPRECATION -rw------- 1 root root 3804 Dec 4 01:30 kubelet_internal_checkpoint srwxr-xr-x 1 root root 0 Dec 4 01:11 kubelet.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-kvm.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-tun.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-vhost-net.sock= srwxr-xr-x 1 root root 0 Dec 4 01:30 nvidia-gpu.sock=
5. 測試 GPU
首先測試本地命令行工具 ctr,這個應該沒啥問題:
$ ctr images pull docker.io/nvidia/cuda:9.0-base $ ctr run --rm -t --gpus 0 docker.io/nvidia/cuda:9.0-base nvidia-smi nvidia-smi Fri Dec 4 07:01:38 2020 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 440.95.01 Driver Version: 440.95.01 CUDA Version: 10.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce RTX 208... Off | 00000000:A1:00.0 Off | N/A | | 30% 33C P8 9W / 250W | 0MiB / 11019MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
最後進入終極測試:在 Pod 中測試 GPU 可用性。先創建部署清單:
gpu-pod.yaml
apiVersion: v1 kind: Pod metadata: name: cuda-vector-add spec: restartPolicy: OnFailure containers: - name: cuda-vector-add image: "k8s.gcr.io/cuda-vector-add:v0.1" resources: limits: nvidia.com/gpu: 1
執行
kubectl apply -f ./gpu-pod.yaml
創建 Pod。使用kubectl get pod
可以看到該 Pod 已經啟動成功:$ kubectl get pod NAME READY STATUS RESTARTS AGE cuda-vector-add 0/1 Completed 0 3s
查看 Pod 日誌:
$ kubectl logs cuda-vector-add [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSED Done
可以看到成功運行。這也說明 Kubernetes 完成了對 GPU 資源的調用。需要注意的是,目前 Kubernetes 只支援卡級別的調度,並且顯示卡資源是獨佔,無法在多個容器之間分享。
參考資料
Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址//store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs載入問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 //github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。