带有 OpenShift 虚拟化的 NVIDIA GPU Operator#

简介#

Red Hat 客户对在 Red Hat OpenShift Virtualization 中使用虚拟 GPU (NVIDIA vGPU) 的需求日益增长。Red Hat OpenShift Virtualization 基于 KubeVirt,KubeVirt 是 Kubernetes 的虚拟机 (VM) 管理附加组件,允许您在 Kubernetes 集群中运行和管理 VM。它消除了管理 VM 和容器工作负载的单独集群的需求,因为两者现在可以在单个 Kubernetes 集群中共存。Red Hat OpenShift Virtualization 是 OpenShift 的一项功能,用于运行由 OpenShift (Kubernetes) 编排的虚拟机 (VM)。

到目前为止,GPU Operator 仅为运行 GPU 加速容器配置工作节点。现在,GPU Operator 也可用于为运行 GPU 加速 VM 配置工作节点。

运行带有 GPU 的容器和 VM 所需的先决条件有所不同,主要区别在于所需的驱动程序。例如,容器需要数据中心驱动程序,GPU 直通需要 vfio-pci 驱动程序,创建 vGPU 设备需要 NVIDIA vGPU Manager。

现在可以配置 GPU Operator,以便根据配置在这些节点上运行的 GPU 工作负载,在工作节点上部署不同的软件组件。考虑以下示例。

节点 A 配置为运行容器。
节点 B 配置为运行带有直通 GPU 的 VM。
节点 C 配置为运行带有 vGPU 的 VM。

节点 A 接收以下软件组件

  • NVIDIA Datacenter Driver - 用于安装驱动程序。

  • NVIDIA Container Toolkit - 确保容器可以正确访问 GPU。

  • NVIDIA Kubernetes Device Plugin - 用于发现和向 kubelet 公告 GPU 资源。

  • NVIDIA DCGM and DCGM Exporter - 用于监控 GPU。

节点 B 接收以下软件组件

  • VFIO Manager - 可选。用于加载 vfio-pci 并将其绑定到节点上的所有 GPU。

  • Sandbox Device Plugin - 可选。用于发现和向 kubelet 公告直通 GPU。

节点 C 接收以下软件组件

  • NVIDIA vGPU Manager - 用于安装驱动程序。

  • NVIDIA vGPU Device Manager - 用于在节点上创建 vGPU 设备。

  • Sandbox Device Plugin - 可选。用于发现和向 kubelet 公告 vGPU 设备。

假设、约束和依赖项#

  • 一个工作节点可以运行 GPU 加速容器,或带有 GPU 直通的 GPU 加速 VM,或带有 vGPU 的 GPU 加速 VM,但不能同时运行它们的组合。

  • 集群管理员或开发人员预先了解他们的集群,并且可以正确标记节点以指示他们将运行的 GPU 工作负载类型。

  • 运行 GPU 加速 VM(带有 pGPU 或 vGPU)的工作节点假定为裸金属。

  • 不支持基于 MIG 的 vGPU。

  • GPU Operator 不会自动安装连接了 vGPU 的 KubeVirt VM 内的 vGPU 客户机驱动程序。

  • 有两个独立的设备插件 – NVIDIA k8s-device-plugin 和 NVIDIA kubevirt-gpu-device-plugin。

  • KubeVirt/Openshift 虚拟化提供内置的设备插件。这些是默认的经过测试的设备插件。

前提条件#

  • 安装 OpenShift Virtualization Operator.

  • 安装 virtctl 客户端.

  • 从 OpenShift Virtualization 4.12.3 和 4.13.0 开始,设置 disableMDevConfiguration 功能门控

    $ kubectl patch hyperconverged -n openshift-cnv  kubevirt-hyperconverged --type='json' -p='[{"op": "add", "path": "/spec/featureGates/disableMDevConfiguration", "value": true}]'
    

    示例输出

    hyperconverged.hco.kubevirt.io/kubevirt-hyperconverged patched
    

在主机上启用 IOMMU 驱动程序#

要在内核中启用 IOMMU(输入/输出内存管理单元)驱动程序,请创建 MachineConfig 对象并添加内核参数。

前提条件#

  • 正常运行的 OpenShift 容器平台集群的管理权限。

  • Intel 或 AMD CPU 硬件。

  • BIOS(基本输入/输出系统)中启用了 Intel 定向 I/O 扩展虚拟化技术或 AMD IOMMU。

步骤#

  1. 创建一个标识内核参数的 MachineConfig 对象。以下示例显示了 Intel CPU 的内核参数

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker
      name: 100-worker-iommu
    spec:
      config:
        ignition:
          version: 3.2.0
      kernelArguments:
          - intel_iommu=on
    
  2. 创建新的 MachineConfig 对象

    $ oc create -f 100-worker-kernel-arg-iommu.yaml
    
  3. 验证新的 MachineConfig 对象已添加

    $ oc get machineconfig
    

