gpu-device-plugin源码分析

源码分析

启动参数

参数名称 对应环境变量 类型 参数说明 默认值
mig-strategy MIG_STRATEGY string GPU上MIG设备的暴露策略:
none、single、mixed
none
fail-on-init-error FAIL_ON_INIT_ERROR bool 如果在初始化过程中遇到错误,就使插件失败,否则将无限期阻塞 false
pass-device-specs PASS_DEVICE_SPECS bool 在 Allocate() 方法中传递 DeviceSpecs 列表给 kubelet false
device-list-strategy DEVICE_LIST_STRATEGY string 给底层的 runtime 传递设备列表的方式:envvar、volume-mounts envvar
device-id-strategy DEVICE_ID_STRATEGY string 给底层 runtime 传递设备 ID 列表的方式:uuid、index uuid
nvidia-driver-root NVIDIA_DRIVER_ROOT string NVIDIA驱动安装的根路径(典型的值是'/' 或 '/run/nvidia/driver') /

核心接口

DevicePlugin

DevicePlugin 接口定义了设备插件的常规工作流程包括以下几个步骤:

  • 初始化。在这个阶段,设备插件将执行供应商特定的初始化和设置, 以确保设备处于就绪状态。

  • 插件使用主机路径 /var/lib/kubelet/device-plugins/ 下的 Unix 套接字启动 一个 gRPC 服务,该服务实现以下接口:

service DevicePlugin {
    // GetDevicePluginOptions 返回与设备管理器沟通的选项。
    rpc GetDevicePluginOptions(Empty) returns (DevicePluginOptions) {}

    // ListAndWatch 返回 Device 列表构成的数据流。
    // 当 Device 状态发生变化或者 Device 消失时,ListAndWatch
    // 会返回新的列表。
    rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}

    // Allocate 在容器创建期间调用,这样设备插件可以运行一些特定于设备的操作,
    // 并告诉 kubelet 如何令 Device 可在容器中访问的所需执行的具体步骤
    rpc Allocate(AllocateRequest) returns (AllocateResponse) {}

    // GetPreferredAllocation 从一组可用的设备中返回一些优选的设备用来分配,
    // 所返回的优选分配结果不一定会是设备管理器的最终分配方案。
    // 此接口的设计仅是为了让设备管理器能够在可能的情况下做出更有意义的决定。
    rpc GetPreferredAllocation(PreferredAllocationRequest) returns (PreferredAllocationResponse) {}

    // PreStartContainer 在设备插件注册阶段根据需要被调用,调用发生在容器启动之前。
    // 在将设备提供给容器使用之前,设备插件可以运行一些诸如重置设备之类的特定于
    // 具体设备的操作,
    rpc PreStartContainer(PreStartContainerRequest) returns (PreStartContainerResponse) {}
}

插件并非必须为 GetPreferredAllocation() 或 PreStartContainer() 提供有用 的实现逻辑,调用 GetDevicePluginOptions() 时所返回的 DevicePluginOptions 消息中应该设置这些调用是否可用。kubelet 在真正调用这些函数之前,总会调用 GetDevicePluginOptions() 来查看是否存在这些可选的函数。

  • 插件通过 Unix socket 在主机路径 /var/lib/kubelet/device-plugins/kubelet.sock 处向 kubelet 注册自身。

  • 成功注册自身后,设备插件将以服务模式运行,在此期间,它将持续监控设备运行状况, 并在设备状态发生任何变化时向 kubelet 报告。它还负责响应 Allocate gRPC 请求。 在 Allocate 期间,设备插件可能还会做一些设备特定的准备;例如 GPU 清理或 QRNG 初始化。 如果操作成功,则设备插件将返回 AllocateResponse,其中包含用于访问被分配的设备容器运行时的配置。 kubelet 将此信息传递到容器运行时。

ResourceManager

ResourceManager 定义了构建设备、获取设备信息和设备健康检查接口。

