物理 GPU 直通环境准备

虚拟机中的物理 GPU 直通是指在虚拟化环境中将实际的 Graphics Processing Unit (GPU) 直接分配给虚拟机的过程。这样虚拟机可以直接访问和使用物理 GPU,实现与直接运行在物理机上相当的图形性能,避免了虚拟图形适配器带来的性能瓶颈,从而提升整体性能。

约束与限制

物理 GPU 直通功能需要使用 kubevirt-gpu-device-plugin;但目前尚无适用于 ARM64 的 kubevirt-gpu-device-plugin 镜像,因此该功能无法在 ARM64 CPU 架构的操作系统中使用。

前提条件

Chart 和镜像准备

获取以下 Chart 和镜像并上传至镜像仓库。本文档以 build-harbor.example.cn 作为示例仓库地址。关于获取 Chart 和镜像的具体方法,请联系相关人员。

Chart

  • build-harbor.example.cn/example/chart-gpu-operator:v23 .9.1

镜像

  • build-harbor.example.cn/3rdparty/nvidia/gpu-operator:v23 .9.0
  • build-harbor.example.cn/3rdparty/nvidia/cloud-native/gpu-operator-validator:v23 .9.0
  • build-harbor.example.cn/3rdparty/nvidia/cuda:12 .3.1-base-ubi8
  • build-harbor.example.cn/3rdparty/nvidia/kubevirt-gpu-device-plugin:v1 .2.4
  • build-harbor.example.cn/3rdparty/nvidia/nfd/node-feature-discovery:v0 .14.2

启用 IOMMU

不同操作系统启用 IOMMU 的操作步骤不同,请参考对应操作系统的文档。本文档以 CentOS 为例,所有命令均在终端执行。

  1. 编辑 /etc/default/grub 文件,在 GRUB_CMDLINE_LINUX 配置项中添加 intel_iommu=on iommu=pt

    GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet intel_iommu=on iommu=pt"
  2. 执行以下命令生成 grub.cfg 文件。

    grub2-mkconfig -o /boot/grub2/grub.cfg
  3. 重启服务器。

  4. 运行以下命令确认 IOMMU 是否成功启用,若输出包含 IOMMU enabled,则表示启用成功。

    dmesg | grep -i iommu

操作步骤

注意:除非另有说明,以下所有命令均应在对应集群 Master 节点的 CLI 工具中执行。

创建命名空间

执行以下命令创建名为 gpu-system 的命名空间,若输出显示 namespace/gpu-system created,表示创建成功。

kubectl create ns gpu-system

部署 gpu-operator

  1. 执行以下命令部署 gpu-operator。

    export REGISTRY=<registry> # 将 <registry> 替换为 gpu-operator 镜像所在的仓库地址,例如:export REGISTRY=build-harbor.example.cn
    
    cat <<EOF | kubectl create -f -
    apiVersion: operator.alauda.io/v1alpha1
    kind: AppRelease
    metadata:
      annotations:
        auto-recycle: "true"
        interval-sync: "true"
      name: gpu-operator
      namespace: gpu-system
    spec:
      destination:
        cluster: ""
        namespace: "gpu-operator"
      source:
        charts:
        - name: <chartName> # 将 <chartName> 替换为实际的 chart 路径,例如:name = example/chart-gpu-operator
          releaseName: gpu-operator
          targetRevision: v23.9.1
        repoURL: $REGISTRY
      timeout: 120
      values:
        global:
          registry:
            address: $REGISTRY
        nfd:
          enabled: true
        sandboxWorkloads:
          enabled: true
          defaultWorkload: "vm-passthrough"
    EOF
  2. 执行以下命令检查 gpu-operator 是否同步完成,若 SYNC 显示为 Synced,表示同步成功。

    kubectl -n gpu-system get apprelease gpu-operator

    输出信息:

    NAME           SYNC           HEALTH        MESSAGE        UPDATE   AGE
    gpu-operator   Synced         Ready         chart synced   28s      32s
  3. 执行以下命令获取所有节点名称,找到 GPU 节点名称。

    kubectl get nodes -o wide
  4. 执行以下命令检查 GPU 节点是否有支持直通的 GPU,若输出包含类似 nvidia.com/GK210GL_TESLA_K80 的 GPU 信息,表示存在支持直通的 GPU。

    kubectl get node <gpu-node-name> -o jsonpath='{.status.allocatable}' # 将 <gpu-node-name> 替换为步骤 3 中获取的 GPU 节点名称

    输出信息:

    {"cpu":"39","devices.kubevirt.io/kvm":"1k","devices.kubevirt.io/tun":"1k","devices.kubevirt.io/vhost-net":"1k","ephemeral-storage":"426562784165","hugepages-1Gi":"0","hugepages-2Mi":"0","memory":"122915848Ki","nvidia.com/GK210GL_TESLA_K80":"8","pods":"256"}
  5. 至此,gpu-operator 已成功部署。

