全部产品
Search
文档中心

容器服务 Kubernetes 版 ACK:使用MPS实现GPU共享调度和显存隔离

更新时间:Nov 26, 2024

共享GPU调度支持通过NVIDIA MPS(Multi-Process Service)作为底层GPU隔离模块,实现多个Pod共享同一张GPU卡,并确保各Pod之间的显存隔离。本文将为您介绍如何启用NVIDIA MPS隔离功能,并将其与共享GPU调度组件集成使用。

背景信息

基于MPI实现CPU核并行化,可以平衡CPU密集型任务之间的资源分配,确保多个计算任务能够同时进行,从而加速整体的计算过程。但当使用CUDA内核加速MPI进程时,每个MPI进程所分配到的工作量可能无法充分利用GPU,导致虽然每个MPI进程运行速度有所提高,但整体GPU的使用效率很低。当单个应用程序发送给GPU的任务量不足,GPU存在闲置资源时,推荐您使用NVIDIA MPS(Multi-Process Service),一种用于在NVIDIA GPU上运行多个CUDA应用程序的技术,适合用于多用户环境或需要同时运行多个小任务的场景,从而提升GPU利用率和应用程序的吞吐量。

MPS允许不同的应用程序在同一个GPU设备上并发执行,以提高集群GPU资源的利用率。MPS通过Client-Server架构来实现了这种功能,确保了二进制兼容性,即您无需对现有的CUDA应用程序进行重大改造。MPS的构成组件如下。

  • Control Daemon Process:负责启动和停止MPS Server,并协调客户端和MPS Server之间的连接,确保客户端能够顺利接入到MPS服务中进行GPU资源的请求和使用。

  • Client Runtime:集成于CUDA驱动程序库内部。开发者无需对CUDA应用程序代码进行重大改造即可使用MPS。当应用程序使用CUDA驱动进行GPU操作时,Client Runtime会自动处理与MPS Server的交互,从而使多个应用程序能够高效、安全地共享GPU。

  • Server Process:接收来自不同客户端的请求,通过高效的调度策略将请求运行在一个GPU设备上,从而实现了客户端之间的并发性。

注意事项

  • 在NVIDIA MPS架构下,MPS Client(您提交的使用MPS功能的GPU应用)需要跟MPS Control Daemon保持交互。一旦MPS Control Daemon重启,这些MPS Client将错误退出。

  • 在本示例中,MPS Control Daemon服务以容器化的方式运行,以DaemonSet的形式在每个GPU节点部署一个MPS Control Daemon Pod,对于MPS Control Daemon Pod说明如下。

    • MPS Control Daemon Pod不能随意删除或重启。删除MPS Control Daemon Pod将会导致节点的GPU应用不可用。您可以通过命令kubectl get po -l app.aliyun.com/name=mps-control-daemon -A查询集群中MPS Control Daemon Pod状态。

    • 容器中运行MPS Control Daemon时,容器需要具有privilegedhostIPChostPID的权限。这可能带来一些潜在风险,请谨慎评估后再决定是否使用该方案。

    • MPS Control Daemon Pod使用priorityClassName: system-node-critical来保证其优先级,以避免节点资源不足时MPS Control Daemon Pod会被终止,继而导致业务程序无法使用。如果在部署MPS Control Daemon组件的过程中遇到节点资源不足的情况,MPS Control Daemon可能会抢占其他优先级较低的业务Pod,导致这些业务Pod被驱逐。请在部署组件前,确保节点CPU、内存等资源充足。

  • 针对纳入K8s集群管理的GPU节点,为业务应用申请和使用GPU资源时,请关注以下注意事项。

    • 请勿直接在节点上运行GPU应用程序。

    • 请勿通过dockerpodmannerdctl等工具命令创建容器并为容器申请GPU资源。例如,执行docker run --gpus alldocker run -e NVIDIA_VISIBLE_DEVICES=all并运行GPU程序。

    • 请勿在Pod YAML的env中直接添加环境变量NVIDIA_VISIBLE_DEVICES=allNVIDIA_VISIBLE_DEVICES=<GPU ID>等,通过容器的环境变量NVIDIA_VISIBLE_DEVICES直接为Pod申请GPU资源,并运行GPU程序。

    • 在Pod YAML中未设置环境变量NVIDIA_VISIBLE_DEVICES,制作Pod所使用的镜像时,请勿将环境变量默认配置为NVIDIA_VISIBLE_DEVICES=all,并运行GPU程序。

    • 请勿在Pod的securityContext中配置privileged: true,并运行GPU程序。

  • 通过以上非标方式为业务应用申请的GPU资源,将存在如下安全隐患。

    • 通过以上方式为业务应用申请的GPU资源,并未在调度器的设备资源账本中统计,有可能造成节点GPU资源的分配情况与调度器设备资源账本中记录的值不一致。调度器仍然会调度某些申请GPU资源的Pod到这个节点上,导致用户业务因为在同一张GPU卡上出现资源争抢(比如GPU显存申请)而运行失败的情况。

    • 非标操作可能引发其他未知问题,例如NVIDIA社区的已知报错

前提条件

已创建ACK集群Pro版,且版本为1.20及以上。具体操作请参见创建ACK托管集群升级集群

操作步骤