type ResourceManager interface {
    Devices() []*Device  # 获取所有设备信息
    BuildDevices()       # 从 nvml 获取设备信息,并封装成 *Device 对象,并保存
    CheckHealth(stop <-chan interface{}, unhealthy chan<- *Device, healthProbe healthprobe.HealthProbe)  # 设备健康检查
}

核心对象

GpuDeviceManager

type GpuDeviceManager struct {
    skipMigEnabledGPUs bool       # 在列举设备时,是否跳过开启了 MIG 的 GPU 设备
    devices            []*Device  # 设备列表
    resourceName       string     # 资源类型名称
    handlers           map[string]HandleDevices
}
构建设备列表
  1. 通过 nvml 获取设备数量

  2. 构建 PCIe 映射

    1. 遍历 /sys/devices/ 目录及其子目录,解析并过滤 PCIe 设备目录

    2. PCIe 设备目录样式为:/sys/devices/pci0000:97/0000:97:03.1/0000:98:00.0/0000:99:08.0/0000:a9:00.0/0000:aa:00.0/0000:ab:00.1/net/eth7

  3. 遍历所有设备,并根据 index 从 nvml 获取设备详细信息

  4. 判断是不是MIG设备,如果是 MIG 设备,并且 skipMigEnabledGPUs 为true,则跳过该设备

  5. 获取该设备的 PCI 信息,并通过 PCI 信息中的 busID 找到对应的 PCIe 设备名称

  6. 获取设备的 minor number 和 uuid

  7. 构建 *Device 对象,并加入 devices 设备列表中

设备健康检查
  1. 如果执行nvml相关命令超时(超时时间通过环境变量 NV_CHECK_TIMEOUT 获取,默认超时时间为5s),则认为所有设备都不健康

  2. 如果执行nvml获取某一设备失败,则认为该设备不健康

  3. 如果禁用健康检查(环境变量 DP_DISABLE_HEALTHCHECKS == "all"),则不继续执行健康检查操作

  4. 遍历所有设备,检查设备是否为 StdCard 模式

  5. 执行 dmesg -t -k -l warn -f daemon | grep 'NVRM: Xid' 命令,检查设备是否发生 xid 错误

  6. 如果设备发生 xid 错误,或者不是标准卡,则认为该设备发生故障

    1. ecc mode 开启,且count 为0

    2. compute mode 为default

    3. persistence mode 为on

    4. accountting mode 为off

    5. display active 为 off

    6. display mode 为 on

  7. 如果设备抛出 nvml.EventTypeXidCriticalError 事件,且 xid 类型不在要跳过的错误类型中(13,31,43,45,68)中,则认为该设备发生故障

  8. 如果设备发生 xid 错误,则 XIDCondition 并上报给 healthProbe

  9. 发生故障的设备信息会被放入 NvidiaDevicePlugin 的 health channel中,NvidiaDevicePlugin.ListAndWatch() 方法从channel中取出输入,然后告知 kubelet 设备故障

MigDeviceManager

MigDeviceManager 的监控检查流程和 GpuDeviceManager 完全相同。

type MigDeviceManager struct {
    strategy     MigStrategy      # MIG 策略
    resource     string
    resourceName string          # 资源类型名称
    devices      []*Device       # 设备列表
    handlers     map[string]HandleDevices
}

Dectector

Dectector 会定期探测节点上的设备信息,并根据设备类型为节点打上对应的标签,这些标签包括:

type Dectector struct {
    loopDuration       uint                      # 循环间隔(单位:秒)
    cs                 *kubernetes.Clientset     # kubernetes 客户端
    modelTranslateFunc func(string) string       # gpu-model 转换方法
    info               Info                      # 设备信息,包括 gpu-model、gpu-memory、gpu-driver-version
    m                  sync.Mutex
}
探测过程
  1. 获取任一设备信息及设备对于的 PCI 信息

  2. 根据 PCI ID获取对应的资源类型

  3. 根据资源类型获取对应的显存配置

  4. 如果设备支持 MIG,获取其关联的所有 MIG 设备,并根据 MIG 设备数量获取其对应的资源类型、显存配置信息

  5. 从 nvml 获取 NVIDIA 驱动版本

  6. 为节点打上对应的标签

