GPU裝置外掛程式(NVIDIA Device Plugin)是Kubernetes叢集中用於管理每個節點的GPU的組件,使得Kubernetes能夠更方便、高效地利用GPU資源。本文介紹在獨佔GPU調度情境下,如何對ACK節點的NVIDIA Device Plugin進行升級、重啟、GPU裝置隔離、版本查看與更新等操作。
使用說明
對於以DaemonSet方式部署的NVIDIA Device Plugin,有如下幾點需要說明:
叢集在建立時,會自動安裝該組件。
如果卸載該組件將導致擴容的GPU節點無法正常上報GPU資源。
叢集由低版本升級到1.32過程中,會同時將以Static Pod方式部署的NVIDIA Device Plugin升級為ACK組件形式。
該DaemonSet存在一個NodeSelector(ack.node.gpu.schedule=default),GPU節點在添加到叢集中時,ACK添加節點的指令碼會自動為該GPU節點打上該標籤,使DaemonSet能夠在GPU節點上部署對應的Pod。
若節點作業系統為Ubuntu 22.04或Red Hat Enterprise Linux(RHEL) 9.3 64位,由於
ack-nvidia-device-plugin組件會為Pod預設配置環境變數NVIDIA_VISIBLE_DEVICES=all,可能會因為節點執行systemctl daemon-reload、systemctl daemon-reexec命令後,無法訪問GPU裝置導致NVIDIA Device Plugin無法正常工作。更多詳情,請參見運行GPU容器出現Failed to initialize NVML: Unknown Error的問題怎麼辦?。若在2025年05月01日之前將叢集從低版本升級到1.32版本,叢集中可能會同時存在以Static Pod方式部署和DaemonSet方式部署的NVIDIA Device Plugin。可執行如下指令碼查看以Static Pod方式部署的節點。
#!/bin/bash for i in $(kubectl get po -n kube-system -l component=nvidia-device-plugin | grep -v NAME | awk '{print $1}');do if kubectl get po $i -o yaml -n kube-system | grep 'kubernetes.io/config.source: file' &> /dev/null;then kubectl get pod $i -n kube-system -o jsonpath='{.spec.nodeName}{"\n"}' fi done預期輸出:
cn-beijing.10.12.XXX.XX cn-beijing.10.13.XXX.XX通過預期輸出可以看到部分節點中仍存在以Static Pod方式部署的NVIDIA Device Plugin。可以使用如下方式將Static Pod方式部署的NVIDIA Device Plugin遷移到DaemonSet。
kubectl label nodes <NODE_NAME> ack.node.gpu.schedule=default
版本差異
ack-nvidia-device-plugin組件隨著叢集版本的不同,其實現方式和管理原則如下表所示。
特性 | 1.32及以上叢集版本 | 1.20至1.31間叢集版本 |
部署方式 | DaemonSet | Static Pod |
管理方式 | 控制台組件管理 | 手動維護 |
節點標籤要求 | ack.node.gpu.schedule=default | 無特殊要求 |
隨節點池升級策略 | 手動升級 | 自動升級 |
若叢集版本低於1.20,建議手動升級叢集。
前提條件
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
查看NVIDIA Device Plugin版本
1.32及以上叢集版本
針對以DaemonSet方式部署的組件,可在控制台組件管理頁面定位ack-nvidia-device-plugin組件,在組件卡片上查看目前的版本。
1.20至1.31間叢集版本
針對以Static Pod方式部署的組件,可執行以下命令查看組件版本。
kubectl get pods -n kube-system -l component=nvidia-device-plugin \
-o jsonpath='{range .items[*]}{.spec.containers[0].image}{"\t"}{.spec.nodeName}{"\n"}{end}' \
| awk -F'[:/]' '{split($NF, a, "-"); print a[1] "\t" $0}' \
| sort -k1,1V \
| cut -f2- \
| awk -F'\t' '{split($1, img, ":"); print img[NF] "\t" $2}'升級NVIDIA Device Plugin
升級ack-nvidia-device-plugin組件。
1.32及以上叢集版本
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,單擊組件管理。
在組件管理頁面,搜尋ack-nvidia-device-plugin組件,在其卡片位置單擊升級。
在彈出的對話方塊中,單擊確定。
1.20至1.31間叢集版本
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
選中需要批量維護的GPU節點,在節點列表下方單擊批量營運,然後在批量營運對話方塊選擇執行Shell命令,單擊確定。
重要建議先選擇少量GPU節點進行升級,操作完成驗證節點Device Plugin正常工作後,再大大量操作。
在自動跳轉的OOS介面,選擇執行模式為失敗暫停後,單擊下一步:設定參數。
在設定參數頁面,選擇運行Shell指令碼,並粘貼如下樣本指令碼。
說明指令碼中
RUN_PKG_VERSION參數需修改為叢集對應的大版本號碼(例如:1.30)。請勿填入小版本號碼(例如:1.30.1),否則會導致指令碼報錯。指令碼中
REGION_ID參數需修改為當前叢集所在的地區ID,例如:cn-beijing。
#!/bin/bash set -xe RUN_PKG_VERSION=1.30 REGION_ID=cn-beijing function update_device_plugin() { base_dir=/tmp/update_device_plugin rm -rf $base_dir mkdir -p $base_dir cd $base_dir region_id=$REGION_ID PKG_URL=https://aliacs-k8s-${region_id}.oss-${region_id}-internal.aliyuncs.com/public/pkg/run/run-${RUN_PKG_VERSION}.tar.gz curl -sSL --retry 3 --retry-delay 2 -o run.tar.gz $PKG_URL tar -xf run.tar.gz local dir=pkg/run/$RUN_PKG_VERSION/module sed -i "s@registry.cn-hangzhou.aliyuncs.com/acs@registry-${region_id}-vpc.ack.aliyuncs.com/acs@g" $dir/nvidia-device-plugin.yml mkdir -p /etc/kubernetes/device-plugin-backup mkdir -p /etc/kubernetes/manifests mv /etc/kubernetes/manifests/nvidia-device-plugin.yml /etc/kubernetes/device-plugin-backup/nvidia-device-plugin.yml.$(date +%s) sleep 5 cp -a $dir/nvidia-device-plugin.yml /etc/kubernetes/manifests echo "succeeded to update device plugin" } if [ -f /etc/kubernetes/manifests/nvidia-device-plugin.yml ]; then update_device_plugin else echo "skip to update device plugin" fi單擊下一步:確定,確認資訊無誤後單擊建立。
建立後自動跳轉至任務執行管理頁面,可查看任務運行狀態。查看執行輸出為
succeeded to update device plugin,表明更新成功。
檢查組件是否正常運行。
執行如下命令,查看GPU節點上Device Plugin是否正常工作。
使用如下命令檢查NVIDIA Device Plugin是否重啟:
kubectl get po -n kube-system -l component=nvidia-device-plugin樣本輸出,通過AGE時間判斷Pod是否重啟。
NAME READY STATUS RESTARTS AGE nvidia-device-plugin-xxxx 1/1 Running 1 1m判斷所有Pod重啟後,執行如下指令碼檢測節點是否上報GPU資源:
#!/bin/bash # 擷取所有合格 NVIDIA Device Plugin Pod及其所在節點 PODS=$(kubectl get po -n kube-system -l component=nvidia-device-plugin -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}') # 遍曆每個 Pod 的節點 echo "$PODS" | while IFS=$'\t' read -r pod_name node_name; do # 擷取節點的 nvidia.com/gpu 資源分派值 gpu_allocatable=$(kubectl get node "$node_name" -o jsonpath='{.status.allocatable.nvidia\.com/gpu}' 2>/dev/null) # 檢查資源值是否為 0 if [ "$gpu_allocatable" == "0" ]; then echo "Error: node=$node_name, pod=$pod_name, resource(nvidia.com/gpu) is 0" fi done如果出現節點上報資源為0, 可參考重啟NVIDIA Device Plugin。
重啟NVIDIA Device Plugin
在ACK的獨佔GPU調度情境下,節點上GPU的裝置上報的Device Plugin預設以一個Pod的形式部署,所以重啟過程需要在目標節點上進行。
1.32及以上叢集版本
執行如下命令,查詢對應節點的Device Plugin Pod。
kubectl get pod -n kube-system -l component=nvidia-device-plugin -o wide | grep <NODE>執行如下命令,重啟對應的Device Plugin Pod。
kubectl delete po <DEVICE_PLUGIN_POD> -n kube-system
1.20至1.31間叢集版本
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
在節點池頁面,單擊節點池名稱,進入節點管理,登入目標GPU節點。
如果作業系統為ContainerOS,為了減少潛在的安全風險,ContainerOS原則上不支援任何使用者直接登入到系統進行一系列可能無法追溯的操作,也不提供SSH登入功能。若仍然有登入執行個體進行營運操作的需求,請參見營運ContainerOS節點。
選中需要批量維護的GPU節點,在節點列表下方單擊批量營運,然後在批量營運對話方塊選擇執行shell命令,單擊確定。
重要建議先選擇少量GPU節點進行重啟,操作完成驗證節點Device Plugin正常工作後,再大大量操作。
在自動跳轉的OOS介面,選擇執行模式為失敗暫停後,單擊下一步:設定參數。
在設定參數頁面,選擇運行shell指令碼,並粘貼如下樣本指令碼。
#!/bin/bash set -e if [ -f /etc/kubernetes/manifests/nvidia-device-plugin.yml ]; then cp -a /etc/kubernetes/manifests/nvidia-device-plugin.yml /etc/kubernetes rm -rf /etc/kubernetes/manifests/nvidia-device-plugin.yml sleep 5 mv /etc/kubernetes/nvidia-device-plugin.yml /etc/kubernetes/manifests echo "the nvidia device is restarted" else echo "no need to restart nvidia device plugin" fi單擊下一步:確定,確認資訊無誤後單擊建立。建立後自動跳轉至任務執行管理頁面,可查看任務運行狀態。
執行如下命令,查看GPU節點上Device Plugin是否正常工作。
kubectl get nodes <NODE_NAME> -o jsonpath='{.metadata.name} ==> nvidia.com/gpu: {.status.allocatable.nvidia\.com/gpu}'預期輸出:
cn-hangzhou.172.16.XXX.XX ==> nvidia.com/gpu: 1GPU節點上報的
nvidia.com/gpu擴充資源不為0,說明Device Plugin正常工作。
修改NVIDIA Device Plugin裝置標識符
Device-Plugin在為Pod分配裝置時會在節點上建立一份Checkpoint檔案,用於記錄和儲存哪些裝置已經被分配,以及它們對應Pod的資訊。在NVIDIA Device Plugin中,Checkpoint檔案預設使用GPU的UUID作為每個GPU裝置的唯一識別碼(Key)。可以參見下文將該Key修改為裝置的Index,以解決VM冷遷移導致的UUID丟失等問題。
1.32及以上叢集版本
執行如下命令,修改NVIDIA Device Plugin Daemonset。
kubectl edit ds -n kube-system ack-nvidia-device-plugin添加如下環境變數
CHECKPOINT_DEVICE_ID_STRATEGY。env: - name: CHECKPOINT_DEVICE_ID_STRATEGY value: index重啟NVIDIA Device Plugin,使得修改內容生效。
1.20至1.31間叢集版本
在目標節點上的
/etc/kubernetes/manifests/nvidia-device-plugin.yml檔案中查看Device-Plugin的鏡像Tag,其所代表的版本號碼即為Device-Plugin的版本。如果版本號碼大於等於0.9.3,則無需修改版本號碼,否則請將版本號碼修改為最新的版本號碼v0.9.3-0dd4d5f5-aliyun。修改
/etc/kubernetes/manifests/nvidia-device-plugin.yml檔案中的Static Pod的環境變數,參見以下代碼增加一個環境變數CHECKPOINT_DEVICE_ID_STRATEGY。env: - name: CHECKPOINT_DEVICE_ID_STRATEGY value: index重啟NVIDIA Device Plugin,使得修改內容生效。
開啟GPU裝置隔離功能
GPU裝置隔離操作僅支援在nvidia-device-plugin的v0.9.1及以上版本中使用。可以參見下文查看NVIDIA Device Plugin版本。
在ACK的獨佔GPU調度情境下,出於某些原因(例如GPU裝置故障等),需要隔離節點上的某個GPU裝置,ACK提供了一個機制供手動對節點上的某個裝置進行隔離,以避免新的GPU應用Pod被分配到這張GPU卡。具體的操作方式如下:
在目標節點/etc/nvidia-device-plugin/的目錄下操作unhealthyDevices.json這個檔案,如果此檔案不存在,請建立此檔案。unhealthyDevices.json的檔案格式請按照以下JSON格式編排。
{
"index": ["x", "x" ..],
"uuid": ["xxx", "xxx" ..]
}可以根據個人偏好,在JSON中填寫目標隔離裝置的index或uuid(同一個裝置只需填寫任意一個),儲存檔案後即可自動生效。
設定完成後,可以通過查看Kubernetes Node上報的Resource中的nvidia.com/gpu資源的數量以查看隔離的效果。
常見問題
如何關閉NVIDIA Device Plugin原生GPU隔離能力?
問題背景
當節點 GPU 出現異常時,ACK 會通過 NVIDIA Device Plugin 自動隔離異常GPU,防止任務被調度到異常GPU上。而自動隔離並不會執行自動修複,您仍需手動重啟或維修節點,並建議配置 GPU 異常警示以便及時處理。關於NVIDIA Device Plugin原生GPU隔離能力的更多資訊,請參見k8s-device-plugin。
隔離後,若節點剩餘 GPU 不足以滿足任務需求(如 8 卡任務在僅有 7 卡可用時),任務將無法調度,可能導致GPU資源閑置。
GPU狀態恢複正常後,對該GPU裝置的隔離會自動解除。
如需關閉自動隔離(出現異常GPU仍然上報資源,不做異常GPU隔離),請參考後續解決方案。
解決方案
確認組件是否已開啟原生的GPU隔離能力。
如果未開啟,則無需執行後續的關閉操作。
1.32及以上叢集版本
登入Container Service管理主控台,在目的地組群的組件管理中檢查ack-nvidia-device-plugin版本。如果版本為v0.1.0,則說明已開啟GPU隔離能力。
1.20至1.31間叢集版本
檢測NVIDIA Device Plugin是否開啟GPU隔離能力。
check_gpu_isolation_enabled() { echo "Checking nodes with NVIDIA Device Plugin deployed as static pods that have GPU isolation enabled (i.e., DP_DISABLE_HEALTHCHECKS is not set to 'all')..." # Get pod names with the expected label pods=$(kubectl get pods -n kube-system -l component=nvidia-device-plugin --no-headers -o custom-columns=":metadata.name" 2>/dev/null) if [ -z "$pods" ]; then echo "No pods found with label 'component=nvidia-device-plugin'." return 0 fi found=0 while IFS= read -r pod; do [ -z "$pod" ] && continue # Check if it's a static pod: annotation kubernetes.io/config.source must be "file" config_source=$(kubectl get pod "$pod" -n kube-system -o jsonpath='{.metadata.annotations.kubernetes\.io/config\.source}' 2>/dev/null) if [ "$config_source" != "file" ]; then # Not a static pod (e.g., managed by DaemonSet), skip continue fi # Get node name node=$(kubectl get pod "$pod" -n kube-system -o jsonpath='{.spec.nodeName}' 2>/dev/null) [ -z "$node" ] && continue # Check if DP_DISABLE_HEALTHCHECKS is set to "all" disabled_value=$(kubectl get pod "$pod" -n kube-system -o jsonpath='{range .spec.containers[*]}{range .env[?(@.name=="DP_DISABLE_HEALTHCHECKS")]}{.value}{"\n"}{end}{end}' 2>/dev/null | head -n1) # If not set or not equal to "all", health checks are active → isolation is enabled if [ -z "$disabled_value" ] || [ "$disabled_value" != "all" ]; then echo "Node: $node, Static Pod: $pod" found=1 fi done <<< "$pods" if [ "$found" -eq 0 ]; then echo "No static pods found with GPU isolation enabled." else echo "Note: The above nodes will automatically isolate faulty GPUs via NVIDIA Device Plugin." fi } check_gpu_isolation_enabled預期輸出:
Checking nodes with NVIDIA Device Plugin deployed as static pods that have GPU isolation enabled (i.e., DP_DISABLE_HEALTHCHECKS is not set to 'all')... Node: cn-beijing.192.168.XXX.XXX, Static Pod: nvidia-device-plugin-cn-beijing.192.168.XXX.XXX Note: The above nodes will automatically isolate faulty GPUs via NVIDIA Device Plugin.若輸出結果中包含
Note: The above nodes will automatically isolate faulty GPUs via NVIDIA Device Plugin.,則說明已開啟GPU隔離能力。
通過升級組件關閉GPU隔離能力。
最新版本的NVIDIA Device Plugin組件已預設關閉原生的GPU隔離能力,請升級NVIDIA Device Plugin組件至最新版。
相關文檔
關於組件的變更記錄,請參見ack-nvidia-device-plugin。
如遇到GPU節點相關問題,請參見自助診斷GPU節點問題、GPU FAQ。
如需瞭解共用GPU調度的相關資訊,請參見共用GPU調度。