---
# System prepended metadata

title: '0625'

---

# 0625
## 1.要先在Master節點上安裝驅動程式(nvidia)
### 前言
NVIDIA 裝置插件（NVIDIA Device Plugin）適用於 Kubernetes，是一個 Daemonset，具備以下功能：

自動暴露叢集每個節點上的 GPU 數量。
追蹤 GPU 的健康狀態。
在 Kubernetes 叢集中運行支持 GPU 的容器。
此儲存庫包含 NVIDIA 官方實作的 Kubernetes 裝置插件。從 v0.15.0 開始，此儲存庫還包含 GPU Feature Discovery 標籤的實作，有關 GPU Feature Discovery 的更多資訊，請參見此處。

請注意：

* 從 Kubernetes v1.10 起，NVIDIA 裝置插件 API 處於 beta 版。
* NVIDIA 裝置插件目前缺乏：
* * 全面的 GPU 健康檢查功能
* * GPU 清理功能
### 準備
運行 NVIDIA 裝置插件所需的先決條件如下：

1. NVIDIA 驅動程序：版本大約為 384.81。
2. nvidia-docker：版本需為 2.0 或更高，或者 nvidia-container-toolkit：版本需為 1.7.0 或更高（要在基於 Tegra 的系統上使用集成 GPU，則需版本為 1.11.0 或更高）。
3. nvidia-container-runtime：配置為預設的低階運行時。
4. Kubernetes：版本需為 1.10 或更高。

### 開始
1. 安裝 NVIDIA 驅動程式
```
# 更新軟件包列表
sudo apt-get update 
# 安裝 NVIDIA 驅動程序(535可以換)這一步會跑比較久
sudo apt-get install -y nvidia-driver-535
# 重啟
sudo reboot

```
2. 安裝 NVIDIA Container Toolkit
```
# 設置 NVIDIA 存儲庫
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
# 安裝 NVIDIA Container Toolkit
sudo apt-get install -y nvidia-container-toolkit
sudo apt-get install -y nvidia-container-runtime
# 配置 Docker 以使用 NVIDIA Container Runtime
sudo tee /etc/docker/daemon.json <<EOF
{
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    },
    "default-runtime": "nvidia"
}
EOF
# 重啟 Docker
sudo systemctl restart docker
```

* nvidia-container-toolkit：

這是一個核心組件，負責設置容器運行時環境。
它確保 NVIDIA GPU 驅動程序和相關庫能夠正確地被容器訪問。
處理 GPU 設備和庫的掛載，確保容器內的應用程序可以使用 GPU。


* nvidia-container-runtime：

這是一個特殊的容器運行時，專門用於支持 NVIDIA GPU。
它與 Docker 引擎集成，允許 Docker 使用 NVIDIA GPU。
在容器啟動時，它會自動配置必要的環境，使容器能夠訪問 GPU。


3. 配置 Containerd
創建文件 /etc/containerd/config.toml 並寫入：
```
[plugins]

  # 定義 Containerd 的插件設置。
  [plugins."io.containerd.grpc.v1.cri".containerd]
  
    # 預設會使用 NVIDIA 運行
    default_runtime_name = "nvidia" 
    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
    
      # NVIDIA 運行時的具體配置
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia] 
      
        # 指定運行時類型為 Linux。
        runtime_type = "io.containerd.runtime.v1.linux" 
        
        # 指定 NVIDIA 容器運行時的路徑。
        runtime_engine = "/usr/bin/nvidia-container-runtime" 
        
        # 運行時的根目錄，這裡設置為空。
        runtime_root = "" 
```
重啟 Containerd
```
sudo systemctl restart containerd
```
這個配置的意義是：

讓 Containerd 知道如何使用 NVIDIA Container Runtime。
設置 NVIDIA 運行時為默認選項，這樣所有通過 Containerd 啟動的容器都能默認使用 GPU，指定了 NVIDIA Container Runtime 的位置，確保 Containerd 能找到並使用它。

這個配置對於在 Kubernetes 這樣的容器編排系統中使用 GPU 特別重要，因為 Kubernetes 通常使用 Containerd 作為其容器運行。通過這個配置，Kubernetes 集群中的節點就能夠正確地使用 NVIDIA GPU ..來運行需要 GPU 的工作負載。
這個設置與之前的 Docker 配置相輔相成，共同確保了在不同的容器環境中都能正確地使用 NVIDIA GPU。