资源名和显存大小对应关系

"A100-80G": "80G" "A100-40G": "40G" "V100-32G": "32G" "V100-16G": "16G" "P40-24G": "24G" "P40-12G": "12G" "T4-16G": "16G" "P4-8G": "8G" "A30-24G": "24G" "A30-MIG-12G": "12G" "A30-MIG-6G": "6G"

NvidiaDevicePlugin

从 NvidiaDevicePlugin 的定义可知,其实现了 ResourceManager 相关接口,从而支持构建设备、获取设备信息和设备健康检查接口。

type NvidiaDevicePlugin struct {
    ResourceManager
    resourceName     string
    deviceListEnvvar string
    allocatePolicy   gpuallocator.Policy
    socket           string
    detector         *Dectector
    healthProbe      healthprobe.HealthProbe
    config           Config

    server        *grpc.Server
    cachedDevices []*Device
    health        chan *Device
    stop          chan interface{}
}
Start()
  1. 获取从 BuildDevices() 方法得到的设备列表,并赋值给 cachedDevices

  2. 创建 *grpc.Server 及 health channel、stop channel

  3. 创建 *kubernetes.Clientset 实例,用于和 apiserver 交互,并创建 EventRecorder

  4. 开启 Detector 探测,Dectector 会定期探测节点上的设备信息,并根据设备类型为节点打上对应的标签

  5. 创建 HealthProbeClient,并创建 HealthProbe

  6. 启动 gpu-device-plugin 的 gRPC 服务

    1. 删除 /var/lib/kubelet/device-plugins/nvidia-gpu.sock 文件,并重新监听该文件

    2. 启动 gRPC 服务,并记录重启次数

    3. 通过启动阻塞连接等待服务器启动

  7. 向Kubelet注册给定resourceName的设备插件

    1. 连接 /var/lib/kubelet/device-plugins/kubelet.sock,超时时间为5s

    2. 调用 kubelet 的 Register() 方法,向 kubelet 注册自身

  8. 开启设备健康检查

启动过程

  1. 注册Prometheus指标 nvml_init_failed 和 gpu_xid_error

  2. 注册 /metrics HTTP站点

  3. 访问 /dev 目录,判断是否存在 nvidia 设备

  4. nvml.Init(),如果 nvml 初始化失败,则向 apiserver 上报 "Nvml Init Failed" 事件

  5. 注册Prometheus指标gpu_topology_sum、healthy_device_count、available_device_count 和 allocate_stats

  6. 创建 FSWatcher 监控 /var/lib/kubelet/device-plugins/ 目录变更

  7. 创建 OSWatcher 监听停止、重启等系统信号

  8. 根据 mig-strategy 策略创建对应的 MigStrategy 实例

  9. 根据命令行参数创建 plugin.Config 实例

  10. 根据配置的 MIG 策略,创建对应的 NvidiaDevicePlugin

  11. 创建 pluginStartError channel,用于接收插件启动失败信息

  12. 遍历所有 NvidiaDevicePlugin,调用其 BuildDevices() 方法从 nvml 获取设备列表,并筛选符合条件的设备

  13. 调用插件的 Start() 方法,如果 Start() 执行失败,则将错误放入 pluginStartError

  14. 启动过程详见:NvidiaDevicePlugin.Start()

  15. 开启事件监听

  16. 如果从 pluginStartError channel中接收到插件启动失败信息,则执行重启操作

  17. 如果从 FSWatcher 监听到 /var/lib/kubelet/device-plugins/kubelet.sock 文件创建事件(即 kubelet 重启事件),则执行重启操作

  18. 如果从 FSWatcher 监听到 error 信息,则在日志中记录该 error信息

  19. 如果从 OSWatcher 监听到 syscall.SIGHUP 信号,则执行重启操作;如果监听到其他信号,则执行停止操作

DevicePlugin 接口实现

ListAndWatch()

ListAndWatch 返回 Device 列表构成的数据流。当 Device 状态发生变化或者 Device 消失时,ListAndWatch会返回新的列表。

从下面的代码实现可知:

  • gpu-device-plugin 在启动后,会向 kubelet 上报节点上的设备信息

  • 之后会不断监听 gpu-device-plugin 的停止消息和设备健康信息,当设备健康状态发生变化时,重新向 kubelet 上报节点上的设备信息

func (m *NvidiaDevicePlugin) ListAndWatch(e *pluginapi.Empty, s pluginapi.DevicePlugin_ListAndWatchServer) error {
    s.SendMsg(&pcieapi.ListAndWatchResponse{Devices: m.apiDevices()})

    for {
        HealthyDeviceMetric.WithLabelValues(os.Getenv("NODE_NAME"), m.detector.GetInfo().ModelName).Set(filterHealthyOnly(m.apiDevices()))
        select {
        case <-m.stop:
            return nil
        case d := <-m.health:
            log.Printf("device received from health chan: %v", d)
            s.SendMsg(&pcieapi.ListAndWatchResponse{Devices: m.apiDevices()})
        }
    }
}

Allocate()

Allocate 在容器创建期间调用,这样设备插件可以运行一些特定于设备的操作,并告诉 kubelet 如何令 Device 可在容器中访问的所需执行的具体步骤

GetPreferredAllocation()

GetPreferredAllocation 从一组可用的设备中返回一些优选的设备用来分配,所返回的优选分配结果不一定会是设备管理器的最终分配方案。此接口的设计仅是为了让设备管理器能够在可能的情况下做出更有意义的决定。

PreStartContainer()

PreStartContainer 在设备插件注册阶段根据需要被调用,调用发生在容器启动之前。在将设备提供给容器使用之前,设备插件可以运行一些诸如重置设备之类的特定于具体设备的操作。

健康检查

gpu-device-plugin 启动上会对设备进行健康检查,之后也会定期对设备进行健康检查。设备健康状态发生变更后,gpu-device-plugin 会通过 NvidiaDevicePlugin.ListAndWatch() 方法告知 kubelet 设备故障。kubelet在得知该设备故障时,就会在分配时排除该设备,从而避免 Pod 运行在故障设备上。

健康检查过程详见:gpu-device-plugin源码分析-GpuDeviceManager-健康检查

MIG 策略

MIG,也就是 Multi-Instance GPU 是 NVIDIA 在 NVIDIA GTC 2020 发布的最新 Ampere 架构的 NVIDIA A100 GPU 推出的新特性。当配置为 MIG 运行状态时,A100 可以通过分出最多 7 个核心来帮助供应商提高 GPU 服务器的利用率,无需额外投入。MIG 提供了一种多用户使用隔离的GPU资源、提高GPU资源使用率的新的方式,特别适合于云服务提供商的多租户场景,保证一个租户的运行不干扰另一个租户。

MIG功能可以将单个GPU划分为多个GPU分区,称为 GPU Insance。创建GPU实例可以认为是将一个大GPU拆分为多个较小的GPU,每个GPU实例都具有专用的计算和内存资源。

nvidia-device-plugin 支持3种 MIG 策略:

  • none:只显示 GPU 设备,并上报为 nvidia.com/gpu 资源类型 ,不显示 MIG 设备。

  • single:如果开启了 MIG,只显示 MIG 设备,并上报为 nvidia.com/gpu 资源类型。

  • mixed:所有的 MIG 设备会以其全限定名称 nvidia.com/mig-<slice_count>g.<memory_size>gb 的方式列举出来。

关于MIG策略详见:MIG Support in Kubernetes

