GPU Operator 与 KubeVirt#
简介#
KubeVirt 是 Kubernetes 的虚拟机管理附加组件,允许您在 Kubernetes 集群中运行和管理虚拟机。它消除了为虚拟机和容器工作负载管理单独集群的需求,因为两者现在可以在单个 Kubernetes 集群中共存。
到目前为止,GPU Operator 仅为运行 GPU 加速容器配置工作节点。现在,GPU Operator 也可用于为运行 GPU 加速虚拟机配置工作节点。
运行带有 GPU 的容器和虚拟机所需的先决条件不同,主要区别在于所需的驱动程序。例如,容器需要数据中心驱动程序,GPU 直通需要 vfio-pci 驱动程序,而创建 vGPU 设备需要NVIDIA vGPU Manager。
现在可以配置 GPU Operator,以便根据配置在这些节点上运行的 GPU 工作负载,在工作节点上部署不同的软件组件。考虑以下示例。
节点 A 接收以下软件组件
NVIDIA Datacenter Driver
- 用于安装驱动程序NVIDIA Container Toolkit
- 用于确保容器可以正确访问 GPUNVIDIA Kubernetes Device Plugin
- 用于发现和向 kubelet 通告 GPU 资源NVIDIA DCGM 和 DCGM Exporter
- 用于监控 GPU
节点 B 接收以下软件组件
VFIO Manager
- 用于加载 vfio-pci 并将其绑定到节点上的所有 GPUSandbox Device Plugin
- 用于发现和向 kubelet 通告直通 GPU
节点 C 接收以下软件组件
NVIDIA vGPU Manager
- 用于安装驱动程序NVIDIA vGPU Device Manager
- 用于在节点上创建 vGPU 设备Sandbox Device Plugin
- 用于发现和向 kubelet 通告 vGPU 设备
假设、约束和依赖项#
一个 GPU 工作节点可以运行特定类型的 GPU 工作负载 - 容器、带有 GPU 直通的虚拟机或带有 vGPU 的虚拟机 - 但不能运行它们的任何组合。
集群管理员或开发人员预先了解其集群,并且可以正确标记节点以指示它们将运行的 GPU 工作负载类型。
运行 GPU 加速虚拟机(带有 pGPU 或 vGPU)的工作节点假定为裸机。
GPU Operator 不会自动在附加了 GPU/vGPU 的 KubeVirt 虚拟机内部安装 NVIDIA 驱动程序。
用户必须手动将所有直通 GPU 和 vGPU 资源添加到 KubeVirt CR 中的
permittedDevices
列表,然后才能将它们分配给 KubeVirt 虚拟机。有关更多信息,请参阅KubeVirt 文档。不支持 MIG 支持的 vGPU。
先决条件#
虚拟化和 IOMMU 扩展(Intel VT-d 或 AMD IOMMU)在 BIOS 中启用。
主机使用内核命令行上的
intel_iommu=on
或amd_iommu=on
启动。如果计划使用 NVIDIA vGPU,如果您的 GPU 基于 NVIDIA Ampere 架构或更高版本,则必须在 BIOS 中启用 SR-IOV。请参阅NVIDIA vGPU 文档,以确保您已满足使用 NVIDIA vGPU 的所有先决条件。
KubeVirt 已安装在集群中。
从 KubeVirt v0.58.2 和 v0.59.1 开始,设置
DisableMDEVConfiguration
功能门$ kubectl patch kubevirt -n kubevirt kubevirt --type='json' \ -p='[{"op": "add", "path": "/spec/configuration/developerConfiguration/featureGates/-", "value": "DisableMDEVConfiguration" }]'
示例输出
kubevirt.kubevirt.io/kubevirt patched
快速入门#
将 GPU Operator 与 KubeVirt 结合使用的高级工作流程如下
确保禁用中介设备配置功能门已设置。
根据工作节点将运行的 GPU 工作负载标记工作节点。
安装 GPU Operator 并设置
sandboxWorkloads.enabled=true
如果使用 NVIDIA vGPU,则需要其他步骤,将在后续章节中介绍
标记工作节点#
使用以下命令向工作节点添加标签
$ kubectl 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>
。
安装 GPU Operator#
根据您是否计划使用 NVIDIA vGPU,按照以下子章节之一安装 GPU Operator。
通常,ClusterPolicy
中的标志 sandboxWorkloads.enabled
控制 GPU Operator 是否可以为虚拟机工作负载以及容器工作负载配置 GPU 工作节点。默认情况下禁用此标志,这意味着所有节点都配置了相同的软件以启用容器工作负载,并且不使用 nvidia.com/gpu.workload.config
节点标签。
注意
术语 sandboxing
指的是在单独隔离的环境中运行软件,通常是为了增加安全性(即虚拟机)。我们使用术语 sandbox workloads
来表示在虚拟机中运行的工作负载,而与所使用的虚拟化技术无关。
安装 GPU Operator(不带 NVIDIA vGPU)#
安装 GPU Operator,启用 sandboxWorkloads
$ helm install --wait --generate-name \
-n gpu-operator --create-namespace \
nvidia/gpu-operator \
--version=v24.9.2 \
--set sandboxWorkloads.enabled=true
安装 GPU Operator(带 NVIDIA vGPU)#
构建私有 NVIDIA vGPU Manager 容器镜像并推送到私有注册表。按照本节中提供的步骤操作。
为 GPU Operator 创建命名空间
$ kubectl create namespace gpu-operator
创建 ImagePullSecret 以访问 NVIDIA vGPU Manager 镜像
$ kubectl create secret docker-registry ${REGISTRY_SECRET_NAME} \
--docker-server=${PRIVATE_REGISTRY} --docker-username=<username> \
--docker-password=<password> \
--docker-email=<email-id> -n gpu-operator
安装启用了 sandboxWorkloads
和 vgpuManager
的 GPU Operator,并指定先前构建的 NVIDIA vGPU Manager 镜像
$ helm install --wait --generate-name \
-n gpu-operator --create-namespace \
nvidia/gpu-operator \
--version=v24.9.2 \
--set sandboxWorkloads.enabled=true \
--set vgpuManager.enabled=true \
--set vgpuManager.repository=<path to private repository> \
--set vgpuManager.image=vgpu-manager \
--set vgpuManager.version=<driver version> \
--set vgpuManager.imagePullSecrets={${REGISTRY_SECRET_NAME}}
由 GPU Operator 部署的 vGPU 设备管理器会自动创建 vGPU 设备,这些设备可以分配给 KubeVirt 虚拟机。在没有其他配置的情况下,GPU Operator 会在所有 GPU 上创建一组默认设备。要了解有关 vGPU 设备管理器以及如何配置在集群中创建哪些类型的 vGPU 设备的更多信息,请参阅vGPU 设备配置。
向 KubeVirt CR 添加 GPU 资源#
更新 KubeVirt 自定义资源,以便允许集群中的所有 GPU 和 vGPU 设备,并且可以将它们分配给虚拟机。
以下示例显示如何允许 A10 GPU 设备和 A10-24Q vGPU 设备。
确定 GPU 设备的资源名称
$ kubectl 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
修改
KubeVirt
自定义资源,如下面的部分示例所示... spec: configuration: developerConfiguration: featureGates: - GPU - DisableMDEVConfiguration permittedHostDevices: pciHostDevices: - externalResourceProvider: true pciVendorSelector: 10DE:2236 resourceName: nvidia.com/GA102GL_A10 mediatedDevices: - externalResourceProvider: true mdevNameSelector: NVIDIA A10-24Q resourceName: nvidia.com/NVIDIA_A10-24Q ...
按如下方式替换 YAML 中的值
pciDeviceSelector
和resourceName
在pciHostDevices
下,以对应于您的 GPU 型号。mdevNameSelector
和resourceName
在mediatedDevices
下,以对应于您的 vGPU 类型。设置
externalResourceProvider=true
以指示此资源由外部设备插件提供,在本例中是由 GPU Operator 部署的sandbox-device-plugin
。
有关配置选项的更多信息,请参阅KubeVirt 用户指南。
创建带有 GPU 的虚拟机#
在 GPU Operator 完成在工作节点上部署沙箱设备插件和 VFIO 管理器 Pod,并将 GPU 资源添加到 KubeVirt 允许列表后,您可以通过编辑 VirtualMachineInstance
清单中的 spec.domain.devices.gpus
字段,将 GPU 分配给虚拟机。
apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachineInstance
...
spec:
domain:
devices:
gpus:
- deviceName: nvidia.com/GA102GL_A10
name: gpu1
...
deviceName
是表示设备的资源名称。name
是用于标识虚拟机中设备的名称
vGPU 设备配置#
vGPU 设备管理器协助在 GPU 工作节点上创建 vGPU 设备。vGPU 设备管理器允许管理员声明性地定义一组他们希望应用于节点上 GPU 的可能的 vGPU 设备配置。在运行时,他们然后将 vGPU 设备管理器指向其中一个配置,而 vGPU 设备管理器负责应用它。配置文件创建为 ConfigMap,并在所有工作节点之间共享。在运行时,可以使用节点标签 nvidia.com/vgpu.config
来决定在任何给定时间实际将这些配置中的哪一个应用于节点。如果节点未标记,则将使用 default
配置。有关此组件及其配置方式的更多信息,请参阅项目 README。
默认情况下,GPU Operator 为 vGPU 设备管理器部署 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
$ kubectl 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 设备配置,前提是节点上当前没有运行带有 vGPU 的虚拟机。任何现有的虚拟机都必须先关闭/迁移。
要在 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 两个)
$ kubectl 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 设备,我们可以像这样标记节点
$ kubectl label node <node-name> --overwrite nvidia.com/vgpu.config=A10-4Q
在 vGPU 设备管理器完成应用新配置后,所有 GPU Operator Pod 应该返回到 Running 状态。
$ kubectl 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 设备。
$ kubectl 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"
}
构建 NVIDIA vGPU Manager 镜像#
注意
仅当您计划使用 NVIDIA vGPU 时才需要构建 NVIDIA vGPU Manager 镜像。如果仅计划使用 PCI 直通,请跳过本节。
本节介绍如何构建 NVIDIA vGPU Manager 容器镜像并将其推送到私有注册表。
从NVIDIA Licensing Portal下载 vGPU 软件。
登录到 NVIDIA Licensing Portal 并导航到 Software Downloads 部分。
NVIDIA vGPU 软件位于 NVIDIA Licensing Portal 的 Software Downloads 部分。
vGPU 软件包以 zip 文件形式打包。下载并解压缩软件包以获取 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 目录。我们以 Ubuntu 20.04 为例。
$ cd vgpu-manager/ubuntu20.04
注意
对于 RedHat OpenShift,运行 cd vgpu-manager/rhel8
以使用 rhel8
文件夹。
从解压后的 zip 文件复制 NVIDIA vGPU Manager
$ cp <local-driver-download-directory>/*-vgpu-kvm.run ./
PRIVATE_REGISTRY
- 用于存储驱动程序镜像的私有注册表的名称VERSION
- 从 NVIDIA Software Portal 下载的 NVIDIA vGPU Manager 版本OS_TAG
- 这必须与 Guest OS 版本匹配。在下面的示例中,使用 ubuntu20.04
。对于 RedHat OpenShift,这应该设置为 rhcos4.x
,其中 x 是支持的次要 OCP 版本。CUDA_VERSION
- 用于构建驱动程序镜像的 CUDA 基础镜像版本。$ export PRIVATE_REGISTRY=my/private/registry VERSION=510.73.06 OS_TAG=ubuntu20.04 CUDA_VERSION=11.7.1
构建 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 镜像推送到您的私有注册表。
$ docker push ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG}