配置及管理ack-nvidia-device-plugin组件

GPU设备插件(NVIDIA Device Plugin)是Kubernetes集群中用于管理每个节点的GPU的组件,使得Kubernetes能够更方便、高效地利用GPU资源。本文介绍在独占GPU调度场景下,如何对ACK节点的NVIDIA Device Plugin进行升级、重启、GPU设备隔离、版本查看与更新等操作。

使用说明

关于如何查看NVIDIA Device Plugin版本、升级NVIDIA Device Plugin、重启NVIDIA Device Plugin、GPU设备隔离等更多操作,请参见配置及管理NVIDIA Device Plugin

对于以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.04Red Hat Enterprise Linux(RHEL) 9.3 64位,由于ack-nvidia-device-plugin组件会为Pod默认配置环境变量NVIDIA_VISIBLE_DEVICES=all,可能会因为节点执行systemctl daemon-reloadsystemctl daemon-reexec命令后,无法访问GPU设备导致NVIDIA Device Plugin无法正常工作。更多详情,请参见运行GPU容器出现Failed to initialize NVML: Unknown Error的问题怎么办?

  • 若在20250501之前将集群从低版本升级到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.20,建议手动升级集群。相关差异如下所示:

特性

1.32及以上集群版本

1.201.31间集群版本

部署方式

DaemonSet

Static Pod

管理方式

控制台组件管理

手动维护

节点标签要求

ack.node.gpu.schedule=default

无特殊要求

前提条件

查看NVIDIA Device Plugin版本

1.32及以上集群版本

针对以DaemonSet方式部署的组件,可在控制台组件管理页面定位ack-nvidia-device-plugin组件,在组件卡片上查看当前版本。

1.201.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

  1. 升级ack-nvidia-device-plugin组件。

    1.32及以上集群版本

    1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,单击组件管理

    3. 在组件管理页面,搜索ack-nvidia-device-plugin组件,在其卡片位置单击升级

    4. 在弹出的对话框中,单击确定

    1.201.31间集群版本

    1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择节点管理 > 节点

    2. 选中需要批量维护的GPU节点,在节点列表下方单击批量运维,然后在批量运维对话框选择执行Shell命令,单击确定

      重要

      建议先选择少量GPU节点进行升级,操作完成验证节点Device Plugin正常工作后,再大批量操作。

    3. 在自动跳转的OOS界面,选择执行模式失败暂停后,单击下一步:设置参数

    4. 在设置参数页面,选择运行Shell脚本,并粘贴如下示例脚本。

      说明

      脚本中RUN_PKG_VERSION参数需修改为集群对应的大版本号(例如:1.30)。请勿填入小版本号(例如:1.30.1),否则会导致脚本报错。

      #!/bin/bash
      set -e
      
      RUN_PKG_VERSION=1.30
      
      function update_device_plugin() {
      	base_dir=/tmp/update_device_plugin
      	rm -rf $base_dir
      	mkdir -p $base_dir
      	cd $base_dir
      	region_id=$(curl -ssL 100.100.100.200/latest/meta-data/region-id  2> /dev/null || echo "")
      	if [[ $region_id == "" ]]; then
      		echo "Error: failed to get region id,region id is null"
      		exit 1
      	fi
      	PKG_URL=https://aliacs-k8s-${region_id}.oss-${region_id}.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
    5. 单击下一步:确定,确认信息无误后单击创建

      创建后自动跳转至任务执行管理页面,可查看任务运行状态。查看执行输出succeeded to update device plugin,表明更新成功。

  2. 检查组件是否正常运行。

    执行如下命令,查看GPU节点上Device Plugin是否正常工作。

    1. WorkbenchCloudShell上使用kubectl连接集群

    2. 使用如下命令检查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
    3. 判断所有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及以上集群版本

  1. 执行如下命令,查询对应节点的Device Plugin Pod。

    kubectl get pod -n kube-system -l component=nvidia-device-plugin -o wide | grep <NODE>
  2. 执行如下命令,重启对应的Device Plugin Pod。

    kubectl delete po <DEVICE_PLUGIN_POD> -n kube-system 

1.201.31间集群版本

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择节点管理 > 节点池

  2. 节点池页面,单击节点池名称,进入节点管理,登录目标GPU节点。

    如果的操作系统为ContainerOS,为了减少潜在的安全风险,ContainerOS原则上不支持任何用户直接登录到系统进行一系列可能无法追溯的操作,也不提供SSH登录功能。若仍然有登录实例进行运维操作的需求,请参见运维ContainerOS节点
  3. 选中需要批量维护的GPU节点,在节点列表下方单击批量运维,然后在批量运维对话框选择执行shell命令,单击确定

    重要

    建议先选择少量GPU节点进行重启,操作完成验证节点Device Plugin正常工作后,再大批量操作。

  4. 在自动跳转的OOS界面,选择执行模式失败暂停后,单击下一步:设置参数

  5. 在设置参数页面,选择运行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
  6. 单击下一步:确定,确认信息无误后单击创建。创建后自动跳转至任务执行管理页面,可查看任务运行状态。

  7. 执行如下命令,查看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: 1

    GPU节点上报的nvidia.com/gpu扩展资源不为0,说明Device Plugin正常工作。

修改NVIDIA Device Plugin设备标识符

Device-Plugin在为Pod分配设备时会在节点上创建一份Checkpoint文件,用于记录和保存哪些设备已经被分配,以及它们对应Pod的信息。在NVIDIA Device Plugin中,Checkpoint文件默认使用GPUUUID作为每个GPU设备的唯一标识符(Key)。可以参见下文将该Key修改为设备的Index,以解决VM冷迁移导致的UUID丢失等问题。

1.32及以上集群版本

  1. 执行如下命令,修改NVIDIA Device Plugin Daemonset。

    kubectl get ds -n kube-system ack-nvidia-device-plugin
  2. 添加如下环境变量CHECKPOINT_DEVICE_ID_STRATEGY

        env:
          - name: CHECKPOINT_DEVICE_ID_STRATEGY
            value: index
  3. 重启NVIDIA Device Plugin,使得修改内容生效。

1.201.31间集群版本

  1. 在目标节点上的/etc/kubernetes/manifests/nvidia-device-plugin.yml文件中查看Device-Plugin的镜像Tag,其所代表的版本号即为Device-Plugin的版本。如果版本号大于等于0.9.3,则无需修改版本号,否则请将版本号修改为最新的版本号v0.9.3-0dd4d5f5-aliyun

  2. 修改/etc/kubernetes/manifests/nvidia-device-plugin.yml文件中的Static Pod的环境变量,参见以下代码增加一个环境变量CHECKPOINT_DEVICE_ID_STRATEGY

        env:
          - name: CHECKPOINT_DEVICE_ID_STRATEGY
            value: index
  3. 重启NVIDIA Device Plugin,使得修改内容生效。

开启GPU设备隔离功能

重要

GPU设备隔离操作仅支持在nvidia-device-pluginv0.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中填写目标隔离设备的indexuuid(同一个设备只需填写任意一个),保存文件后即可自动生效。

设置完成后,可以通过查看Kubernetes Node上报的Resource中的nvidia.com/gpu资源的数量以查看隔离的效果。

相关文档