关于MIG详见:【异构计算】NVIDIA GPU MIG

none

none 策略旨在保持 nvidia-device-plugin 一如既往地运行。该插件不会对 GPU 设备是否支持 MIG 做区分,会列举出当前节点上的所有 GPU,并通过 nvidia.com/gpu 资源类型使这些 GPU 可用。

为了测试这个策略,我们检查了启用和不启用MIG的GPU的枚举,并确保在这两种情况下都可以看到它。测试假设集群中的单个节点上有一个GPU。

1、确保 GPU 不支持 MIG

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  A100-SXM4-40GB      Off  | 00000000:36:00.0 Off |                    0 |
| N/A   29C    P0    62W / 400W |      0MiB / 40537MiB |      6%      Default |
|                               |                      |             Disabled |
+-------------------------------+----------------------+----------------------+

2、使用 none 策略启动 nvidia-device-plugin,如果 nvidia-device-plugin 已经在运行则需要重启。

3、观察到节点上只有1个可用、资源类型为 nvidia.com/gpu 的 GPU:

kubectl describe node
...
Capacity:
nvidia.com/gpu:          1
...
Allocatable:
nvidia.com/gpu:          1
...

4、使用 none 策略启动 gpu-feature-discovery

5、观察到已经为当前 MIG 策略正确设置相关标签:

$ kubectl get node -o json | \
   jq '.items[0].metadata.labels | with_entries(select(.key | startswith("nvidia.com")))'
{
"nvidia.com/cuda.driver.major": "450",
"nvidia.com/cuda.driver.minor": "80",
"nvidia.com/cuda.driver.rev": "02",
"nvidia.com/cuda.runtime.major": "11",
"nvidia.com/cuda.runtime.minor": "0",
"nvidia.com/gfd.timestamp": "1605312111",
"nvidia.com/gpu.compute.major": "8",
"nvidia.com/gpu.compute.minor": "0",
"nvidia.com/gpu.count": "1",
"nvidia.com/gpu.family": "ampere",
"nvidia.com/gpu.machine": "NVIDIA DGX",
"nvidia.com/gpu.memory": "40537",
"nvidia.com/gpu.product": "A100-SXM4-40GB"
}

6、部署一个pod用于消耗 GPU 并运行 nvidia-smi 命令

$ kubectl run -it --rm \
   --image=nvidia/cuda:11.0-base \
   --restart=Never \
   --limits=nvidia.com/gpu=1 \
   mig-none-example -- nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-15f0798d-c807-231d-6525-a7827081f0f1)

7、为 GPU 开启 MIG(需要先停掉所有 GPU 客户端)

$ sudo systemctl stop kubelet
$ sudo nvidia-smi -mig 1
Enabled MIG Mode for GPU 00000000:36:00.0
All done.

$ nvidia-smi --query-gpu=mig.mode.current --format=csv,noheader
Enabled

8、重启 kubelet 和 nvidia-device-plugin

$ sudo systemctl start kubelet

9、观察到节点上只有1个可用、资源类型为 nvidia.com/gpu 的 GPU:

$ kubectl describe node
...
Capacity:
nvidia.com/gpu:          1
...
Allocatable:
nvidia.com/gpu:          1
...

10、观察到节点标签未发生变化

$ kubectl get node -o json | \
   jq '.items[0].metadata.labels | with_entries(select(.key | startswith("nvidia.com")))'
{
"nvidia.com/cuda.driver.major": "450",
"nvidia.com/cuda.driver.minor": "80",
"nvidia.com/cuda.driver.rev": "02",
"nvidia.com/cuda.runtime.major": "11",
"nvidia.com/cuda.runtime.minor": "0",
"nvidia.com/gfd.timestamp": "1605312111",
"nvidia.com/gpu.compute.major": "8",
"nvidia.com/gpu.compute.minor": "0",
"nvidia.com/gpu.count": "1",
"nvidia.com/gpu.family": "ampere",
"nvidia.com/gpu.machine": "NVIDIA DGX",
"nvidia.com/gpu.memory": "40537",
"nvidia.com/gpu.product": "A100-SXM4-40GB"
}

