Kubernetes 中的时间分片 GPU#
了解时间分片 GPU#
NVIDIA GPU Operator 通过 NVIDIA Kubernetes Device Plugin 的一组扩展选项,实现了 GPU 的超额订阅。GPU 时间分片使计划在超额订阅 GPU 上的工作负载能够相互交错运行。
这种在 Kubernetes 中启用 GPU时间分片的机制使系统管理员能够为 GPU 定义一组副本,每个副本都可以独立分发给 Pod 以运行工作负载。与多实例 GPU (MIG) 不同,副本之间没有内存或故障隔离,但对于某些工作负载来说,这比完全无法共享要好。在内部,GPU 时间分片用于多路复用来自同一底层 GPU 副本的工作负载。
注意
典型的资源请求提供对 GPU 的独占访问。对时间分片 GPU 的请求提供共享访问。请求多个时间分片 GPU 并不能保证 Pod 获得成比例的 GPU 计算能力。
请求多个时间分片 GPU 仅指定 Pod 可以访问与其他 Pod 共享的 GPU。每个 Pod 可以在底层 GPU 上运行任意数量的进程,而没有限制。GPU 只是在所有 Pod 的所有 GPU 进程之间提供相等的时间份额。
您可以应用集群范围的默认时间分片配置。您还可以应用节点特定的配置。例如,您可以仅对具有 Tesla-T4 GPU 的节点应用时间分片配置,而不修改具有其他 GPU 型号的节点。
您可以将这两种方法结合起来,应用集群范围的默认配置,然后标记节点,以便这些节点接收节点特定的配置。
比较:时间分片和多实例 GPU#
最新一代 NVIDIA GPU 提供了一种名为多实例 GPU (MIG) 的操作模式。MIG 允许您将 GPU 分区为几个较小的、预定义的实例,每个实例看起来都像一个迷你 GPU,在硬件层提供内存和故障隔离。您可以通过在这些预定义实例之一上运行工作负载,而不是在完整的原生 GPU 上运行工作负载来共享对 GPU 的访问。
MIG 支持于 2020 年添加到 Kubernetes 中。有关其工作原理的详细信息,请参阅在 Kubernetes 中支持 MIG。
时间分片牺牲了 MIG 提供的内存和故障隔离,以换取更多用户共享 GPU 的能力。时间分片还为不支持 MIG 的旧代 GPU 提供了一种共享访问 GPU 的方法。但是,您可以结合使用 MIG 和时间分片来提供对 MIG 实例的共享访问。
支持平台和资源类型#
GPU 时间分片可以与裸金属应用程序、具有 GPU 直通的虚拟机以及具有 NVIDIA vGPU 的虚拟机一起使用。
目前,唯一支持的资源类型是 nvidia.com/gpu
以及通过使用混合 MIG 策略配置节点而出现的任何资源类型。
限制#
当启用 GPU 时间分片并使用 NVIDIA Kubernetes Device Plugin 时,DCGM-Exporter 不支持将指标与容器关联。
Operator 不会监视时间分片 ConfigMap 的更改。请参阅更新时间分片 ConfigMap。
节点标签的更改#
除了 GPU Feature Discovery (GFD) 应用于节点的标准节点标签之外,在您为节点配置 GPU 时间分片后,还会应用以下标签
nvidia.com/<resource-name>.replicas = <replicas-count>
其中 <replicas-count>
是 <resource-name>
的每个资源被超额订阅的因子。
此外,默认情况下,nvidia.com/<resource-name>.product
标签会被修改
nvidia.com/<resource-name>.product = <product-name>-SHARED
例如,在 NVIDIA DGX A100 机器上,根据时间分片配置,标签可能类似于以下示例
nvidia.com/gpu.replicas = 8
nvidia.com/gpu.product = A100-SXM4-40GB-SHARED
使用这些标签,您可以请求时间分片 GPU 的访问权限或独占 GPU 的访问权限,就像您传统上指定节点选择器来请求一种 GPU 型号而不是另一种型号一样。也就是说,-SHARED
产品名称后缀确保您可以指定节点选择器,以将 Pod 分配给具有时间分片 GPU 的节点。
migStrategy
配置选项对产品名称的节点标签有影响。当 renameByDefault=false
(默认值)和 migStrategy=single
时,MIG 配置文件名称和 -SHARED
后缀都将附加到产品名称,例如以下示例
nvidia.com/gpu.product = A100-SXM4-40GB-MIG-1g.5gb-SHARED
如果您设置 renameByDefault=true
,则 nvidia.com/gpu.product
节点标签的值不会被修改。
配置#
关于配置 GPU 时间分片#
您可以通过执行以下高级步骤来配置 GPU 时间分片
将 ConfigMap 添加到 GPU Operator 使用的命名空间。
配置集群策略,以便 Device Plugin 使用 ConfigMap。
将标签应用于要配置 GPU 时间分片的节点。
在具有一个 GPU 的机器上,以下 ConfigMap 配置 Kubernetes,以便节点通告四个 GPU 资源。具有两个 GPU 的机器通告八个 GPU,依此类推。
示例 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config
data:
any: |-
version: v1
flags:
migStrategy: none
sharing:
timeSlicing:
renameByDefault: false
failRequestsGreaterThanOne: false
resources:
- name: nvidia.com/gpu
replicas: 4
下表描述了 ConfigMap 中的关键字段。
字段 |
类型 |
描述 |
---|---|---|
|
字符串 |
指定时间分片配置名称。 如果您要分配节点特定的配置,则可以指定多个配置。在前面的示例中, |
|
字符串 |
指定如何标记接收时间分片配置的节点的 MIG 设备。指定 默认值为 |
|
布尔值 |
设置为 例如,如果此字段设置为 当此字段设置为 默认值为 |
|
布尔值 |
此字段的目的是强制意识到请求多个 GPU 副本不会导致获得更多比例的 GPU 访问权限。 例如,如果 设置为 |
|
字符串 |
指定要通过时间分片访问提供的资源类型,例如 |
|
整数 |
指定要为共享访问指定资源类型的 GPU 提供的分时 GPU 副本的数量。 |
应用一个集群范围的配置#
如果您已经安装了 GPU Operator 并希望在集群中的所有节点上应用相同的时间分片配置,请执行以下步骤来配置 GPU 时间分片。
创建一个文件,例如
time-slicing-config-all.yaml
,内容如下例所示apiVersion: v1 kind: ConfigMap metadata: name: time-slicing-config-all data: any: |- version: v1 flags: migStrategy: none sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4
将 ConfigMap 添加到与 GPU Operator 相同的命名空间
$ kubectl create -n gpu-operator -f time-slicing-config-all.yaml
使用 ConfigMap 配置 Device Plugin 并设置默认时间分片配置
$ kubectl patch clusterpolicies.nvidia.com/cluster-policy \ -n gpu-operator --type merge \ -p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config-all", "default": "any"}}}}'
可选:确认
gpu-feature-discovery
和nvidia-device-plugin-daemonset
Pod 重新启动。$ kubectl get events -n gpu-operator --sort-by='.lastTimestamp'
示例输出
LAST SEEN TYPE REASON OBJECT MESSAGE 33s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container toolkit-validation 33s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container toolkit-validation 33s Normal Started pod/gpu-feature-discovery-rvlg9 Started container toolkit-validation 33s Normal Created pod/gpu-feature-discovery-rvlg9 Created container toolkit-validation 33s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/cloud-native/gpu-operator-validator:v22.9.1" already present on machine 33s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/cloud-native/gpu-operator-validator:v22.9.1" already present on machine 32s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container config-manager-init 32s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 32s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 32s Normal Created pod/gpu-feature-discovery-rvlg9 Created container config-manager-init 32s Normal Started pod/gpu-feature-discovery-rvlg9 Started container config-manager-init 32s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container config-manager-init 31s Normal Created pod/gpu-feature-discovery-rvlg9 Created container config-manager 31s Normal Started pod/gpu-feature-discovery-rvlg9 Started container gpu-feature-discovery 31s Normal Created pod/gpu-feature-discovery-rvlg9 Created container gpu-feature-discovery 31s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/gpu-feature-discovery:v0.7.0-ubi8" already present on machine 31s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container config-manager 31s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container config-manager 31s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container nvidia-device-plugin 31s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container nvidia-device-plugin 31s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Started pod/gpu-feature-discovery-rvlg9 Started container config-manager
请参阅验证 GPU 时间分片配置。
应用多个节点特定的配置#
应用一个集群范围配置的替代方法是在 ConfigMap 中指定多个时间分片配置,并逐节点应用标签以控制将哪个配置应用于哪些节点。
创建一个文件,例如
time-slicing-config-fine.yaml
,内容如下例所示apiVersion: v1 kind: ConfigMap metadata: name: time-slicing-config-fine data: a100-40gb: |- version: v1 flags: migStrategy: mixed sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 8 - name: nvidia.com/mig-1g.5gb replicas: 2 - name: nvidia.com/mig-2g.10gb replicas: 2 - name: nvidia.com/mig-3g.20gb replicas: 3 - name: nvidia.com/mig-7g.40gb replicas: 7 tesla-t4: |- version: v1 flags: migStrategy: none sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4
将 ConfigMap 添加到与 GPU Operator 相同的命名空间
$ kubectl create -n gpu-operator -f time-slicing-config-fine.yaml
使用 ConfigMap 配置 Device Plugin 并设置默认时间分片配置
$ kubectl patch clusterpolicies.nvidia.com/cluster-policy \ -n gpu-operator --type merge \ -p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config-fine"}}}}'
由于规范不包含
devicePlugin.config.default
字段,因此当 Device Plugin Pod 重新部署时,它们不会自动将时间分片配置应用于所有节点。可选:确认
gpu-feature-discovery
和nvidia-device-plugin-daemonset
Pod 重新启动。$ kubectl get events -n gpu-operator --sort-by='.lastTimestamp'
示例输出
LAST SEEN TYPE REASON OBJECT MESSAGE 33s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container toolkit-validation 33s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container toolkit-validation 33s Normal Started pod/gpu-feature-discovery-rvlg9 Started container toolkit-validation 33s Normal Created pod/gpu-feature-discovery-rvlg9 Created container toolkit-validation 33s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/cloud-native/gpu-operator-validator:v22.9.1" already present on machine 33s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/cloud-native/gpu-operator-validator:v22.9.1" already present on machine 32s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container config-manager-init 32s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 32s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 32s Normal Created pod/gpu-feature-discovery-rvlg9 Created container config-manager-init 32s Normal Started pod/gpu-feature-discovery-rvlg9 Started container config-manager-init 32s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container config-manager-init 31s Normal Created pod/gpu-feature-discovery-rvlg9 Created container config-manager 31s Normal Started pod/gpu-feature-discovery-rvlg9 Started container gpu-feature-discovery 31s Normal Created pod/gpu-feature-discovery-rvlg9 Created container gpu-feature-discovery 31s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/gpu-feature-discovery:v0.7.0-ubi8" already present on machine 31s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container config-manager 31s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container config-manager 31s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Started pod/nvidia-device-plugin-daemonset-cffds Started container nvidia-device-plugin 31s Normal Created pod/nvidia-device-plugin-daemonset-cffds Created container nvidia-device-plugin 31s Normal Pulled pod/nvidia-device-plugin-daemonset-cffds Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Pulled pod/gpu-feature-discovery-rvlg9 Container image "nvcr.io/nvidia/k8s-device-plugin:v0.13.0-ubi8" already present on machine 31s Normal Started pod/gpu-feature-discovery-rvlg9 Started container config-manager
通过运行以下一个或多个命令,将标签应用于节点
通过指定节点名称,逐个将标签应用于节点
$ kubectl label node <node-name> nvidia.com/device-plugin.config=tesla-t4
通过指定标签选择器,一次将标签应用于多个节点
$ kubectl label node \ --selector=nvidia.com/gpu.product=Tesla-T4 \ nvidia.com/device-plugin.config=tesla-t4
请参阅验证 GPU 时间分片配置。
在安装 NVIDIA GPU Operator 之前配置时间分片#
您可以通过在安装期间传递 devicePlugin.config.name=<config-map-name>
参数,使用 NVIDIA GPU Operator 启用时间分片。
执行以下步骤以在安装 Operator 之前配置时间分片
为 Operator 创建命名空间
$ kubectl create namespace gpu-operator
创建一个文件,例如
time-slicing-config.yaml
,其中包含 ConfigMap 内容。请参阅应用一个集群范围的配置或应用多个节点特定的配置部分。
将 ConfigMap 添加到与 GPU Operator 相同的命名空间
$ kubectl create -f time-slicing-config.yaml
使用 Helm 安装 Operator
$ helm install gpu-operator nvidia/gpu-operator \ -n gpu-operator \ --version=v24.9.2 \ --set devicePlugin.config.name=time-slicing-config
请参阅应用一个集群范围的配置或应用多个节点特定的配置,并执行以下任务
通过运行
kubectl patch
命令来配置 Device Plugin。如果您添加了带有节点特定配置的 ConfigMap,请将标签应用于节点。
安装后,请参阅验证 GPU 时间分片配置。
更新时间分片 ConfigMap#
Operator 不会监视时间分片 ConfigMap。因此,如果您修改 ConfigMap,Device Plugin Pod 不会重新启动,也不会应用修改后的配置。
要应用修改后的 ConfigMap,请手动重新启动 Device Plugin Pod
$ kubectl rollout restart -n gpu-operator daemonset/nvidia-device-plugin-daemonset
当前正在运行的工作负载不受影响并继续运行,但 NVIDIA 建议在维护期间执行重新启动。
验证 GPU 时间分片配置#
执行以下步骤以验证时间分片配置是否已成功应用
确认节点通告了额外的 GPU 资源
$ kubectl describe node <node-name>
示例输出
示例输出因节点中的 GPU 和您应用的配置而异。
以下输出适用于
renameByDefault
设置为false
(默认值)时。关键考虑因素如下nvidia.com/gpu.count
标签报告机器中物理 GPU 的数量。nvidia.com/gpu.product
标签在产品名称中包含-SHARED
后缀。nvidia.com/gpu.replicas
标签与报告的容量匹配。
... Labels: nvidia.com/gpu.count=4 nvidia.com/gpu.product=Tesla-T4-SHARED nvidia.com/gpu.replicas=4 Capacity: nvidia.com/gpu: 16 ... Allocatable: nvidia.com/gpu: 16 ...
以下输出适用于
renameByDefault
设置为true
时。关键考虑因素如下nvidia.com/gpu.count
标签报告机器中物理 GPU 的数量。nvidia.com/gpu
容量报告0
。nvidia.com/gpu.shared
容量等于物理 GPU 的数量乘以要创建的指定 GPU 副本的数量。
... Labels: nvidia.com/gpu.count=4 nvidia.com/gpu.product=Tesla-T4 nvidia.com/gpu.replicas=4 Capacity: nvidia.com/gpu: 0 nvidia.com/gpu.shared: 16 ... Allocatable: nvidia.com/gpu: 0 nvidia.com/gpu.shared: 16 ...
可选:部署工作负载以验证 GPU 时间分片
创建一个文件,例如
time-slicing-verification.yaml
,内容如下apiVersion: apps/v1 kind: Deployment metadata: name: time-slicing-verification labels: app: time-slicing-verification spec: replicas: 5 selector: matchLabels: app: time-slicing-verification template: metadata: labels: app: time-slicing-verification spec: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule hostPID: true containers: - name: cuda-sample-vector-add image: "nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubuntu20.04" command: ["/bin/bash", "-c", "--"] args: - while true; do /cuda-samples/vectorAdd; done resources: limits: nvidia.com/gpu: 1
使用多个副本创建部署
$ kubectl apply -f time-slicing-verification.yaml
验证所有五个副本都在运行
$ kubectl get pods
示例输出
NAME READY STATUS RESTARTS AGE time-slicing-verification-7cdc7f87c5-lkd9d 1/1 Running 0 23s time-slicing-verification-7cdc7f87c5-rrzq7 1/1 Running 0 23s time-slicing-verification-7cdc7f87c5-s8qwk 1/1 Running 0 23s time-slicing-verification-7cdc7f87c5-xhmb7 1/1 Running 0 23s time-slicing-verification-7cdc7f87c5-zsncp 1/1 Running 0 23s
查看其中一个 Pod 的日志
$ kubectl logs deploy/time-slicing-verification
示例输出
Found 5 pods, using pod/time-slicing-verification-7cdc7f87c5-s8qwk [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSED Done [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory ...
停止部署
$ kubectl delete -f time-slicing-verification.yaml
示例输出
deployment.apps "time-slicing-verification" deleted