配置 Kubevirt

  1. 执行以下命令启用 DisableMDEVConfiguration 功能,若返回类似 hyperconverged.hco.kubevirt.io/kubevirt-hyperconverged patched 的信息,表示启用成功。

    kubectl patch hco kubevirt-hyperconverged -n kubevirt --type='json' -p='[{"op": "add", "path": "/spec/featureGates/disableMDevConfiguration", "value": true }]'
  2. 在 GPU 节点终端执行以下命令获取 pciDeviceSelector,输出中的 10de:102d 即为 pciDeviceSelector 的值。

    lspci -nn | grep -i nvidia

    输出信息:

    04:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    05:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    08:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    09:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    85:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    86:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    89:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
    8a:00.0 3D controller [0302]: NVIDIA Corporation GK210GL [Tesla K80] [10de:102d] (rev a1)
  3. 执行以下命令获取所有节点名称,找到 GPU 节点名称。

    kubectl get nodes -o wide
  4. 执行以下命令获取 resourceName,输出中的 nvidia.com/GK210GL_TESLA_K80 即为 resourceName 的值。

    kubectl get node <gpu-node-name> -o jsonpath='{.status.allocatable}' # 将 <gpu-node-name> 替换为步骤 3 中获取的 GPU 节点名称

    输出信息:

    {"cpu":"39","devices.kubevirt.io/kvm":"1k","devices.kubevirt.io/tun":"1k","devices.kubevirt.io/vhost-net":"1k","ephemeral-storage":"426562784165","hugepages-1Gi":"0","hugepages-2Mi":"0","memory":"122915848Ki","nvidia.com/GK210GL_TESLA_K80":"8","pods":"256"}
  5. 执行以下命令添加直通 GPU。

    注意:将下述命令中 <pci-devices-id> 替换为步骤 2 中获取的 pciDeviceSelector 值时,pciDeviceSelector 中的所有字母必须转换为大写。例如,若 pciDeviceSelector 值为 10de:102d,则应替换为 export DEVICE=10DE:102D

    • 添加单张 GPU 卡

      export DEVICE=<pci-devices-id> # 将 <pci-devices-id> 替换为步骤 2 中获取的 pciDeviceSelector,例如:export DEVICE=10DE:102D
      export RESOURCE=<resource-name> # 将 <resource-name> 替换为步骤 4 中获取的 resourceName,例如:export RESOURCE=nvidia.com/GK210GL_TESLA_K80
      
      kubectl patch hco kubevirt-hyperconverged -n kubevirt --type='json' -p='
      [
        {
          "op": "add",
          "path": "/spec/permittedHostDevices",
          "value": {
            "pciHostDevices": [
              {
                "externalResourceProvider": true,
                "pciDeviceSelector": "'"$DEVICE"'",
                "resourceName": "'"$RESOURCE"'"
              }
            ]
          }
        }
      ]'
    • 添加多张 GPU 卡

      注意:添加多张 GPU 卡时,用于替换 <pci-devices-id> 的每个 pciDeviceSelector 值必须唯一。

      export DEVICE1=<pci-devices-id1> # 将 <pci-devices-id1> 替换为步骤 2 中获取的 pciDeviceSelector
      export RESOURCE1=<resource-name1> # 将 <resource-name1> 替换为步骤 4 中获取的 resourceName
      export DEVICE2=<pci-devices-id2> # 将 <pci-devices-id2> 替换为步骤 2 中获取的 pciDeviceSelector
      export RESOURCE2=<resource-name2> # 将 <resource-name2> 替换为步骤 4 中获取的 resourceName
      
      kubectl patch hco kubevirt-hyperconverged -n kubevirt --type='json' -p='
      [
        {
          "op": "add",
          "path": "/spec/permittedHostDevices",
          "value": {
            "pciHostDevices": [
              {
                "externalResourceProvider": true,
                "pciDeviceSelector": "'"$DEVICE"'",
                "resourceName": "'"$RESOURCE"'"
              },
              {
                "externalResourceProvider": true,
                "pciDeviceSelector": "'"$DEVICE2"'",
                "resourceName": "'"$RESOURCE2"'"
              }
            ]
          }
        }
      ]'
    • 已添加 GPU 卡后新增 GPU 卡

      export DEVICE=<pci-devices-id> # 将 <pci-devices-id> 替换为步骤 2 中获取的 pciDeviceSelector
      export RESOURCE=<resource-name> # 将 <resource-name> 替换为步骤 4 中获取的 resourceName
      export INDEX=<index> # index 是从零开始的数组索引,用数字替换 <index>,例如:已添加一张 GPU 卡,现需添加另一张,则 index 应为 1,即 export INDEX=1
      
      kubectl patch hco kubevirt-hyperconverged -n kubevirt --type='json' -p='
      [
        {
          "op": "add",
          "path": "/spec/permittedHostDevices/pciHostDevices/'"${INDEX}"'",
          "value": {
            "externalResourceProvider": true,
            "pciDeviceSelector": "'"$DEVICE"'",
            "resourceName": "'"$RESOURCE"'"
          }
        }
      ]'