11、部署一个pod用于消耗 GPU 并运行 nvidia-smi 命令

$ kubectl run -it --rm \
   --image=nvidia/cuda:11.0-base \
   --restart=Never \
   --limits=nvidia.com/gpu=1 \
   mig-none-example -- nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-15f0798d-c807-231d-6525-a7827081f0f1)

single

single 策略旨在保持在Kubernetes中使用GPU的用户体验与以往相同。MIG 设备也会以 nvidia.com/gpu 类型列举出来。然而,该资源类型的属性会被映射到当前节点上可以的 MIG 设备,而不是完整的 GPU。

通过该测试,我们可以看到所有 MIG 设备会以传统的 nvidia.com/gpu 资源类型列举出来。该测试假设集群中的单个节点上有一个GPU,并且支持 MIG。

1、确保 GPU 支持 MIG,并且没有开启 MIG

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  A100-SXM4-40GB      On   | 00000000:00:04.0 Off |                   On |
| N/A   32C    P0    43W / 400W |      0MiB / 40537MiB |     N/A      Default |
|                               |                      |              Enabled |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| MIG devices:                                                                |
+------------------+----------------------+-----------+-----------------------+
| GPU  GI  CI  MIG |         Memory-Usage |        Vol|         Shared        |
|      ID  ID  Dev |           BAR1-Usage | SM     Unc| CE  ENC  DEC  OFA  JPG|
|                  |                      |        ECC|                       |
|==================+======================+===========+=======================|
|  No MIG devices found                                                       |
+-----------------------------------------------------------------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

2、在该 GPU 设备上创建7个单切片 MIG 设备:

$ sudo nvidia-smi mig -cgi 19,19,19,19,19,19,19 -C
$ nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-4200ccc0-2667-d4cb-9137-f932c716232a)
  MIG 1g.5gb Device 0: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/7/0)
  MIG 1g.5gb Device 1: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/8/0)
  MIG 1g.5gb Device 2: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/9/0)
  MIG 1g.5gb Device 3: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/10/0)
  MIG 1g.5gb Device 4: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/11/0)
  MIG 1g.5gb Device 5: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/12/0)
  MIG 1g.5gb Device 6: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/13/0)

3、用 single 策略启动 nvidia-device-plugin。如果已经在运行,则需要重启。

4、观察到当前节点上出现7个资源类型为 nvidia.com/gpu 的 MIG 设备:

$ kubectl describe node
...
Capacity:
nvidia.com/gpu:          7
...
Allocatable:
nvidia.com/gpu:          7
...

5、用 single 策略启动 gpu-feature-discovery。如果已经在运行,则需要重启。

6、观察到已经为当前 MIG 策略正确设置相关标签:

$ kubectl get node -o json | \
   jq '.items[0].metadata.labels | with_entries(select(.key | startswith("nvidia.com")))'
{
"nvidia.com/cuda.driver.major": "450",
"nvidia.com/cuda.driver.minor": "80",
"nvidia.com/cuda.driver.rev": "02",
"nvidia.com/cuda.runtime.major": "11",
"nvidia.com/cuda.runtime.minor": "0",
"nvidia.com/gfd.timestamp": "1605657366",
"nvidia.com/gpu.compute.major": "8",
"nvidia.com/gpu.compute.minor": "0",
"nvidia.com/gpu.count": "7",
"nvidia.com/gpu.engines.copy": "1",
"nvidia.com/gpu.engines.decoder": "0",
"nvidia.com/gpu.engines.encoder": "0",
"nvidia.com/gpu.engines.jpeg": "0",
"nvidia.com/gpu.engines.ofa": "0",
"nvidia.com/gpu.family": "ampere",
"nvidia.com/gpu.machine": "NVIDIA DGX",
"nvidia.com/gpu.memory": "4864",
"nvidia.com/gpu.multiprocessors": "14",
"nvidia.com/gpu.product": "A100-SXM4-40GB-MIG-1g.5gb",
"nvidia.com/gpu.slices.ci": "1",
"nvidia.com/gpu.slices.gi": "1",
"nvidia.com/mig.strategy": "single"
}