步骤一:安装MPS Control Daemon组件

  1. 登录容器服务管理控制台,在左侧导航栏选择市场 > 应用市场

  2. 进入应用市场界面,在搜索框输入ack-mps-control,然后单击搜索到的组件,进入其安装界面。

  3. ack-mps-control安装界面,单击一键部署,选择需要部署组件的集群,然后单击下一步

  4. 创建页面,选择对应Chart版本,然后单击确定完成安装。

    重要

    卸载和升级MPS Control Daemon组件ack-mps-control都会影响节点上已经运行的GPU应用,导致GPU应用错误退出。请在业务低峰期执行这些操作。

步骤二:安装共享GPU组件

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择应用 > 云原生AI套件

  3. 云原生AI套件页面,单击一键部署

  4. 在一键部署云原生AI套件页面,选中调度策略扩展(批量任务调度、GPU共享、GPU拓扑感知)

  5. 云原生AI套件页面最下方,单击部署云原生AI套件

    组件安装成功后,在云原生AI套件页面的组件列表中能看到已安装的共享GPU组件ack-ai-installer

步骤三:开启GPU共享调度能力和显存隔离能力

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择节点管理 > 节点池

  2. 节点池页面,单击创建节点池

  3. 创建节点池页面,设置创建节点池的配置项,然后单击确认配置

    以下为重要配置项的说明,其余配置项的配置方法,请参见创建节点池

    配置项

    说明

    期望节点数

    设置节点池初始节点数量。如无需创建节点,可以填写为0。

    说明

    完成创建节点池后,您还可以在节点池中添加GPU节点。添加GPU节点时,您需要将实例规格架构设置为GPU云服务器。具体操作,请参见添加已有节点创建节点池

    节点标签

    单击节点标签节点标签,设置为ack.node.gpu.schedule,为mps。

    重要

步骤四:安装共享GPU查询工具

  1. 下载kubectl-inspect-cgpu。

    • 如果您使用的是Linux系统,您可以通过以下命令下载kubectl-inspect-cgpu。

      wget http://aliacs-k8s-cn-beijing.oss-cn-beijing.aliyuncs.com/gpushare/kubectl-inspect-cgpu-linux -O /usr/local/bin/kubectl-inspect-cgpu
    • 如果您使用的是macOS系统,您可以通过以下命令下载kubectl-inspect-cgpu。

      wget http://aliacs-k8s-cn-beijing.oss-cn-beijing.aliyuncs.com/gpushare/kubectl-inspect-cgpu-darwin -O /usr/local/bin/kubectl-inspect-cgpu
  2. 执行以下命令,为kubectl-inspect-cgpu添加执行权限。

    chmod +x /usr/local/bin/kubectl-inspect-cgpu
  3. 执行以下命令,查看集群GPU使用情况。

    kubectl inspect cgpu

    预期输出:

    NAME                       IPADDRESS      GPU0(Allocated/Total)  GPU Memory(GiB)
    cn-shanghai.192.168.6.104  192.168.6.104  0/15                   0/15
    ----------------------------------------------------------------------
    Allocated/Total GPU Memory In Cluster:
    0/15 (0%)

步骤五:部署示例应用

  1. 使用如下YAML创建一个示例应用。

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: mps-sample
    spec:
      parallelism: 1
      template:
        metadata:
          labels:
            app: mps-sample
        spec:
          hostIPC: true  # 需要设置的选项,否则Pod会启动失败。
          hostPID: true  # 不需要设置此选项,此处设置只是便于看到使用MPS的效果。
          containers:
          - name: mps-sample
            image: registry.cn-hangzhou.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:
              limits: 
                aliyun.com/gpu-mem: 7  # 为该Pod申请7GiB显存。
            workingDir: /root
          restartPolicy: Never
    说明

    当节点开启MPS能力后,在该节点上运行的GPU应用Pod需要配置hostIPC: true,否则Pod会启动失败。

  2. 等待Pod创建并处于Running状态,使用如下命令查看MPS是否使用。

    kubectl exec -ti mps-sample-xxxxx --  nvidia-smi

    预期输出:

    Tue Nov 12 11:09:35 2024
    +---------------------------------------------------------------------------------------+
    | NVIDIA-SMI 535.161.07             Driver Version: 535.161.07   CUDA Version: 12.2     |
    |-----------------------------------------+----------------------+----------------------+
    | 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 xxxxxxxxxxxxxx           On  | 00000000:00:07.0 Off |                    0 |
    | N/A   37C    P0              56W / 300W |    345MiB / 32768MiB |      0%   E. Process |
    |                                         |                      |                  N/A |
    +-----------------------------------------+----------------------+----------------------+
    
    +---------------------------------------------------------------------------------------+
    | Processes:                                                                            |
    |  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
    |        ID   ID                                                             Usage      |
    |=======================================================================================|
    |    0   N/A  N/A    197792      C   nvidia-cuda-mps-server                       30MiB |
    |    0   N/A  N/A    387820    M+C   python                                      312MiB |
    +---------------------------------------------------------------------------------------+

    可以看到,nvidia-smi命令输出中,mps-server已经启动,在宿主机上的进程号为197792,同时以MPS方式启动了一个进程号为387820的Python程序,说明MPS是正常运行的。