源码分析
启动参数
参数名称 | 对应环境变量 | 类型 | 参数说明 | 默认值 |
---|---|---|---|---|
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
}
构建设备列表
通过 nvml 获取设备数量
-
构建 PCIe 映射
遍历 /sys/devices/ 目录及其子目录,解析并过滤 PCIe 设备目录
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
遍历所有设备,并根据 index 从 nvml 获取设备详细信息
判断是不是MIG设备,如果是 MIG 设备,并且 skipMigEnabledGPUs 为true,则跳过该设备
获取该设备的 PCI 信息,并通过 PCI 信息中的 busID 找到对应的 PCIe 设备名称
获取设备的 minor number 和 uuid
构建 *Device 对象,并加入 devices 设备列表中
设备健康检查
如果执行nvml相关命令超时(超时时间通过环境变量 NV_CHECK_TIMEOUT 获取,默认超时时间为5s),则认为所有设备都不健康
如果执行nvml获取某一设备失败,则认为该设备不健康
如果禁用健康检查(环境变量 DP_DISABLE_HEALTHCHECKS == "all"),则不继续执行健康检查操作
遍历所有设备,检查设备是否为 StdCard 模式
执行 dmesg -t -k -l warn -f daemon | grep 'NVRM: Xid' 命令,检查设备是否发生 xid 错误
-
如果设备发生 xid 错误,或者不是标准卡,则认为该设备发生故障
ecc mode 开启,且count 为0
compute mode 为default
persistence mode 为on
accountting mode 为off
display active 为 off
display mode 为 on
如果设备抛出 nvml.EventTypeXidCriticalError 事件,且 xid 类型不在要跳过的错误类型中(13,31,43,45,68)中,则认为该设备发生故障
如果设备发生 xid 错误,则 XIDCondition 并上报给 healthProbe
发生故障的设备信息会被放入 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 会定期探测节点上的设备信息,并根据设备类型为节点打上对应的标签,这些标签包括:
gpu-model:GPU 资源类型,详见 https://km.sankuai.com/page/1221978322 和 https://pci-ids.ucw.cz/read/PC/10de
gpu-memory:显存配置
gpu-driver-version:NVIDIA 驱动版本
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
}
探测过程
获取任一设备信息及设备对于的 PCI 信息
根据 PCI ID获取对应的资源类型
根据资源类型获取对应的显存配置
如果设备支持 MIG,获取其关联的所有 MIG 设备,并根据 MIG 设备数量获取其对应的资源类型、显存配置信息
从 nvml 获取 NVIDIA 驱动版本
为节点打上对应的标签
资源名和显存大小对应关系
"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()
获取从 BuildDevices() 方法得到的设备列表,并赋值给 cachedDevices
创建 *grpc.Server 及 health channel、stop channel
创建 *kubernetes.Clientset 实例,用于和 apiserver 交互,并创建 EventRecorder
开启 Detector 探测,Dectector 会定期探测节点上的设备信息,并根据设备类型为节点打上对应的标签
创建 HealthProbeClient,并创建 HealthProbe
-
启动 gpu-device-plugin 的 gRPC 服务
删除 /var/lib/kubelet/device-plugins/nvidia-gpu.sock 文件,并重新监听该文件
启动 gRPC 服务,并记录重启次数
通过启动阻塞连接等待服务器启动
-
向Kubelet注册给定resourceName的设备插件
连接 /var/lib/kubelet/device-plugins/kubelet.sock,超时时间为5s
调用 kubelet 的 Register() 方法,向 kubelet 注册自身
开启设备健康检查
启动过程
注册Prometheus指标 nvml_init_failed 和 gpu_xid_error
注册 /metrics HTTP站点
访问 /dev 目录,判断是否存在 nvidia 设备
nvml.Init(),如果 nvml 初始化失败,则向 apiserver 上报 "Nvml Init Failed" 事件
注册Prometheus指标gpu_topology_sum、healthy_device_count、available_device_count 和 allocate_stats
创建 FSWatcher 监控 /var/lib/kubelet/device-plugins/ 目录变更
创建 OSWatcher 监听停止、重启等系统信号
根据 mig-strategy 策略创建对应的 MigStrategy 实例
根据命令行参数创建 plugin.Config 实例
根据配置的 MIG 策略,创建对应的 NvidiaDevicePlugin
创建 pluginStartError channel,用于接收插件启动失败信息
遍历所有 NvidiaDevicePlugin,调用其 BuildDevices() 方法从 nvml 获取设备列表,并筛选符合条件的设备
调用插件的 Start() 方法,如果 Start() 执行失败,则将错误放入 pluginStartError
启动过程详见:NvidiaDevicePlugin.Start()
开启事件监听
如果从 pluginStartError channel中接收到插件启动失败信息,则执行重启操作
如果从 FSWatcher 监听到 /var/lib/kubelet/device-plugins/kubelet.sock 文件创建事件(即 kubelet 重启事件),则执行重启操作
如果从 FSWatcher 监听到 error 信息,则在日志中记录该 error信息
如果从 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