7、部署7个pod,每个pod消费一个 MIG 设备(然后读取pod日志并删除pod)

$ for i in $(seq 7); do
   kubectl run \
      --image=nvidia/cuda:11.0-base \
      --restart=Never \
      --limits=nvidia.com/gpu=1 \
      mig-single-example-${i} -- bash -c "nvidia-smi -L; sleep infinity"
done

pod/mig-single-example-1 created
pod/mig-single-example-2 created
pod/mig-single-example-3 created
pod/mig-single-example-4 created
pod/mig-single-example-5 created
pod/mig-single-example-6 created
pod/mig-single-example-7 created

$ for i in $(seq 7); do
echo "mig-single-example-${i}";
kubectl logs mig-single-example-${i}
echo "";
done

mig-single-example-1
GPU 0: A100-SXM4-40GB (UUID: GPU-4200ccc0-2667-d4cb-9137-f932c716232a)
   MIG 1g.5gb Device 0: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/7/0)

mig-single-example-2
GPU 0: A100-SXM4-40GB (UUID: GPU-4200ccc0-2667-d4cb-9137-f932c716232a)
   MIG 1g.5gb Device 0: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/9/0)

...

$ for i in $(seq 7); do
kubectl delete pod mig-single-example-${i};
done

pod "mig-single-example-1" deleted
pod "mig-single-example-2" deleted
...

mixed

mixed 旨在为集群中可用的每个MIG设备配置枚举不同的资源类型。

通过测试该策略,我们可以看到所有的 MIG 设备会以其全限定名称 nvidia.com/mig-<slice_count>g.<memory_size>gb 的方式列举出来。该测试假设集群中的单个节点上有一个GPU,并且支持 MIG。

1、确保 GPU 支持 MIG,并且没有开启 MIG

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  A100-SXM4-40GB      On   | 00000000:00:04.0 Off |                   On |
| N/A   32C    P0    43W / 400W |      0MiB / 40537MiB |     N/A      Default |
|                               |                      |              Enabled |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| MIG devices:                                                                |
+------------------+----------------------+-----------+-----------------------+
| GPU  GI  CI  MIG |         Memory-Usage |        Vol|         Shared        |
|      ID  ID  Dev |           BAR1-Usage | SM     Unc| CE  ENC  DEC  OFA  JPG|
|                  |                      |        ECC|                       |
|==================+======================+===========+=======================|
|  No MIG devices found                                                       |
+-----------------------------------------------------------------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

2、在该 GPU 设备上创建3个大小不同的 MIG 设备:

$ sudo nvidia-smi mig -cgi 9,14,19 -C
$ nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-4200ccc0-2667-d4cb-9137-f932c716232a)
  MIG 3g.20gb Device 0: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/2/0)
  MIG 2g.10gb Device 1: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/3/0)
  MIG 1g.5gb Device 2: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/9/0)

3、用 mixed 策略启动 nvidia-device-plugin。如果已经在运行,则需要重启。

4、观察到当前节点有3个 nvidia.com/gpu 类型的 MIG 设备可用:

$ kubectl describe node
...
Capacity:
nvidia.com/mig-1g.5gb:   1
nvidia.com/mig-2g.10gb:  1
nvidia.com/mig-3g.20gb:  1
...
Allocatable:
nvidia.com/mig-1g.5gb:   1
nvidia.com/mig-2g.10gb:  1
nvidia.com/mig-3g.20gb:  1
...

5、用 mixed 策略启动 gpu-feature-discovery。如果已经在运行,则需要重启。