标记工作节点#

使用以下命令向工作节点添加标签

$ oc label node <node-name> --overwrite nvidia.com/gpu.workload.config=vm-vgpu

您可以将以下值分配给标签:containervm-passthroughvm-vgpu。GPU Operator 使用此标签的值来确定要部署的操作数。

如果节点上不存在节点标签 nvidia.com/gpu.workload.config,则 GPU Operator 假定默认的 GPU 工作负载配置为 container,并部署支持此工作负载类型所需的软件组件。要更改默认的 GPU 工作负载配置,请在 ClusterPolicy 中设置以下值:sandboxWorkloads.defaultWorkload=<config>

构建 vGPU Manager 镜像#

注意

构建 vGPU Manager 镜像仅在 NVIDIA vGPU 的情况下是必需的。如果您计划仅使用 GPU 直通,请跳过本节。

使用以下步骤构建 vGPU Manager 容器并将其推送到私有 registry。

  1. NVIDIA 许可门户下载 vGPU 软件。

    • 登录到 NVIDIA 许可门户并导航到 软件下载 部分。

    • NVIDIA vGPU 软件位于 软件下载 页面的 驱动程序下载 选项卡上。

    • 单击 Linux KVM 完整 vGPU 软件包的 下载 链接。确认 产品版本 列显示要安装的 vGPU 版本。解压缩捆绑包以获取 NVIDIA vGPU Manager for Linux 文件,NVIDIA-Linux-x86_64-<version>-vgpu-kvm.run

    注意

    NVIDIA AI Enterprise 客户必须使用 aie .run 文件来构建 NVIDIA vGPU Manager 镜像。请下载 NVIDIA-Linux-x86_64-<version>-vgpu-kvm-aie.run 文件,并将其重命名为 NVIDIA-Linux-x86_64-<version>-vgpu-kvm.run,然后再继续执行其余步骤。

    使用以下步骤克隆驱动程序容器存储库并构建驱动程序镜像。

  2. 打开终端并克隆驱动程序容器镜像存储库

    $ git clone https://gitlab.com/nvidia/container-images/driver
    $ cd driver
    
  3. 切换到您的操作系统的 vgpu-manager 目录

    $ cd vgpu-manager/rhel
    
  4. 从解压缩的 zip 文件中复制 NVIDIA vGPU Manager

    $ cp <local-driver-download-directory>/*-vgpu-kvm.run ./
    
  5. 设置以下环境变量

    • PRIVATE_REGISTRY - 用于存储驱动程序镜像的私有 registry 的名称。

    • VERSION - 从 NVIDIA 软件门户下载的 NVIDIA vGPU Manager 版本。

    • OS_TAG - 这必须与 Guest OS 版本匹配。对于 RedHat OpenShift,请指定 rhcos4.x,其中 _x_ 是受支持的次要 OCP 版本。

    • CUDA_VERSION - 用于构建驱动程序镜像的 CUDA 基础镜像版本。

    $ export PRIVATE_REGISTRY=my/private/registry VERSION=510.73.06 OS_TAG=rhcos4.11 CUDA_VERSION=11.7.1
    

    注意

    建议使用的 registry 是集成的 OpenShift 容器平台 registry。有关 registry 的更多信息,请参阅 访问 registry

  6. 构建 NVIDIA vGPU Manager 镜像

    $ docker build \
        --build-arg DRIVER_VERSION=${VERSION} \
        --build-arg CUDA_VERSION=${CUDA_VERSION} \
        -t ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG} .
    
  7. 将 NVIDIA vGPU Manager 镜像推送到您的私有 registry

    $ docker push ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG}
    

使用 CLI 安装 NVIDIA GPU Operator#

使用 安装 NVIDIA GPU Operator 中的指南安装 NVIDIA GPU Operator。

注意

当提示创建集群策略时,请遵循 为 GPU Operator 创建 ClusterPolicy 中的指南。

创建 secret#

OpenShift 具有 secret 对象类型,它提供了一种机制来保存敏感信息,例如密码和私有源存储库凭据。接下来,您将创建一个 secret 对象,用于存储您的 registry API 密钥(用于验证您对私有容器 registry 的访问权限的机制)。

注意

在开始之前,您需要为您的私有 registry 生成或使用现有的 API 密钥。

  1. 导航到 主页 > 项目 并确保选择了 nvidia-gpu-operator

  2. 在 OpenShift 容器平台 Web 控制台中,从工作负载下拉列表中单击 Secrets

  3. 单击 创建 下拉列表。

  4. 选择镜像拉取 Secret。

    _images/secrets.png
  5. 在每个字段中输入以下内容

    • Secret 名称: private-registry-secret

    • 身份验证类型: 镜像 registry 凭据

    • Registry 服务器地址: <private-registry_address>

    • 用户名: $oauthtoken

    • 密码: <API-KEY>

    • 电子邮件: <YOUR-EMAIL>

  6. 单击 创建

    已创建拉取 secret。

为 GPU Operator 创建 ClusterPolicy#

作为集群管理员,您可以使用 OpenShift 容器平台 CLI 创建 ClusterPolicy。使用 CLI 创建集群策略

  1. 创建 ClusterPolicy

    $ oc get csv -n nvidia-gpu-operator gpu-operator-certified.v22.9.0 -ojsonpath={.metadata.annotations.alm-examples} | jq .[0] > clusterpolicy.json
    
  2. 如下修改 clusterpolicy.json 文件

    注意

    仅当您要使用 NVIDIA vGPU 时,才需要 vgpuManager 选项。如果您仅使用 GPU 直通,则不应设置这些选项。

    • sandboxWorloads.enabled=true

    • vgpuManager.enabled=true

    • vgpuManager.repository=<私有存储库路径>

    • vgpuManager.image=vgpu-manager

    • vgpuManager.version=<驱动程序版本>

    • vgpuManager.imagePullSecrets={<镜像拉取 secret 的名称>}

  3. 应用更改

    $ oc apply -f clusterpolicy.json
    
    clusterpolicy.nvidia.com/gpu-cluster-policy created
    

由 GPU Operator 部署的 vGPU Device Manager 会自动创建 vGPU 设备,这些设备可以分配给 KubeVirt VM。在没有其他配置的情况下,GPU Operator 会在所有 GPU 上创建一组默认设备。要了解有关 vGPU Device Manager 以及如何配置在集群中创建哪些类型的 vGPU 设备的更多信息,请参阅 vGPU 设备配置

将 GPU 资源添加到 HyperConverged 自定义资源#

更新 HyperConverged 自定义资源,以便允许集群中的所有 GPU 和 vGPU 设备并可以将它们分配给虚拟机。

以下示例允许 A10 GPU 设备和 A10-24Q vGPU 设备。

  1. 确定 GPU 设备的资源名称

    $ oc get node cnt-server-2 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("nvidia.com/"))) | with_entries(select(.value != "0"))'
    

    示例输出

    {
      "nvidia.com/NVIDIA_A10-12Q": "4"
    }
    
  2. 确定 GPU 的 PCI 设备 ID。

    • 您可以在 PCI ID 数据库中按设备名称搜索。

    • 如果您具有对节点的 host 访问权限,则可以使用类似于以下示例的命令列出 NVIDIA GPU 设备

      $ lspci -nnk -d 10de:
      

      示例输出

      65:00.0 3D controller [0302]: NVIDIA Corporation GA102GL [A10] [10de:2236] (rev a1)
              Subsystem: NVIDIA Corporation GA102GL [A10] [10de:1482]
              Kernel modules: nvidiafb, nouveau
      
  3. 像以下部分示例一样修改 HyperConverged 自定义资源

    ...
    spec:
      featureGates:
        disableMDevConfiguration: true
      permittedHostDevices:
        pciHostDevices:
        - externalResourceProvider: true
          pciDeviceSelector: 10DE:2236
          resourceName: nvidia.com/GA102GL_A10
        mediatedDevices:
        - externalResourceProvider: true
          mdevNameSelector: NVIDIA A10-24Q
          resourceName: nvidia.com/NVIDIA_A10-24Q
    ...
    

    如下替换 YAML 中的值

    • pciHostDevices 下的 pciDeviceSelectorresourceName 以对应于您的 GPU 型号。

    • mediatedDevices 下的 mdevNameSelectorresourceName 以对应于您的 vGPU 类型。

    • 设置 externalResourceProvider=true 以指示此资源由外部设备插件提供,在本例中是由 GPU Operator 部署的 sandbox-device-plugin

有关配置选项的更多信息,请参阅 KubeVirt 用户指南

关于中介设备#

被划分为一个或多个虚拟设备的物理设备。vGPU 是一种中介设备 (mdev);物理 GPU 的性能在虚拟设备之间分配。您可以将中介设备分配给一个或多个虚拟机 (VM),但客户机的数量必须与您的 GPU 兼容。某些 GPU 不支持多个客户机。

创建带有 GPU 的虚拟机#

将 GPU 设备(直通或 vGPU)分配给虚拟机。

前提条件#

  • GPU 设备在 HyperConverged 自定义资源 (CR) 中配置。

步骤#

  1. 通过编辑 VirtualMachine 清单的 spec.domain.devices.gpus 字段,将 GPU 设备分配给虚拟机 (VM)

    apiVersion: kubevirt.io/v1
    kind: VirtualMachine
    ...
    spec:
      domain:
        devices:
          gpus:
          - deviceName: nvidia.com/GA102GL_A10
            name: gpu1
          - deviceName: nvidia.com/GRID_T4-1Q
            name: gpu2
    ...
    
    • deviceName 与 GPU 关联的资源名称。

    • name 用于标识 VM 上设备的名称。

vGPU 设备配置#

vGPU Device Manager 协助在 GPU 工作节点上创建 vGPU 设备。

vGPU Device Manager 允许管理员声明性地定义一组他们希望应用于节点上 GPU 的可能的 vGPU 设备配置。在运行时,他们将 vGPU Device Manager 指向其中一个配置,而 vGPU Device Manager 负责应用它。

配置文件创建为 ConfigMap,并在所有工作节点之间共享。在运行时,可以使用节点标签 nvidia.com/vgpu.config 来决定在任何给定时间实际将这些配置中的哪一个应用于节点。如果节点未标记,则将使用 default 配置。

有关此组件及其配置方式的更多信息,请参阅项目 README

默认情况下,GPU Operator 为 vGPU Device Manager 部署 ConfigMap,其中包含 NVIDIA vGPU 支持的所有 vGPU 类型的命名配置。用户可以通过应用 nvidia.com/vgpu.config 节点标签为工作节点选择特定配置。

例如,使用 nvidia.com/vgpu.config=A10-8Q 标记节点将在节点上所有 A10 GPU 上创建 3 个 A10-8Q 类型的 vGPU 设备(注意:3 是每个 GPU 可以创建的 A10-8Q 设备的最大数量)。如果节点未标记,则将应用 default 配置。

default 配置将在所有 GPU 上创建 Q 系列 vGPU 设备,其中每个 vGPU 设备的帧缓冲区内存量是 GPU 总内存的一半。例如,default 配置将在所有 A10 GPU 上创建两个 A10-12Q 设备,在所有 V100 GPU 上创建两个 V100-8Q 设备,并在所有 T4 GPU 上创建两个 T4-8Q 设备。

如果需要自定义 vGPU 设备配置,超出默认 ConfigMap 提供的范围,您可以创建自己的 ConfigMap

$ oc create configmap custom-vgpu-config -n gpu-operator --from-file=config.yaml=/path/to/file

然后通过设置 vgpuDeviceManager.config.name=custom-vgpu-config 来配置 GPU Operator 以使用它。

应用新的 vGPU 设备配置#

通过设置 nvidia.com/vgpu.config 节点标签,在每个节点的基础上应用特定的 vGPU 设备配置。如果您不希望应用默认配置,建议在安装 GPU Operator 之前设置此节点标签。

在成功应用 vGPU 设备配置后切换配置,前提是节点上当前没有运行带有 vGPU 的 VM。任何现有的 VM 都必须先关闭/迁移。

要在 GPU Operator 安装后应用新配置,只需更新 nvidia.com/vgpu.config 节点标签。

让我们在一个具有两个 A10 GPU 的系统上运行一个示例。

$ nvidia-smi -L
GPU 0: NVIDIA A10 (UUID: GPU-ebd34bdf-1083-eaac-2aff-4b71a022f9bd)
GPU 1: NVIDIA A10 (UUID: GPU-1795e88b-3395-b27b-dad8-0488474eec0c)

按照前面部分详述的步骤安装 GPU Operator 后,并且在没有使用 nvidia.com/vgpu.config 标记节点的情况下,将应用 default vGPU 配置 – 创建四个 A10-12Q 设备(每个 GPU 两个)

$ oc get node cnt-server-2 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("nvidia.com/"))) | with_entries(select(.value != "0"))'
{
  "nvidia.com/NVIDIA_A10-12Q": "4"
}

如果您改为要创建 A10-4Q 设备,我们可以像这样标记节点

$ oc label node <node-name> --overwrite nvidia.com/vgpu.config=A10-4Q

在 vGPU Device Manager 完成应用新配置后,所有 GPU Operator pod 都应返回到 Running 状态。

$ oc get pods -n gpu-operator
NAME                                                          READY   STATUS    RESTARTS   AGE
...
nvidia-sandbox-device-plugin-daemonset-brtb6                  1/1     Running   0          10s
nvidia-sandbox-validator-ljnwg                                1/1     Running   0          10s
nvidia-vgpu-device-manager-8mgg8                              1/1     Running   0          30m
nvidia-vgpu-manager-daemonset-fpplc                           1/1     Running   0          31m

您现在应该在节点上看到 12 个 A10-4Q 设备,因为每个 A10 GPU 可以创建 6 个 A10-4Q 设备。

$ oc get node cnt-server-2 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("nvidia.com/"))) | with_entries(select(.value != "0"))'
{
  "nvidia.com/NVIDIA_A10-4Q": "12"
}