结果验证

完成上述配置步骤后,创建虚拟机时若能选择对应的物理 GPU,表示物理 GPU 直通环境已成功准备。

注意:若需配置物理 GPU 直通,请提前启用相关功能。

  1. 进入 Container Platform

  2. 在左侧导航栏点击 Virtualization > Virtual Machines

  3. 点击 Create Virtual Machine

  4. 配置虚拟机的 Physical GPU (Alpha) 参数。

    参数说明
    Physical GPU (Alpha)选择已配置的物理 GPU 型号。每个虚拟机只能分配一张物理 GPU。
  5. 至此,物理 GPU 直通环境已成功准备。

相关操作

删除带直通 GPU 的虚拟机

  1. 进入 Container Platform

  2. 在左侧导航栏点击 Virtualization > Virtual Machines

  3. 在列表页,点击待删除虚拟机右侧的 ⋮ > Delete,或点击待删除虚拟机名称进入详情页,点击 Actions > Delete

  4. 输入确认信息,删除带直通 GPU 的虚拟机。

从 KubeVirt 移除 GPU 相关配置

  1. 在对应 GPU 集群 Master 节点,使用 CLI 工具执行以下命令,从 KubeVirt 移除 GPU 相关配置。

    kubectl patch hco kubevirt-hyperconverged -n kubevirt --type='json' -p='[{"op": "remove", "path": "/spec/permittedHostDevices"}]'
  2. 删除后,若通过 Container Platform 创建虚拟机时无法选择对应的物理 GPU 型号,表示删除成功。具体创建虚拟机步骤请参考 Select Physical GPU Model

卸载 gpu-operator

  1. 在对应 GPU 集群 Master 节点,使用 CLI 工具执行以下命令卸载 gpu-operator。

    kubectl -n gpu-system delete apprelease gpu-operator

    输出信息:

    apprelease.operator.alauda.io "gpu-operator" deleted
  2. 执行命令后,若收到如下响应,表示 gpu-operator 已成功卸载。

    kubectl -n gpu-system get apprelease gpu-operator

    输出信息:

    Error from server (NotFound): appreleases.operator.alauda.io "gpu-operator" not found