带有 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 接收以下软件组件
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 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。
步骤#
创建一个标识内核参数的
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
创建新的
MachineConfig
对象$ oc create -f 100-worker-kernel-arg-iommu.yaml
验证新的
MachineConfig
对象已添加$ oc get machineconfig
标记工作节点#
使用以下命令向工作节点添加标签
$ oc label node <node-name> --overwrite nvidia.com/gpu.workload.config=vm-vgpu
您可以将以下值分配给标签:container
、vm-passthrough
和 vm-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。
从 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
,然后再继续执行其余步骤。使用以下步骤克隆驱动程序容器存储库并构建驱动程序镜像。
打开终端并克隆驱动程序容器镜像存储库
$ git clone https://gitlab.com/nvidia/container-images/driver $ cd driver
切换到您的操作系统的
vgpu-manager
目录$ cd vgpu-manager/rhel
从解压缩的 zip 文件中复制 NVIDIA vGPU Manager
$ cp <local-driver-download-directory>/*-vgpu-kvm.run ./
设置以下环境变量
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。
构建 NVIDIA vGPU Manager 镜像
$ docker build \ --build-arg DRIVER_VERSION=${VERSION} \ --build-arg CUDA_VERSION=${CUDA_VERSION} \ -t ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG} .
将 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 密钥。
导航到 主页 > 项目 并确保选择了
nvidia-gpu-operator
。在 OpenShift 容器平台 Web 控制台中,从工作负载下拉列表中单击 Secrets。
单击 创建 下拉列表。
选择镜像拉取 Secret。
在每个字段中输入以下内容
Secret 名称: private-registry-secret
身份验证类型: 镜像 registry 凭据
Registry 服务器地址: <private-registry_address>
用户名: $oauthtoken
密码: <API-KEY>
电子邮件: <YOUR-EMAIL>
单击 创建。
已创建拉取 secret。
为 GPU Operator 创建 ClusterPolicy#
作为集群管理员,您可以使用 OpenShift 容器平台 CLI 创建 ClusterPolicy。使用 CLI 创建集群策略
创建 ClusterPolicy
$ oc get csv -n nvidia-gpu-operator gpu-operator-certified.v22.9.0 -ojsonpath={.metadata.annotations.alm-examples} | jq .[0] > clusterpolicy.json
如下修改
clusterpolicy.json
文件注意
仅当您要使用 NVIDIA vGPU 时,才需要
vgpuManager
选项。如果您仅使用 GPU 直通,则不应设置这些选项。sandboxWorloads.enabled=true
vgpuManager.enabled=true
vgpuManager.repository=<私有存储库路径>
vgpuManager.image=vgpu-manager
vgpuManager.version=<驱动程序版本>
vgpuManager.imagePullSecrets={<镜像拉取 secret 的名称>}
应用更改
$ 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 设备。
确定 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" }
确定 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
像以下部分示例一样修改
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
下的pciDeviceSelector
和resourceName
以对应于您的 GPU 型号。mediatedDevices
下的mdevNameSelector
和resourceName
以对应于您的 vGPU 类型。设置
externalResourceProvider=true
以指示此资源由外部设备插件提供,在本例中是由 GPU Operator 部署的sandbox-device-plugin
。
有关配置选项的更多信息,请参阅 KubeVirt 用户指南。
关于中介设备#
被划分为一个或多个虚拟设备的物理设备。vGPU 是一种中介设备 (mdev);物理 GPU 的性能在虚拟设备之间分配。您可以将中介设备分配给一个或多个虚拟机 (VM),但客户机的数量必须与您的 GPU 兼容。某些 GPU 不支持多个客户机。
创建带有 GPU 的虚拟机#
将 GPU 设备(直通或 vGPU)分配给虚拟机。
前提条件#
GPU 设备在
HyperConverged
自定义资源 (CR) 中配置。
步骤#
通过编辑
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" }