在 KubeVirt 中使用 GPU Operator
基于最新的GPU Operator版本24.9.0。
原文链接:GPU Operator with KubeVirt — NVIDIA GPU Operator 24.9.0 documentation
1. 简介
KubeVirt 是 Kubernetes 的一个虚拟机管理插件,允许您在 Kubernetes 集群中运行和管理虚拟机。它消除了为虚拟机和容器工作负载管理独立集群的需求,二者现在可以在单一 Kubernetes 集群中共存。
在此之前,GPU Operator 仅支持为运行 GPU 加速的容器配置工作节点。现在,GPU Operator 也可以用于为运行 GPU 加速的虚拟机配置工作节点。
运行带有 GPU 的容器和虚拟机所需的前提条件不同,主要区别在于所需的驱动程序。例如,数据中心驱动程序用于容器,vfio-pci 驱动程序用于 GPU 直通,而 NVIDIA vGPU Manager 用于创建 vGPU 设备。
现在可以将 GPU Operator 配置为根据节点上配置的 GPU 工作负载来部署不同的软件组件。以下示例展示了这一点。
- 节点 A 被配置为运行容器。
- 节点 B 被配置为运行具有直通 GPU 的虚拟机。
- 节点 C 被配置为运行具有 vGPU 的虚拟机。
节点 A 配置的软件组件:
- NVIDIA 数据中心驱动程序:用于安装驱动程序。
- NVIDIA 容器工具包:确保容器可以正确访问 GPU。
- NVIDIA Kubernetes 设备插件:用于发现 GPU 资源并将其发布给 kubelet。
- NVIDIA DCGM 和 DCGM Exporter:用于监控 GPU。
节点 B 配置的软件组件:
- VFIO 管理器:用于加载 vfio-pci 并将其绑定到节点上的所有 GPU。
- 沙盒设备插件:用于发现 GPU 直通资源并将其发布给 kubelet。
节点 C 配置的软件组件:
- NVIDIA vGPU 管理器:用于安装驱动程序。
- NVIDIA vGPU 设备管理器:用于在节点上创建 vGPU 设备。
- 沙盒设备插件:用于发现 vGPU 设备并将其发布给 kubelet。
2. 假设、约束和依赖项
- 一个 GPU 工作节点可以运行特定类型的 GPU 工作负载——容器、具有 GPU 直通的虚拟机或具有 vGPU 的虚拟机——但不能混合运行这些类型的工作负载。
- 集群管理员或开发者需提前了解集群的需求,并正确地为节点贴上标签,以指示其将运行的 GPU 工作负载类型。
- 运行 GPU 加速虚拟机(使用 pGPU 或 vGPU)的工作节点假定为裸机。
- GPU Operator 不会自动在附带 GPU/vGPU 的 KubeVirt 虚拟机中安装 NVIDIA 驱动。
- 用户在将 GPU 直通和 vGPU 资源分配给 KubeVirt 虚拟机之前,必须手动将所有 GPU 直通和 vGPU 资源添加到 KubeVirt CR 中的
permittedDevices
列表中。有关更多信息,请参阅 KubeVirt 文档。 - 不支持基于 MIG 的 vGPU。
3. 先决条件
- 在 BIOS 中启用虚拟化和 IOMMU 扩展(Intel VT-d 或 AMD IOMMU)。
- 主机以
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
4. 入门指南
使用 GPU Operator 和 KubeVirt 的高层次工作流程如下:
-
确保已设置禁用中介设备配置的功能门控。
-
根据将要运行的 GPU 工作负载类型为工作节点打标签。
-
安装 GPU Operator 并设置
sandboxWorkloads.enabled=true
。
如果使用 NVIDIA vGPU,还需要执行其他步骤,这将在后续部分中介绍。
5. 为工作节点打标签
使用以下命令为工作节点添加标签:
kubectl label node <node-name> --overwrite nvidia.com/gpu.workload.config=vm-vgpu
可以为标签 nvidia.com/gpu.workload.config
指定以下值:container
、vm-passthrough
和 vm-vgpu
。GPU Operator 使用该标签的值来确定在每个工作节点上部署哪些操作对象。
如果节点上不存在 nvidia.com/gpu.workload.config
标签,GPU Operator 将假定默认的 GPU 工作负载配置为 container
,并部署支持该类型负载所需的软件组件。要覆盖默认的 GPU 工作负载配置,可在 ClusterPolicy 中设置以下值:sandboxWorkloads.defaultWorkload=<config>
。
6. 安装 GPU Operator
根据是否计划使用 NVIDIA vGPU,选择以下适当的小节以安装 GPU Operator。
通常,ClusterPolicy 中的 sandboxWorkloads.enabled
标志控制 GPU Operator 是否可以为虚拟机工作负载(以及容器工作负载)配置 GPU 工作节点。默认情况下,此标志是禁用的,这意味着所有节点将使用相同的软件配置以支持容器工作负载,并且不会使用 nvidia.com/gpu.workload.config
节点标签。
注意
术语“沙箱”通常指在一个单独的隔离环境中运行软件,通常是为了增加安全性(如虚拟机)。我们使用“沙箱工作负载”一词来表示在虚拟机中运行的工作负载,无论使用何种虚拟化技术。
安装 GPU Operator(不使用 NVIDIA vGPU)
安装 GPU Operator,并启用 sandboxWorkloads
:
helm install --wait --generate-name \
-n gpu-operator --create-namespace \
nvidia/gpu-operator \
--set sandboxWorkloads.enabled=true
安装 GPU Operator(使用 NVIDIA vGPU)
构建私有的 NVIDIA vGPU Manager 容器镜像并推送到私有镜像仓库。请按照本节提供的步骤操作。
创建 GPU Operator 的命名空间:
kubectl create namespace gpu-operator
创建用于访问 NVIDIA vGPU Manager 镜像的 ImagePullSecret:
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
安装 GPU Operator,启用 sandboxWorkloads
和 vgpuManager
,并指定之前构建的 NVIDIA vGPU Manager 镜像:
helm install --wait --generate-name \
-n gpu-operator --create-namespace \
nvidia/gpu-operator \
--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 Device Manager 会自动创建 vGPU 设备,这些设备可以分配给 KubeVirt 虚拟机。默认情况下,GPU Operator 会在所有 GPU 上创建一组默认设备。要了解 vGPU Device Manager 的更多信息以及如何配置在集群中创建的 vGPU 设备类型,请参考 vGPU 设备配置文档。
7. 向 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 IDs 数据库中按设备名称进行搜索。
如果有节点的主机访问权限,可以使用以下命令列出 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 中的值:
- 在
pciHostDevices
下,将pciVendorSelector
和resourceName
替换为您的 GPU 型号。 - 在
mediatedDevices
下,将mdevNameSelector
和resourceName
替换为您的 vGPU 类型。
- 在
-
设置
externalResourceProvider=true
,以表明该资源由外部设备插件(即 GPU Operator 部署的sandbox-device-plugin
)提供。
有关更多配置信息,请参阅 KubeVirt 用户指南。
8. 创建带有 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
是在虚拟机中用于标识该设备的名称。
9. vGPU 设备配置
vGPU 设备管理器(vGPU Device Manager)用于在 GPU 工作节点上创建 vGPU 设备。管理员可以声明式地定义一组可能的 vGPU 设备配置,并应用于节点上的 GPU。运行时,可以将 vGPU 设备管理器指向这些配置中的一个,设备管理器会负责将其应用。配置文件以 ConfigMap 的形式创建,并在所有工作节点之间共享。运行时,可以使用节点标签 nvidia.com/vgpu.config
来决定在特定时间应在节点上应用哪个配置。如果节点没有此标签,则使用默认配置。有关此组件及其配置的更多信息,请参阅项目的 README。
默认情况下,GPU Operator 部署一个 vGPU 设备管理器的 ConfigMap,包含所有 NVIDIA vGPU 支持的 vGPU 类型的命名配置。用户可以通过应用 nvidia.com/vgpu.config
节点标签为工作节点选择特定配置。例如,将节点标记为 nvidia.com/vgpu.config=A10-8Q
会在节点上的所有 A10 GPU 上创建 3 个 A10-8Q 类型的 vGPU 设备(注:每个 GPU 最多可创建 3 个 A10-8Q 设备)。如果节点没有标签,则应用默认配置。默认配置会在所有 GPU 上创建 Q 系列的 vGPU 设备,其中每个 vGPU 设备的帧缓冲内存为 GPU 总内存的一半。例如,默认配置会在所有 A10 GPU 上创建两个 A10-12Q 设备,在所有 V100 GPU 上创建两个 V100-8Q 设备,在所有 T4 GPU 上创建两个 T4-8Q 设备。
如果需要自定义的 vGPU 设备配置,可以创建自己的 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 使用该自定义配置。
10. 应用新的 vGPU 设备配置
可以通过设置 nvidia.com/vgpu.config
节点标签,在每个节点上应用特定的 vGPU 设备配置。如果不希望应用默认配置,建议在安装 GPU Operator 前先设置此节点标签。
在已成功应用某一 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
标签对节点进行标记时,将应用默认的 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"
}
11. 构建 NVIDIA vGPU 管理器镜像
注意:
如果计划使用 NVIDIA vGPU,才需要构建 NVIDIA vGPU 管理器镜像。如果仅计划使用 PCI 直通,请跳过此部分。
本节涵盖了构建 NVIDIA vGPU 管理器容器镜像并将其推送到私有注册表的过程。
下载 vGPU 软件
从 NVIDIA 许可门户下载 vGPU 软件。
-
登录到 NVIDIA 许可门户,并导航到软件下载部分。
-
NVIDIA vGPU 软件位于 NVIDIA 许可门户的 软件下载 部分。
-
vGPU 软件包以 zip 文件形式打包。下载并解压该包,以获取适用于 Linux 的 NVIDIA vGPU 管理器文件
NVIDIA-Linux-x86_64-<version>-vgpu-kvm.run
。
注意:
对于 NVIDIA AI 企业客户,必须使用 aie .run 文件来构建 NVIDIA vGPU 管理器镜像。请下载
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 管理器文件
cp <local-driver-download-directory>/*-vgpu-kvm.run ./
设置以下环境变量:
PRIVATE_REGISTRY
- 用于存储驱动镜像的私有注册表名称。VERSION
- 从 NVIDIA 软件门户下载的 NVIDIA vGPU 管理器版本。OS_TAG
- 必须与客户端操作系统版本匹配。上面的示例中使用的是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 管理器镜像
docker build \
--build-arg DRIVER_VERSION=${VERSION} \
--build-arg CUDA_VERSION=${CUDA_VERSION} \
-t ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG} .
将 NVIDIA vGPU 管理器镜像推送到私有注册表(registry)
docker push ${PRIVATE_REGISTRY}/vgpu-manager:${VERSION}-${OS_TAG}