本文介绍如何在ACK灵骏托管版集群中的灵骏节点上使用共享GPU调度,实现GPU的共享和隔离能力。
前提条件
已创建ACK灵骏托管版集群,并且集群带有GPU的灵骏节点。具体操作,请参见创建带有ACK灵骏托管版的集群。
ACK灵骏托管版集群默认会安装共享GPU调度组件,您可以在ACK灵骏托管集群中通过给GPU节点打上共享GPU调度的标签开启节点共享GPU调度能力。相关信息,请参见GPU节点调度属性标签说明。
使用共享GPU调度
对于使用共享GPU调度,一般分为如下两种场景:
仅共享不隔离:允许多个Pod共同运行在同一块GPU上,并不处理(或交由上层应用处理)这块GPU卡上多个Pod之间相互影响的问题,例如争抢GPU显存资源等情况。
既共享又隔离:允许多个Pod运行在同一块GPU上,同时也处理这块GPU卡上多个Pod相互影响的问题。
场景1:仅共享不隔离
在部分场景中,不需要GPU隔离模块参与共享GPU调度。有些业务应用本身提供显存限制能力,例如Java应用启动时,可以通过选项指定该应用的最大内存使用量。这种情况下,使用GPU隔离模块隔离业务显存会有资源冲突等问题。因此,共享GPU调度支持某些节点不安装GPU隔离模块的选项。
步骤一:开启节点GPU共享调度能力
查找
/etc/lingjun_metadata
文件是否存在。如果文件存在,然后执行命令
nvidia-smi
,如果输出正常,表明该节点为预期开启共享GPU调度能力的灵骏节点,可继续执行下一步。如果文件不存在,表明预期开启共享GPU调度能力的节点不是灵骏节点,因此此节点无法开启GPU共享调度能力。如果需要开启GPU共享调度能力,请创建灵骏节点。具体操作,请参见灵骏节点池概述。
执行如下命令,通过给节点设置标签
ack.node.gpu.schedule
为节点开启共享GPU调度能力。
kubectl label node <NODE_NAME> ack.node.gpu.schedule=share
步骤二:使用GPU共享资源
使用以下示例创建
tensorflow.yaml
文件。apiVersion: batch/v1 kind: Job metadata: name: tensorflow-mnist-share spec: parallelism: 1 template: metadata: labels: app: tensorflow-mnist-share spec: # 该YAML定义了一个使用tensorflow mnist样例的Job。Job有1个Pod,该Pod申请4 GiB显存。 containers: - name: tensorflow-mnist-share image: registry.cn-beijing.aliyuncs.com/ai-samples/gpushare-sample:tensorflow-1.5 command: - python - tensorflow-sample-code/tfjob/docker/mnist/main.py - --max_steps=100000 - --data_dir=tensorflow-sample-code/data resources: # Pod申请4 GiB显存通过在Pod resources.limits定义aliyun.com/gpu-mem: 4实现。 limits: aliyun.com/gpu-mem: 4 # 总共申请4 GiB显存。 workingDir: /root restartPolicy: Never
执行如下命令,提交任务。
kubectl apply -f tensorflow.yaml
步骤三:验证仅共享不隔离能力
找到前一步创建Job的Pod,使用kubectl执行如下命令。
kubectl get pod | grep tensorflow
kubectl exec -ti tensorflow-mnist-share-xxxxx -- nvidia-smi
预期输出:
Wed Jun 14 06:45:56 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.105.01 Driver Version: 515.105.01 CUDA Version: 11.7 |
|-------------------------------+----------------------+----------------------+
| 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 Tesla V100-SXM2... On | 00000000:00:09.0 Off | 0 |
| N/A 35C P0 59W / 300W | 334MiB / 16384MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
Pod内部能够发现整块GPU卡的总显存为16384 MiB,而在有隔离模块参与的场景下,该值与Pod申请值一致,说明配置生效。
本示例中使用的GPU卡型号为V100,Pod显存申请值为4 GiB,实际数据以您的操作环境为准。
业务应用需要从两个环境变量中读取该业务能够使用的显存值。
ALIYUN_COM_GPU_MEM_CONTAINER=4 # 该Pod能够使用的显存值。
ALIYUN_COM_GPU_MEM_DEV=16 # 每块GPU卡总共的显存值。
如果需要的是该应用使用的显存占GPU卡总显存的百分比。可以使用上述两个环境变量得出。
percetange = ALIYUN_COM_GPU_MEM_CONTAINER / ALIYUN_COM_GPU_MEM_DEV = 4 / 16 = 0.25
场景2:既共享又隔离
在多个Pod共享一块GPU前提下,隔离是一个关键的需求。如何限制运行在同一个GPU上的多个容器能够按照自己申请的资源使用量运行,避免因为其资源用量超标影响同一个GPU上的其他容器的正常工作,对此业界也做了很多探索。NVIDIA vGPU、MPS和vCUDA、eGPU等方案,都为更小颗粒度的使用GPU提供了可能,下面以eGPU隔离模块为例进行说明。
步骤一:开启节点GPU共享调度能力
查找
/etc/lingjun_metadata
文件是否存在。如果文件存在,然后执行命令
nvidia-smi
,如果输出正常,表明该节点为预期开启共享GPU调度能力的灵骏节点,可继续执行下一步。如果文件不存在,表明预期开启共享GPU调度能力的节点不是灵骏节点,因此此节点无法开启GPU共享调度能力。如果需要开启GPU共享调度能力,请创建灵骏节点。具体操作,请参见灵骏节点池概述。
执行如下命令,通过给节点设置标签
ack.node.gpu.schedule
为节点开启共享GPU调度能力。kubectl label node <NODE_NAME> ack.node.gpu.schedule=egpu_mem
如果标签的Value为egpu_mem,表示只进行GPU显存隔离。本文以该标签为例。
如果标签的Value设置为egpu_core_mem,表示进行GPU显存和算力双隔离。
您可以只申请GPU显存资源,但是如果要申请GPU算力资源,则需要同时申请GPU显存资源和GPU算力资源。
步骤二:使用GPU共享资源
等待节点将共享GPU的资源上报结束。
执行如下命令,查看Node资源信息。
kubectl get node <NODE_NAME> -oyaml
预期输出为:
allocatable:
aliyun.com/gpu-count: "1"
aliyun.com/gpu-mem: "80"
...
nvidia.com/gpu: "0"
...
capacity:
aliyun.com/gpu-count: "1"
aliyun.com/gpu-mem: "80
...
nvidia.com/gpu: "0"
...
预期输出表明,节点资源列表中已存在aliyun.com/gpu-mem
,总共1块GPU卡,80G显存。
如果Pod需要调度并使用整卡资源,则需要在目标Pod上增加标签ack.gpushare.placement=require-whole-device
,然后指定需要使用的GPU显存数量gpu-mem
,则该Pod会被默认调度到拥有该数量显存的整块GPU上。
步骤三:运行共享GPU示例
使用如下YAML提交Benchmark任务。
apiVersion: batch/v1 kind: Job metadata: name: benchmark-job spec: parallelism: 1 template: spec: containers: - name: benchmark-job image: registry.cn-beijing.aliyuncs.com/ai-samples/gpushare-sample:benchmark-tensorflow-2.2.3 command: - bash - run.sh - --num_batches=500000000 - --batch_size=8 resources: limits: aliyun.com/gpu-mem: 10 # 申请10G显存。 workingDir: /root restartPolicy: Never hostNetwork: true tolerations: - operator: Exists
执行如下命令,提交任务。
kubectl apply -f benchmark.yaml
等待Pod运行起来后,请使用如下命令进入Pod。
kubectl exec -ti benchmark-job-xxxx bash
在容器中执行如下命令,查看GPU隔离情况。
vgpu-smi
预期输出为:
+------------------------------------------------------------------------------+ | VGPU_SMI 460.91.03 DRIVER_VERSION: 460.91.03 CUDA Version: 11.2 | +-------------------------------------------+----------------------------------+ | GPU Name Bus-Id | Memory-Usage GPU-Util | |===========================================+==================================| | 0 xxxxxxxx 00000000:00:07.0 | 8307MiB / 10782MiB 100% / 100% | +-------------------------------------------+----------------------------------+
预期输出表明,Pod容器被分配了10 GB的显存。
常见问题
如何查看是否已安装共享GPU组件?
执行如下命令,查看是否已安装基于eGPU的共享GPU组件。
kubectl get ds -nkube-system | grep gpushare
预期输出:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
gpushare-egpu-device-plugin-ds 0 0 0 0 0 <none>
gpushare-egpucore-device-plugin-ds 0 0 0 0 0 <none>
预期输出表明,共享GPU组件已安装。