4. 配置 CRI-O
先創建資料夾，再創建文件 /etc/crio/crio.conf.d/99-nvidia.conf 
```
# 創建 CRI-O 配置目錄(-p:如果連父資料夾都沒有的話也一併創建)
sudo mkdir -p /etc/crio/crio.conf.d

# 使用 nano 編輯器創建並編輯 NVIDIA 相關的 CRI-O 配置文件
sudo nano /etc/crio/crio.conf.d/99-nvidia.conf
```
並寫入：
```
[crio]
  [crio.runtime]
     # 預設運行的容器為nvidia
    default_runtime = "nvidia"

    [crio.runtime.runtimes]
      [crio.runtime.runtimes.nvidia]
        # 指定 NVIDIA 容器運行時的路徑
        runtime_path = "/usr/bin/nvidia-container-runtime"
        # 指定運行時類型為 OCI (Open Container Initiative)
        runtime_type = "oci"
```
使用 nvidia-ctk 自動生成配置文件
```
sudo nvidia-ctk runtime configure --runtime=crio --set-as-default --config=/etc/crio/crio.conf.d/99-nvidia.conf
```
在配置文件 /etc/nvidia-container-runtime/config.toml 中更改順序 
```
[nvidia-container-runtime]
runtimes = ["crun", "docker-runc", "runc"]
```
重啟 CRI-O([安裝CRI-O](https://hackmd.io/cbJ9UVCQQxiWj9mNLlnSlg))
```
sudo systemctl restart crio
```
### 測試成功
```
master@virtualbox-vm:~$ kubectl describe node ncue-csie 
.......
Capacity:
  cpu:                16
  ephemeral-storage:  95536548Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             65774596Ki
  nvidia.com/gpu:     1
  pods:               110
Allocatable:
  cpu:                16
  ephemeral-storage:  88046482492
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             65672196Ki
  nvidia.com/gpu:     1
  pods:               110

```

Q:為什麼又要改plugins又要改CRI-O:
![image](https://hackmd.io/_uploads/rJSDZpKvC.png)

### 在 Kubernetes 中啟用 GPU 支持
完成以上步驟後，部署以下 Daemonset 來啟用 GPU：
```
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.15.0/deployments/static/nvidia-device-plugin.yml
```
可以再更進一步使用Helm 部署
Helm 是 Kubernetes 的一個包管理工具，可以更方便地部署和管理 Kubernetes 應用程序。
```
# 安裝 Helm
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
# 添加 NVIDIA 存儲庫
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo 
# 使用 Helm 部署 NVIDIA 裝置插件
helm install --generate-name nvdp/nvidia-device-plugin
```
### 執行 GPU 任務
```
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  restartPolicy: Never
  containers:
    - name: cuda-container
      image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
      resources:
        limits:
          nvidia.com/gpu: 1 # 請求 1 個 GPU
  tolerations:
  - key: nvidia.com/gpu
    operator: Exists
    effect: NoSchedule
EOF
```
執行上述命令後，您可以檢查 Pod 的日誌以確認 GPU 任務是否成功執行：
```
kubectl logs gpu-pod
```
應該要有這個輸出
```
[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
```
## 2.使用裝置插件
Kubernetes 實現了裝置插件，使 Pod 能夠訪問專門的硬件功能，如 GPU。
以nvidia為主

https://github.com/NVIDIA/k8s-device-plugin#quick-start

可以像請求 CPU 或內存一樣，從容器中請求這些 GPU 資源。但是，在指定自定義設備資源需求時有一些限制。

GPU 只能在 limits 部分中指定，這意味著：

* 你可以只指定 GPU 的 limits，而不指定 requests，因為 Kubernetes 會默認將 limits 作為 requests 的值。
* 你可以同時在 limits 和 requests 中指定 GPU，但這兩個值必須相等。
* 你不能只指定 GPU 的 requests，而不指定 limits。
以下是一個請求 GPU 的 Pod 的範例：
```
apiVersion: v1
kind: Pod
metadata:
  name: example-vector-add
spec:
  restartPolicy: OnFailure
  containers:
    - name: example-vector-add
      image: "registry.example/example-vector-add:v42"
      resources:
        limits:
          gpu-vendor.example/example-gpu: 1 # 請求 1 個 GPU
```
## 管理具有不同類型 GPU 的叢集（這應該用不到）
如果叢集中不同的節點具有不同類型的 GPU，則可以使用節點標籤（Node Labels）和節點選擇器（Node Selectors）來將 Pod 調度到合適的節點。
```
kubectl label nodes node1 accelerator=example-gpu-x100
kubectl label nodes node2 accelerator=other-gpu-k915
```
## vGPU
不是每個POD都一定要用到一個GPU，可以用類似virtual memory的方式來分配gpu在每個pod的使用，例如pod1用0.5張卡，pod2用0.4張
https://www.cnblogs.com/niuben/p/18160759

https://www.huweihuang.com/kubernetes-notes/runtime/runtime.html
https://ithelp.ithome.com.tw/m/articles/10216215
https://blog.csdn.net/u013149714/article/details/127767490