Kubernetes 中的 MIG 支持

多实例 GPU (MIG) 功能支持将 GPU(例如 NVIDIA A100)安全地划分为多个独立的 GPU 实例,用于 CUDA 应用程序。例如,NVIDIA A100 最多支持七个独立的 GPU 实例。

MIG 为多个用户提供独立的 GPU 资源,以实现最佳的 GPU 利用率。此功能对于不能完全饱和 GPU 计算能力的工作负载尤其有益,因此用户可能希望并行运行不同的工作负载以最大化利用率。

本文档概述了启用 Kubernetes 的 MIG 支持所需的必要软件。有关技术概念、MIG 设置以及使用 MIG 运行容器的 NVIDIA Container Toolkit 的更多详细信息,请参阅 MIG 用户指南

部署工作流程需要以下先决条件

  1. 您已安装 NVIDIA A100 所需的 NVIDIA R450+ 数据中心 (450.80.02+) 驱动程序。

  2. 您已安装 NVIDIA Container Toolkit v2.5.0+

  3. 您已经有一个 Kubernetes 部署正在运行,并且可以访问至少一个 NVIDIA A100 GPU。

满足这些先决条件后,您可以继续在集群中部署 NVIDIA k8s-device-plugin 和(可选)gpu-feature-discovery 组件的 MIG 功能版本,以便 Kubernetes 可以在可用的 MIG 设备上调度 Pod。

下面列出了所需软件组件的最低版本

  1. NVIDIA R450+ 数据中心驱动程序:450.80.02+

  2. NVIDIA Container Toolkit (nvidia-docker2):v2.5.0+

  3. NVIDIA k8s-device-plugin:v0.7.0+

  4. NVIDIA gpu-feature-discovery:v0.2.0+

MIG 策略

NVIDIA 提供了两种在 Kubernetes 节点上公开 MIG 设备的策略。有关策略的更多详细信息,请参阅 设计文档

在 Kubernetes 中使用 MIG 策略

本节将逐步介绍部署和运行各种 MIG 策略的 k8s-device-plugingpu-feature-discovery 组件所需的步骤。首选的部署方法是通过 Helm。

对于备用部署方法,请参阅以下 GitHub 存储库中的安装说明

首先,添加 nvidia-device-plugingpu-feature-discovery helm 存储库

$ helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
$ helm repo add nvgfd https://nvidia.github.io/gpu-feature-discovery
$ helm repo update

然后,验证 nvidia-device-pluginv0.7.0 版本和 gpu-feature-discoveryv0.2.0 版本是否可用

$ helm search repo nvdp --devel
NAME                           CHART VERSION  APP VERSION    DESCRIPTION
nvdp/nvidia-device-plugin      0.7.0          0.7.0         A Helm chart for ...
$ helm search repo nvgfd --devel
NAME                           CHART VERSION  APP VERSION    DESCRIPTION
nvgfd/gpu-feature-discovery  0.2.0          0.2.0           A Helm chart for ...

最后,选择一个 MIG 策略并部署 nvidia-device-plugingpu-feature-discovery 组件

$ export MIG_STRATEGY=<none | single | mixed>
$ helm install \
   --version=0.7.0 \
   --generate-name \
   --set migStrategy=${MIG_STRATEGY} \
   nvdp/nvidia-device-plugin
$ helm install \
   --version=0.2.0 \
   --generate-name \
   --set migStrategy=${MIG_STRATEGY} \
   nvgfd/gpu-feature-discovery

使用不同策略进行测试

本节将逐步介绍测试每种 MIG 策略所需的步骤。

注意

在默认设置下,对于 mixed 策略,一个容器一次只能请求 一种 设备类型。如果容器请求多种设备类型,则接收到的设备是未定义的。例如,容器不能同时请求 nvidia.com/gpunvidia.com/mig-3g.20gb。但是,它可以请求同一资源类型的多个实例(例如,nvidia.com/gpu: 2nvidia.com/mig-3g.20gb: 2),而没有限制。

为了缓解此行为,我们建议遵循 文档 中概述的指南。

none 策略

none 策略旨在使 nvidia-device-plugin 的运行方式与以往相同。该插件不会区分启用或未启用 MIG 的 GPU,并将枚举节点上的所有 GPU,使其可以使用 nvidia.com/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。如果插件已在运行,请重新启动它。

  3. 观察到节点上有一个 GPU 可用,资源类型为 nvidia.com/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 和插件

    $ sudo systemctl start kubelet
    
  9. 观察到节点上有一个 GPU 可用,资源类型为 nvidia.com/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:9.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。

测试

为了测试此策略,我们检查是否使用传统的 nvidia.com/gpu 资源类型枚举了单一类型的 MIG 设备。此测试假设集群中的单个节点上有一个 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 个 MIG 设备可用,资源类型为 nvidia.com/gpu

    $ 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 设备(然后读取其日志并删除它们)

    $ 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 设备配置枚举不同的资源类型。

测试

为了测试此策略,我们检查是否使用其完全限定名称(格式为 nvidia.com/mig-<slice_count>g.<memory_size>gb)枚举了所有 MIG 设备。此测试假设集群中的单个节点上有一个 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 个 MIG 设备可用,资源类型为 nvidia.com/gpu

    $ 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