将虚拟 GPU 设备附加到虚拟机

重要提示

以下描述的功能仅受 libvirt/KVM 驱动程序支持。

Nova 中的虚拟 GPU 功能允许部署为使用可提供虚拟设备的物理 GPU 的实例提供特定的 GPU 类型。

例如,单个 Intel GVT-gNVIDIA GRID vGPU 物理图形处理器 (pGPU) 可以虚拟化为多个虚拟图形处理器 (vGPU),如果超visor 支持硬件驱动程序并具有使用这些虚拟设备创建虚拟机的功能。

此功能高度依赖于 libvirt 的版本以及主机上存在的物理设备。此外,厂商的 vGPU 驱动程序软件必须同时安装和配置在主机上。

注意事项在 注意事项 部分中提到。

要启用虚拟 GPU,请按照以下步骤操作

  1. 启用 GPU 类型(计算)

  2. 配置风味(控制器)

启用 GPU 类型(计算)

  1. 对于支持 SR-IOV 的 NVIDIA GPU,请启用虚拟功能。

    $ /usr/lib/nvidia/sriov-manage -e slot:bus:domain.function
    

    例如,要为插槽 0000、总线 41、域 00 和功能 0 的 GPU 启用虚拟功能

    $ /usr/lib/nvidia/sriov-manage -e 0000:41:00.0
    

    您可能需要自动化此过程,因为它必须在主机每次启动时完成。

    给出一个示例 systemd 模板单元文件,名为 nvidia-sriov-manage@.service

    [Unit]
    After = nvidia-vgpu-mgr.service
    After = nvidia-vgpud.service
    Description = Enable Nvidia GPU virtual functions
    
    [Service]
    Type = oneshot
    User = root
    Group = root
    ExecStart = /usr/lib/nvidia/sriov-manage -e %i
    # Give a reasonable amount of time for the server to start up/shut down
    TimeoutSec = 120
    # This creates a specific slice which all services will operate from
    #  The accounting options give us the ability to see resource usage
    #  through the `systemd-cgtop` command.
    Slice = system.slice
    # Set Accounting
    CPUAccounting = True
    BlockIOAccounting = True
    MemoryAccounting = True
    TasksAccounting = True
    RemainAfterExit = True
    ExecStartPre = /usr/bin/sleep 30
    
    [Install]
    WantedBy = multi-user.target
    

    要为插槽 0000、总线 41、域 00 和功能 0 的 GPU 启用虚拟功能

    $ systemctl enable nvidia-sriov-manage@0000:41:00.0.service
    

    注意

    这只是一个示例,重要的是参考相关厂商文档以获取您拥有的特定设备。

  2. 指定实例将获得哪些特定的 GPU 类型。

    编辑 devices.enabled_mdev_types

    [devices]
    enabled_mdev_types = nvidia-35
    

    如果您想支持多个 GPU 类型,则需要为每个设备提供一个单独的配置部分。例如

    [devices]
    enabled_mdev_types = nvidia-35, nvidia-36
    
    [mdev_nvidia-35]
    device_addresses = 0000:84:00.0,0000:85:00.0
    
    [mdev_nvidia-36]
    device_addresses = 0000:86:00.0
    

    您需要定义每个 GPU 类型支持哪些物理 GPU。

    如果为两个不同类型提供了相同的 PCI 地址,nova-compute 将拒绝启动并在日志中发出特定错误。

    要了解应提及哪些特定类型,请参阅 如何发现 GPU 类型

    版本 21.0.0 中更改:支持多种 GPU 类型仅受 Ussuri 版本及更高版本支持。

  3. 重新启动 nova-compute 服务。

    警告

    更改类型是可能的,但由于现有的物理 GPU 无法为具有不同类型的多个虚拟机提供服务,因此 Nova 会返回 NoValidHost,如果仍然存在具有原始类型的实例。因此,强烈建议将新类型部署到没有工作负载的新计算节点,并在需要更改类型的节点上重建实例。

