本文介绍如何在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组件已安装。