全部产品
Search
文档中心

容器服务 Kubernetes 版 ACK:使用共享GPU调度

更新时间:Jun 17, 2024

本文介绍如何在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共享调度能力

  1. 查找/etc/lingjun_metadata文件是否存在。

    • 如果文件存在,然后执行命令nvidia-smi,如果输出正常,表明该节点为预期开启共享GPU调度能力的灵骏节点,可继续执行下一步。

    • 如果文件不存在,表明预期开启共享GPU调度能力的节点不是灵骏节点,因此此节点无法开启GPU共享调度能力。如果需要开启GPU共享调度能力,请创建灵骏节点。具体操作,请参见灵骏节点池概述

  2. 执行如下命令,通过给节点设置标签ack.node.gpu.schedule为节点开启共享GPU调度能力。

    kubectl label node <NODE_NAME> ack.node.gpu.schedule=share

步骤二:使用GPU共享资源

  1. 使用以下示例创建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
  2. 执行如下命令,提交任务。

    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共享调度能力

  1. 查找/etc/lingjun_metadata文件是否存在。

    • 如果文件存在,然后执行命令nvidia-smi,如果输出正常,表明该节点为预期开启共享GPU调度能力的灵骏节点,可继续执行下一步。

    • 如果文件不存在,表明预期开启共享GPU调度能力的节点不是灵骏节点,因此此节点无法开启GPU共享调度能力。如果需要开启GPU共享调度能力,请创建灵骏节点。具体操作,请参见灵骏节点池概述

  2. 执行如下命令,通过给节点设置标签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共享资源

  1. 等待节点将共享GPU的资源上报结束。

  2. 执行如下命令,查看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示例

  1. 使用如下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
  2. 执行如下命令,提交任务。

    kubectl apply -f benchmark.yaml
  3. 等待Pod运行起来后,请使用如下命令进入Pod。

    kubectl exec -ti benchmark-job-xxxx bash
  4. 在容器中执行如下命令,查看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组件已安装。