配置风味(控制器)

配置风味以请求一个虚拟 GPU

$ openstack flavor set vgpu_1 --property "resources:VGPU=1"

注意

从 Queens 版本开始,所有支持虚拟 GPU 的超visor 仅接受每个实例一个虚拟 GPU。

计算主机上启用的 vGPU 类型不会暴露给 API 用户。配置为 vGPU 支持的风味可以绑定到主机聚合,作为将这些风味正确调度到支持它们的计算主机的一种方式。有关更多信息,请参阅 主机聚合

使用虚拟 GPU 设备创建实例

nova-scheduler 通过调用 Placement API 获取计算节点提供的特定 VGPU 资源类,选择具有可用 vGPU 设备的的目标主机。

$ openstack server create --flavor vgpu_1 --image cirros-0.3.5-x86_64-uec --wait test-vgpu

如何发现 GPU 类型

虚拟 GPU 被视为中介设备。支持虚拟 GPU 的物理 PCI 设备(这里的显卡)会提出中介设备 (mdev) 类型。由于在安装厂商的虚拟 GPU 驱动程序软件后,中介设备受 Linux 内核通过 sysfs 文件支持,因此您可以按如下所示查看所需的属性

$ ls /sys/class/mdev_bus/*/mdev_supported_types
/sys/class/mdev_bus/0000:84:00.0/mdev_supported_types:
nvidia-35  nvidia-36  nvidia-37  nvidia-38  nvidia-39  nvidia-40  nvidia-41  nvidia-42  nvidia-43  nvidia-44  nvidia-45

/sys/class/mdev_bus/0000:85:00.0/mdev_supported_types:
nvidia-35  nvidia-36  nvidia-37  nvidia-38  nvidia-39  nvidia-40  nvidia-41  nvidia-42  nvidia-43  nvidia-44  nvidia-45

/sys/class/mdev_bus/0000:86:00.0/mdev_supported_types:
nvidia-35  nvidia-36  nvidia-37  nvidia-38  nvidia-39  nvidia-40  nvidia-41  nvidia-42  nvidia-43  nvidia-44  nvidia-45

/sys/class/mdev_bus/0000:87:00.0/mdev_supported_types:
nvidia-35  nvidia-36  nvidia-37  nvidia-38  nvidia-39  nvidia-40  nvidia-41  nvidia-42  nvidia-43  nvidia-44  nvidia-45

检查虚拟 GPU 的分配和库存

注意

以下信息仅从 19.0.0 Stein 版本有效。在此版本之前,与 VGPU 资源类相关的库存和分配仍然位于与计算节点相关的根资源提供程序上。如果从 Rocky 升级并使用 libvirt 驱动程序,VGPU 库存和分配将移动到代表实际物理 GPU 的子资源提供程序。

您将看到以下示例使用 osc-placement 插件 for OpenStackClient。有关特定命令的详细信息,请参阅其文档。

  1. 获取资源提供程序列表

    $ openstack resource provider list
    +--------------------------------------+---------------------------------------------------------+------------+
    | uuid                                 | name                                                    | generation |
    +--------------------------------------+---------------------------------------------------------+------------+
    | 5958a366-3cad-416a-a2c9-cfbb5a472287 | virtlab606.xxxxxxxxxxxxxxxxxxxxxxxxxxx                  |          7 |
    | fc9b9287-ef5e-4408-aced-d5577560160c | virtlab606.xxxxxxxxxxxxxxxxxxxxxxxxxxx_pci_0000_86_00_0 |          2 |
    | e2f8607b-0683-4141-a8af-f5e20682e28c | virtlab606.xxxxxxxxxxxxxxxxxxxxxxxxxxx_pci_0000_85_00_0 |          3 |
    | 85dd4837-76f9-41f2-9f19-df386017d8a0 | virtlab606.xxxxxxxxxxxxxxxxxxxxxxxxxxx_pci_0000_87_00_0 |          2 |
    | 7033d860-8d8a-4963-8555-0aa902a08653 | virtlab606.xxxxxxxxxxxxxxxxxxxxxxxxxxx_pci_0000_84_00_0 |          2 |
    +--------------------------------------+---------------------------------------------------------+------------+
    

    在此示例中,我们看到根资源提供程序 5958a366-3cad-416a-a2c9-cfbb5a472287 以及四个其他资源提供程序,它们是其子项,每个子项对应一个物理 GPU。

  2. 检查每个资源提供程序的库存以查看资源类

    $ openstack resource provider inventory list 5958a366-3cad-416a-a2c9-cfbb5a472287
    +----------------+------------------+----------+----------+-----------+----------+-------+
    | resource_class | allocation_ratio | max_unit | reserved | step_size | min_unit | total |
    +----------------+------------------+----------+----------+-----------+----------+-------+
    | VCPU           |             16.0 |       48 |        0 |         1 |        1 |    48 |
    | MEMORY_MB      |              1.5 |    65442 |      512 |         1 |        1 | 65442 |
    | DISK_GB        |              1.0 |       49 |        0 |         1 |        1 |    49 |
    +----------------+------------------+----------+----------+-----------+----------+-------+
    $ openstack resource provider inventory list e2f8607b-0683-4141-a8af-f5e20682e28c
    +----------------+------------------+----------+----------+-----------+----------+-------+
    | resource_class | allocation_ratio | max_unit | reserved | step_size | min_unit | total |
    +----------------+------------------+----------+----------+-----------+----------+-------+
    | VGPU           |              1.0 |       16 |        0 |         1 |        1 |    16 |
    +----------------+------------------+----------+----------+-----------+----------+-------+
    

    您可以在子资源提供程序上看到 VGPU 库存,而其他资源类库存仍然位于根资源提供程序上。

  3. 检查使用虚拟 GPU 的每个服务器的分配

    $ openstack server list
    +--------------------------------------+-------+--------+---------------------------------------------------------+--------------------------+--------+
    | ID                                   | Name  | Status | Networks                                                | Image                    | Flavor |
    +--------------------------------------+-------+--------+---------------------------------------------------------+--------------------------+--------+
    | 5294f726-33d5-472a-bef1-9e19bb41626d | vgpu2 | ACTIVE | private=10.0.0.14, fd45:cdad:c431:0:f816:3eff:fe78:a748 | cirros-0.4.0-x86_64-disk | vgpu   |
    | a6811fc2-cec8-4f1d-baea-e2c6339a9697 | vgpu1 | ACTIVE | private=10.0.0.34, fd45:cdad:c431:0:f816:3eff:fe54:cc8f | cirros-0.4.0-x86_64-disk | vgpu   |
    +--------------------------------------+-------+--------+---------------------------------------------------------+--------------------------+--------+
    
    $ openstack resource provider allocation show 5294f726-33d5-472a-bef1-9e19bb41626d
    +--------------------------------------+------------+------------------------------------------------+
    | resource_provider                    | generation | resources                                      |
    +--------------------------------------+------------+------------------------------------------------+
    | 5958a366-3cad-416a-a2c9-cfbb5a472287 |          8 | {u'VCPU': 1, u'MEMORY_MB': 512, u'DISK_GB': 1} |
    | 7033d860-8d8a-4963-8555-0aa902a08653 |          3 | {u'VGPU': 1}                                   |
    +--------------------------------------+------------+------------------------------------------------+
    
    $ openstack resource provider allocation show a6811fc2-cec8-4f1d-baea-e2c6339a9697
    +--------------------------------------+------------+------------------------------------------------+
    | resource_provider                    | generation | resources                                      |
    +--------------------------------------+------------+------------------------------------------------+
    | e2f8607b-0683-4141-a8af-f5e20682e28c |          3 | {u'VGPU': 1}                                   |
    | 5958a366-3cad-416a-a2c9-cfbb5a472287 |          8 | {u'VCPU': 1, u'MEMORY_MB': 512, u'DISK_GB': 1} |
    +--------------------------------------+------------+------------------------------------------------+
    

    在此示例中,创建了两个使用请求 1 个 VGPU 的风味的服务器,因此在查看每个消费者 UUID(即服务器 UUID)的分配时,您可以看到 VGPU 分配针对子资源提供程序,而其他分配针对根资源提供程序。这意味着由具有 PCI ID 0000:85:00.0 的物理 GPU 提供 a6811fc2-cec8-4f1d-baea-e2c6339a9697 使用的虚拟 GPU。

(可选)为多种 GPU 类型提供自定义特征

由于操作员希望每个计算节点支持不同的 GPU 类型,因此最好有请求特定 GPU 类型的风味。现在可以使用自定义特征通过装饰对应于物理 GPU 的子资源提供程序来实现这一点。

注意

未来版本中可能的改进包括提供自动标记资源提供程序与标准特征,这些特征对应于公共 GPU 类型的版本映射。目前,这必须手动完成。

  1. 获取资源提供程序列表

    首先查看 检查虚拟 GPU 的分配和库存 以获取支持 VGPU 资源类的资源提供程序列表。

  2. 定义将对应于每个 GPU 类型的自定义特征

    $ openstack --os-placement-api-version 1.6 trait create CUSTOM_NVIDIA_11
    

    在此示例中,我们要求创建一个名为 CUSTOM_NVIDIA_11 的自定义特征。

  3. 将相应的特征添加到与 GPU 匹配的资源提供程序

    $ openstack --os-placement-api-version 1.6 resource provider trait set \
        --trait CUSTOM_NVIDIA_11 e2f8607b-0683-4141-a8af-f5e20682e28c
    

    在这种情况下,特征 CUSTOM_NVIDIA_11 将添加到 UUID 为 e2f8607b-0683-4141-a8af-f5e20682e28c 的资源提供程序,该资源提供程序对应于上述 PCI 地址 0000:85:00:0

  4. 修改风味以添加请求的特征

    $ openstack flavor set --property trait:CUSTOM_NVIDIA_11=required vgpu_1
    

    在此示例中,我们将 CUSTOM_NVIDIA_11 特征作为我们之前创建的 vgpu_1 风味所需的添加信息。

    这将允许 Placement 服务仅返回匹配此特征的资源提供程序,因此只有装饰了这些 GPU 的 GPU 才会被检查此风味。

注意事项

注意

此信息截至 17.0.0 Queens 版本是正确的。如果进行了改进或修复了问题,则会按项目进行说明。

  • 在计算节点上安装 NVIDIA 驱动程序后,如果未看到 mdev,但 VF 设备存在于类似 /sys/bus/pci/devices/0000:25:00.4/nvidia 的路径下,这表明正在使用 **内核变体驱动程序**。

    这很可能发生在 **Ubuntu Noble** 或 **RHEL 10** 上。

    版本 31.0.0 中更改:请参阅 PCI 直通文档 以获取正确的配置。

  • 当使用最新的 nVidia GPU 架构(如 Ampere 或更新的 GPU),这些 GPU 具有 SR-IOV 功能时,Nova 无法知道特定类型可以使用多少个 vGPU。然后,您需要创建虚拟功能,然后通过设置 device_addresses 提供每个 GPU 可以使用的虚拟功能列表。

    版本 29.0.0 中更改:到 2024.1 Caracal 版本,如果您使用这些硬件,则需要在相关的 mdev 类型组(例如 mdev_nvidia-35)中提供一个新的配置选项,名为 max_instances,该选项的值将是该类型可以创建的 vGPU 数量。

    例如,对于 A40-2Q nVidia GPU 类型,它可以创建最多 24 个 vGPU,请提供以下配置

    [devices]
    enabled_mdev_types = nvidia-558
    
    [mdev_nvidia-558]
    max_instances = 24
    

    作为补充说明,您可以看到我们在 mdev_nvidia-558 部分中不使用 device_addresses,因为我们不需要告诉要使用哪些确切的虚拟功能。

  • 在迁移使用 vGPU 的实例时,libvirt guest domain XML 未使用目标所需的新的中介设备 UUID 进行更新。

    版本 29.0.0 中更改:在 2024.1 Caracal 版本中,Nova 现在 支持 vGPU 实时迁移。为了做到这一点,源计算服务和目标计算服务都需要至少具有 libvirt-8.6.0、QEMU-8.1.0 和 Linux 内核 5.18.0 的最低版本。您需要确保只在两个计算之间使用单一通用的 vGPU 类型。如果源和目标主机上配置了多种 mdev 类型,则必须配置自定义特征或自定义资源类,由主机报告并由实例请求,以确保 Placement API 正确返回使用正确 vGPU 类型的 GPU 进行迁移。最后,如果您想实时迁移 nVidia 中介设备,则需要更新 libvirt.live_migration_downtimelibvirt.live_migration_downtime_stepslibvirt.live_migration_downtime_delay

    live_migration_downtime = 500000
    live_migration_downtime_steps = 3
    live_migration_downtime_delay = 3
    

    您可以在 此处 找到一个工作实时迁移的示例。

  • 具有 vGPU 的虚拟机的挂起目前不起作用,因为 libvirt 存在限制(它无法从虚拟机热插拔中介设备)。建议使用其他实例操作(例如快照实例或将其搁置)作为解决方法,直到 libvirt 获得 mdev 热插拔支持。如果用户尝试挂起实例,libvirt 驱动程序将引发异常,这将导致实例恢复到 ACTIVE 状态。 os-instance-actions API 中的 suspend 操作将具有 *Error* 状态。

    版本 25.0.0 中更改:这已在 Yoga 版本中解决。请参阅 bug 1948705

  • 使用具有 vGPU 资源的新的风味调整实例大小不会将这些 vGPU 分配给实例(实例是在没有 vGPU 资源的情况下创建的)。建议的解决方法是在调整大小后重建实例。重建操作分配 vGPU 给实例。

    版本 21.0.0 中更改:这已在 Ussuri 版本中解决。请参阅 bug 1778563

  • 将实例冷迁移到另一个主机将与调整大小一样的问题。如果您想迁移实例,请确保在迁移后重建它。

    版本 21.0.0 中更改:这已在 Ussuri 版本中解决。请参阅 bug 1778563

  • 救援镜像不使用 vGPU。正在救援的实例在救援期间不会保留其 vGPU。在此期间,另一个实例可以接收这些 vGPU。这是一个已知问题。建议的解决方法是在救援后立即重建实例。但是,只有在主机上有其他空闲 vGPU 的情况下,重建救援的实例才会有帮助。

    已在 18.0.0 版本中更改:此问题已在 Rocky 版本中解决。请参阅 bug 1762688

对于嵌套 vGPU

注意

此信息截至 21.0.0 Ussuri 版本为准。如果进行了改进或修复了问题,则会逐项注明。

  • 如果创建请求 vGPU 的 flavor 的服务器,并且用户想要多重创建(例如,使用 –max 2),即使每个物理 GPU 至少可以支持一个特定实例,调度器也可能会返回 NoValidHosts 异常,如果总请求容量不由单个物理 GPU 支持。(请参阅 bug 1874664。)

    例如,创建请求 vGPU 的 flavor 的服务器,如果两个子 RP 具有 4 个 vGPU 库存

    • 您可以使用 –max 2 请求具有 2 个 vGPU 的 flavor。

    • 但是,您不能使用 –max 2 请求具有 4 个 vGPU 的 flavor。