6、观察到已经为当前 MIG 策略正确设置相关标签:

$ kubectl get node -o json | \
   jq '.items[0].metadata.labels | with_entries(select(.key | startswith("nvidia.com")))'
{
"nvidia.com/cuda.driver.major": "450",
"nvidia.com/cuda.driver.minor": "80",
"nvidia.com/cuda.driver.rev": "02",
"nvidia.com/cuda.runtime.major": "11",
"nvidia.com/cuda.runtime.minor": "0",
"nvidia.com/gfd.timestamp": "1605658841",
"nvidia.com/gpu.compute.major": "8",
"nvidia.com/gpu.compute.minor": "0",
"nvidia.com/gpu.count": "1",
"nvidia.com/gpu.family": "ampere",
"nvidia.com/gpu.machine": "NVIDIA DGX",
"nvidia.com/gpu.memory": "40537",
"nvidia.com/gpu.product": "A100-SXM4-40GB",
"nvidia.com/mig-1g.5gb.count": "1",
"nvidia.com/mig-1g.5gb.engines.copy": "1",
"nvidia.com/mig-1g.5gb.engines.decoder": "0",
"nvidia.com/mig-1g.5gb.engines.encoder": "0",
"nvidia.com/mig-1g.5gb.engines.jpeg": "0",
"nvidia.com/mig-1g.5gb.engines.ofa": "0",
"nvidia.com/mig-1g.5gb.memory": "4864",
"nvidia.com/mig-1g.5gb.multiprocessors": "14",
"nvidia.com/mig-1g.5gb.slices.ci": "1",
"nvidia.com/mig-1g.5gb.slices.gi": "1",
"nvidia.com/mig-2g.10gb.count": "1",
"nvidia.com/mig-2g.10gb.engines.copy": "2",
"nvidia.com/mig-2g.10gb.engines.decoder": "1",
"nvidia.com/mig-2g.10gb.engines.encoder": "0",
"nvidia.com/mig-2g.10gb.engines.jpeg": "0",
"nvidia.com/mig-2g.10gb.engines.ofa": "0",
"nvidia.com/mig-2g.10gb.memory": "9984",
"nvidia.com/mig-2g.10gb.multiprocessors": "28",
"nvidia.com/mig-2g.10gb.slices.ci": "2",
"nvidia.com/mig-2g.10gb.slices.gi": "2",
"nvidia.com/mig-3g.21gb.count": "1",
"nvidia.com/mig-3g.21gb.engines.copy": "3",
"nvidia.com/mig-3g.21gb.engines.decoder": "2",
"nvidia.com/mig-3g.21gb.engines.encoder": "0",
"nvidia.com/mig-3g.21gb.engines.jpeg": "0",
"nvidia.com/mig-3g.21gb.engines.ofa": "0",
"nvidia.com/mig-3g.21gb.memory": "20096",
"nvidia.com/mig-3g.21gb.multiprocessors": "42",
"nvidia.com/mig-3g.21gb.slices.ci": "3",
"nvidia.com/mig-3g.21gb.slices.gi": "3",
"nvidia.com/mig.strategy": "mixed"
}

7、部署3个pod,每个pod消费一个对应的 MIG 设备

$ kubectl run -it --rm \
   --image=nvidia/cuda:11.0-base \
   --restart=Never \
   --limits=nvidia.com/mig-1g.5gb=1 \
   mig-mixed-example -- nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-4200ccc0-2667-d4cb-9137-f932c716232a)
MIG 1g.5gb Device 0: (UUID: MIG-GPU-4200ccc0-2667-d4cb-9137-f932c716232a/9/0)
pod "mig-mixed-example" deleted
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,848评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,529评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,824评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,329评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,227评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,879评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,218评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,877评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,159评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,155评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,987评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,736评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,273评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,407评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,663评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,158评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,517评论 2 339

推荐阅读更多精彩内容