1. 基于k8s的GPU调度方案

1.1. 调度解决方案概述

Kubernetes 原生调度器仅提供基于 GPU 数量的基础调度能力,无法充分利用 GPU 资源。

沐曦提供了多种基于 Kubernetes 的调度解决方案,旨在解决特定场景下的调度需求,提升系统的整体性能和用户体验。 调度解决方案说明及推荐场景参见下表。

调度解决方案

描述

推荐场景

gpu-scheduler
gpu-scheduler 实现了 GPU 资源的拓扑感知调度,确保 GPU 任务高效、均衡地部署到集群节点
  • 任务需要独占 GPU 资源, 且需提高 GPU 任务的性能及集群 GPU 资源利用率

  • 无需安装额外的调度组件

HAMi
HAMi 支持 GPU 资源的共享以提高 GPU资源的利用率,同时也支持了 GPU 资源的拓扑感知调度
  • 期望多个任务可以共享 GPU 资源, 提高 GPU 资源的利用率( sGPU 场景)

  • 同时支持任务独占 GPU 资源

Volcano

Volcano 是基于 Kubernetes 的批任务调度器。
基于 Volcano 的调度扩展机制开发了调度插件以支持超节点任务调度及 GPU 资源的拓扑感知调度
  • 期望使用 Gang 策略等高阶调度策略

  • 期望在以下场景使用:

    • 基于超节点集群( SwitchBox 拓扑形态集群)的超节点任务调度

    • 任务需要独占 GPU 资源,且需提高 GPU 任务的性能及集群 GPU 资源利用率

上述调度解决方案所支持的调度功能特性参见下表。

表 1.1 调度解决方案列表

调度解决方案

GPU 拓扑感知调度

GPU 共享

指定 GPU 调度

超节点调度

gpu-scheduler

×

×

×

HAMi

×

Volcano

×

×

备注

启用 GPU VF 场景下,原生调度器与上述调度方案均可使用,但仅提供基于 GPU 数量的基础调度能力。

用户可根据使用场景及需要的调度功能特性选择对应的调度解决方案。后续章节描述对应的部署流程。

1.2. 准备 GPU Operator 所需的前置资源

无论选择何种调度解决方案,都需要安装 GPU Operator 组件,以下步骤为准备 GPU Operator 的前置资源。

备注

关于 GPU Operator 所依赖的前置资源,参见《曦云系列通用GPU云原生参考手册》中“安装与维护”章节。

  1. 获取安装包

    以 0.13.0 版本为例,从 沐曦软件中心 下载离线安装包 metax-gpu-k8s-package.0.13.0.tar.gz,解压后获取以下文件:

    • metax-k8s-images.0.13.0.run:镜像资源包

    • metax-operator-0.13.0.tgz:Operator Helm Chart

    • metax-gpu-extensions-0.13.0.tgz:Extensions Helm Chart

  2. 准备内核驱动和 MXMACA® SDK 镜像

    GPU Operator 会自动管理节点上的内核驱动及 MXMACA® SDK 的部署与更新,需确保所有工作节点均可正常拉取相关镜像资源。

    内核驱动与 MXMACA® SDK 可从 沐曦软件中心 下载。

    资源包格式:

    • 内核驱动镜像包

      metax-k8s-driver-image.<VERSION>-<ARCH>.run:包含内核态驱动和配套 mx-smi 工具的资源包

    • MXMACA® SDK 镜像包

      随 MXMACA® 的发布包发布,例如 maca-native:<VERSION>-<DISTRO>-<ARCH>.container.xz 或者 maca-c500-container-*.xz

  3. 推送镜像

    # 假设容器仓库服务器域名为 DOMAIN ,用于存放沐曦Kubernetes组件镜像的项目名为 PROJECT。
    # 默认使用docker进行镜像推送
    metax-k8s-images.0.13.0.run push DOMAIN/PROJECT
    # 使用nerdctl进行镜像推送
    metax-k8s-images.0.13.0.run nerdctl push DOMAIN/PROJECT
    

    备注

    • 自 0.13.0 起,该工具支持多种运行时:dockernerdctlctr

    • 若未显式指定,默认使用docker。若主机未安装docker,系统将自动检测可用运行时并执行镜像推送。

    • 若远程registry为http协议registry,push方式参见《曦云系列通用GPU云原生参考手册》“支持”章节。

  4. 推送 Helm Charts

    helm push ./k8s/metax-operator-0.13.0.tgz oci://DOMAIN/PROJECT
    

1.3. 部署 gpu-scheduler 方案

1.3.1. 安装 GPU Operator

  1. 安装 GPU Operator

    以容器镜像仓库地址为 DOMAIN/PROJECT 为例,在 Kubernetes 管理节点执行以下命令安装 GPU Operator 。

    helm install ./k8s/metax-operator-0.13.0.tgz \
      --create-namespace -n metax-operator \
      --generate-name \
      --wait \
      --set registry=DOMAIN/PROJECT \
      --set gpuScheduler.deploy=true
    
  2. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n metax-operator
    NAME                                           READY   STATUS      RESTARTS   AGE
    metax-container-runtime-4lsd7                  1/1     Running     0          31s
    metax-gpu-device-7774b                         1/1     Running     0          31s
    metax-gpu-label-l5tkf                          1/1     Running     0          31s
    metax-gpu-scheduler-69b58895fd-gcgcz           2/2     Running     0          31s
    metax-operator-1755847288-77bfc94568-7wqlh     1/1     Running     0          31s
    ...
    
  3. 检查节点资源

    以 sample-node1 节点为例,在 Kubernetes 管理节点执行以下命令检查节点资源。

    kubectl get node sample-node1 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("metax-tech.com/gpu")))'
    
    # 示例输出
    {
      "metax-tech.com/gpu": "8"
    }
    

1.3.2. 编写任务 YAML

创建 sample.yaml,用户可参考以下示例编写任务文件。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: ubuntu
      image: ubuntu:22.04
      imagePullPolicy: IfNotPresent
      command: ['bash', '-c']
      args: ["sleep infinity"]
      resources:
        limits:
          metax-tech.com/gpu: 2

1.3.3. 提交任务

在 Kubernetes 管理节点执行以下命令提交任务。

kubectl create -f sample.yaml

1.3.4. 检查调度结果

在 Kubernetes 管理节点执行以下命令检查任务的调度节点。

kubectl get pod -owide
NAME                        READY   STATUS      RESTARTS   AGE   NODE
sample-pod                  1/1     Running     0          31s   gpu-node

1.4. 部署 HAMi 方案

1.4.1. 安装 GPU Operator

1.4.1.1. 集群内所有沐曦 GPU 都需启用 GPU 共享功能

  1. 安装 GPU Operator

    以容器镜像仓库地址为 DOMAIN/PROJECT 为例,在 Kubernetes 管理节点执行以下命令安装 GPU Operator 。

    helm install ./k8s/metax-operator-0.13.0.tgz \
      --create-namespace -n metax-operator \
      --generate-name \
      --wait \
      --set registry=DOMAIN/PROJECT \
      --set gpuDevice.sGPUHybridMode=true
    
  2. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n metax-operator
    NAME                                           READY   STATUS      RESTARTS   AGE
    metax-container-runtime-4lsd7                  1/1     Running     0          31s
    metax-gpu-device-7774b                         1/1     Running     0          31s
    metax-gpu-label-l5tkf                          1/1     Running     0          31s
    metax-operator-1755847288-77bfc94568-7wqlh     1/1     Running     0          31s
    ...
    
  3. 检查节点资源

    以 sample-node1 节点为例,在 Kubernetes 管理节点执行以下命令检查节点资源。

    kubectl get node sample-node1 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("metax-tech.com/sgpu")))'
    
    # 示例输出
    {
      "metax-tech.com/sgpu": "16"
    }
    

1.4.1.2. 集群内仅部分节点的沐曦 GPU 需启用 GPU 共享功能

  1. 安装 GPU Operator

    以容器镜像仓库地址为 DOMAIN/PROJECT 为例,在 Kubernetes 管理节点执行以下命令安装 GPU Operator 。

    helm install ./k8s/metax-operator-0.13.0.tgz \
      --create-namespace -n metax-operator \
      --generate-name \
      --wait \
      --set registry=DOMAIN/PROJECT
    
  2. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n metax-operator
    NAME                                           READY   STATUS      RESTARTS   AGE
    metax-container-runtime-4lsd7                  1/1     Running     0          31s
    metax-gpu-device-7774b                         1/1     Running     0          31s
    metax-gpu-label-l5tkf                          1/1     Running     0          31s
    metax-operator-1755847288-77bfc94568-7wqlh     1/1     Running     0          31s
    ...
    
  3. 创建ConfigMap配置

    在 Kubernetes 管理节点执行以下命令创建 ConfigMap 配置集群级别和节点级别的 gpu-device 的运行模式。 配置为 sgpu 模式的节点将启用 GPU 共享功能。

    cat << "EOF" | kubectl apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: metax-device-config
      namespace: metax-operator
    data:
      version: v1
      cluster-config: |
        mode: "native"
      nodes-config: |
        - nodeName: "sample-node1"
          mode: "sgpu"
    EOF
    
  4. 检查节点资源

    以 sample-node1 节点为例,在 Kubernetes 管理节点执行以下命令检查配置为 sgpu 模式的节点资源。

    kubectl get node sample-node1 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("metax-tech.com/sgpu")))'
    
    # 示例输出
    {
      "metax-tech.com/sgpu": "16"
    }
    

1.4.2. 安装 HAMi

备注

HAMi 版本需≥2.6.0。

  1. 安装 HAMi

    在 Kubernetes 管理节点执行以下命令安装 HAMi 。

    helm repo add hami-charts https://project-hami.github.io/HAMi/
    helm install hami hami-charts/hami -n hami --create-namespace
    
  2. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n hami
    NAME                                           READY   STATUS      RESTARTS   AGE
    hami-scheduler-5888f74b95-l8s6p                2/2     Running     0          31s
    

1.4.3. 编写任务 YAML

创建 sample.yaml,用户可参考以下示例编写任务文件。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  schedulerName: hami-scheduler
  containers:
    - name: ubuntu
      image: ubuntu:22.04
      imagePullPolicy: IfNotPresent
      command: ['bash', '-c']
      args: ["sleep infinity"]
      resources:
        limits:
          metax-tech.com/sgpu: 1 # requesting 1 GPU
          metax-tech.com/vcore: 60 # requesting 60% compute of full GPU
          metax-tech.com/vmemory: 4 # requesting 4 GiB device memory of full GPU

1.4.4. 提交任务

在 Kubernetes 管理节点执行以下命令提交任务。

kubectl create -f sample.yaml

1.4.5. 检查调度结果

在 Kubernetes 管理节点执行以下命令检查任务的调度节点。

kubectl get pod -owide
NAME                        READY   STATUS      RESTARTS   AGE   NODE
sample-pod                  1/1     Running     0          31s   sgpu-node

1.5. 部署 Volcano 方案

1.5.1. 安装 GPU Operator

1.5.1.1. 常规 GPU 集群

  1. 安装 GPU Operator

    以容器镜像仓库地址为 DOMAIN/PROJECT 为例,在 Kubernetes 管理节点执行以下命令安装 GPU Operator 。

    helm install ./k8s/metax-operator-0.13.0.tgz \
      --create-namespace -n metax-operator \
      --generate-name \
      --wait \
      --set registry=DOMAIN/PROJECT
    
  2. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n metax-operator
    NAME                                           READY   STATUS      RESTARTS   AGE
    metax-container-runtime-4lsd7                  1/1     Running     0          31s
    metax-gpu-device-7774b                         1/1     Running     0          31s
    metax-gpu-label-l5tkf                          1/1     Running     0          31s
    metax-operator-1755847288-77bfc94568-7wqlh     1/1     Running     0          31s
    ...
    
  3. 检查节点资源

    以 sample-node1 节点为例,在 Kubernetes 管理节点执行以下命令检查节点资源。

    kubectl get node sample-node1 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("metax-tech.com/gpu")))'
    
    # 示例输出
    {
      "metax-tech.com/gpu": "8"
    }
    

1.5.1.2. 超节点集群( SwitchBox 拓扑形态集群)

  1. 获取cluster-manager组件信息

    获取 cluster-manager 组件的服务地址和用户密码。这里以服务地址为 https://127.0.0.1,用户名为 metax ,密码为 test 为例。执行以下命令。

    export CLUSTER_ADDR=https://127.0.0.1
    export CLUSTER_USER=$(echo metax | base64)
    export CLUSTER_PASSWORD=$(echo test | base64)
    
  2. 安装 GPU Operator

    以容器镜像仓库地址为 DOMAIN/PROJECT 为例,执行以下命令安装 GPU Operator 。

    helm install ./k8s/metax-operator-0.13.0.tgz \
      --create-namespace -n metax-operator \
      --generate-name \
      --wait \
      --set registry=DOMAIN/PROJECT \
      --set topoDiscovery.deploy=true \
      --set topoDiscovery.mode=switchbox \
      --set topoDiscovery.master.env[0].name="CLIENT_GO_QPS" \
      --set-string topoDiscovery.master.env[0].value="100" \
      --set topoDiscovery.master.env[1].name="CLIENT_GO_BRUST" \
      --set-string topoDiscovery.master.env[1].value="100" \
      --set topoDiscovery.switchbox.clusterManagerAddress=$CLUSTER_ADDR \
      --set topoDiscovery.switchbox.clusterManagerUser=$CLUSTER_USER \
      --set topoDiscovery.switchbox.clusterManagerPassword=$CLUSTER_PASSWORD
    
  3. 验证安装状态

    在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

    kubectl get pod -n metax-operator
    NAME                                           READY   STATUS      RESTARTS   AGE
    metax-container-runtime-4lsd7                  1/1     Running     0          31s
    metax-gpu-device-7774b                         1/1     Running     0          31s
    metax-gpu-label-l5tkf                          1/1     Running     0          31s
    metax-operator-1755847288-77bfc94568-7wqlh     1/1     Running     0          31s
    metax-topo-master-6f6cdbf65-84lbc              1/1     Running     0          31s
    metax-topo-worker-57g2d                        1/1     Running     0          31s
    ...
    
  4. 检查节点资源

    以 sample-node1 节点为例,在 Kubernetes 管理节点执行以下命令检查节点资源。

    kubectl get node sample-node1 -o json | jq '.status.allocatable | with_entries(select(.key | startswith("metax-tech.com/gpu")))'
    
    # 示例输出
    {
      "metax-tech.com/gpu": "8"
    }
    
  5. 检查超节点集群拓扑

    在 Kubernetes 管理节点执行以下命令检查超节点集群拓扑是否和物理拓扑一致。

    TOPO_MASTER_IP=`kubectl get pod -n metax-gpu -owide | grep topo-master | awk {'print $6'}`
    curl $TOPO_MASTER_IP:9001/node_group
    

    例如在拓扑为两节点组成一个 dragonfly 组,两个 dragonfly 节点组成一个 switchbox 组的集群中,则可看到以下内容。

    [
      {
        "name": "switchbox-sample1",
        "kind": "switchbox",
        "child": [
          {
            "name": "dragonfly-sample1",
            "kind": "dragonfly",
            "child": [
              {
                "name": "node-sample1",
                "kind": "node",
                "status": "Ready"
              },
              {
                "name": "node-sample2",
                "kind": "node",
                "status": "Ready"
              }
            ],
            "status": "Ready"
          },
          {
            "name": "dragonfly-sample2",
            "kind": "dragonfly",
            "child": [
              {
                "name": "node-sample3",
                "kind": "node",
                "status": "Ready"
              },
              {
                "name": "node-sample4",
                "kind": "node",
                "status": "Ready"
              }
            ],
            "status": "Ready"
          }
        ],
        "status": "Ready"
      }
    ]
    

1.5.2. 安装 Volcano

1.5.2.1. 解压 Volcano 离线安装包

Volcano 相关的容器镜像及 Helm Chart 以离线形式发布。 以 0.13.0 版本为例,用户可从 沐曦软件中心 获取离线安装包 volcano-package-0.13.0.tar.gz,并进行解压缩。

mkdir k8s
tar -C k8s -xvzf volcano-package.0.13.0.tar.gz
volcano-images.0.13.0.run
volcano-0.13.0.tgz

1.5.2.2. 推送 Volcano 容器镜像

以容器镜像仓库地址为 DOMAIN/PROJECT 为例,用户可执行以下命令将 Volcano 镜像推送到镜像仓库。

./k8s/volcano-images.0.13.0.run push DOMAIN/PROJECT

备注

当前版本仅支持 Docker 作为容器镜像推送工具,需确保节点已预装 Docker。

1.5.2.3. 安装 Volcano

以容器镜像仓库地址为 DOMAIN/PROJECT 为例,在 Kubernetes 管理节点执行以下命令安装 Volcano 。

helm install volcano volcano-0.13.0.tgz --create-namespace -n volcano \
  --set basic.controller_image_name=DOMAIN/PROJECT/vc-controller-manager \
  --set basic.scheduler_image_name=DOMAIN/PROJECT/vc-scheduler \
  --set basic.admission_image_name=DOMAIN/PROJECT/vc-webhook-manager \
  --wait

1.5.2.4. 检查安装状态

在 Kubernetes 管理节点执行以下命令检查 Pod 是否处于 Running 状态。

kubectl get pod -n volcano
NAME                                   READY   STATUS      RESTARTS   AGE
volcano-admission-67c4564c6-twzdj      1/1     Running     0          31s
volcano-admission-init-mbtnr           0/1     Completed   0          31s
volcano-controllers-568447f669-g844c   1/1     Running     0          31s
volcano-scheduler-76d6458568-sjbbl     1/1     Running     0          31s

1.5.3. 配置 Volcano 调度插件

在 Kubernetes 管理节点执行以下命令更新 Volcano 调度插件配置。

kubectl edit configmaps -n volcano volcano-scheduler-configmap
  • 超节点集群( SwitchBox 拓扑形态集群):添加 gpu-podaffinity 调度插件。

     1apiVersion: v1
     2data:
     3  volcano-scheduler.conf: |
     4    actions: "enqueue, allocate, backfill"
     5    tiers:
     6    - plugins:
     7      - name: priority
     8      - name: gang
     9        enablePreemptable: false
    10      - name: conformance
    11      - name: gpu-podaffinity  # add it to enable gpu-podaffinity plugin
    12    - plugins:
    13      - name: overcommit
    14      - name: drf
    15        enablePreemptable: false
    16      - name: predicates
    17      - name: proportion
    18      - name: nodeorder
    19      - name: binpack
    
  • 常规 GPU 集群:添加 gpu-aware 调度插件。

     1apiVersion: v1
     2data:
     3  volcano-scheduler.conf: |
     4    actions: "enqueue, allocate, backfill"
     5    tiers:
     6    - plugins:
     7      - name: priority
     8      - name: gang
     9        enablePreemptable: false
    10      - name: conformance
    11    - plugins:
    12      - name: overcommit
    13      - name: drf
    14        enablePreemptable: false
    15      - name: predicates
    16      - name: proportion
    17      - name: nodeorder
    18      - name: binpack
    19      - name: gpu-aware       # add it to enable gpu-ware plugin
    20        arguments:            # add it to enable gpu-ware plugin
    21          weight: 1           # add it to enable gpu-ware plugin
    22          loss.weight: 0.5    # add it to enable gpu-ware plugin
    

1.5.4. 编写任务 YAML

  • 超节点集群( SwitchBox 拓扑形态集群):创建 sample.yaml,用户可参考以下示例编写任务文件。

     1apiVersion: batch.volcano.sh/v1alpha1
     2kind: Job
     3metadata:
     4  name: pytorch-demo
     5spec:
     6  schedulerName: volcano
     7  plugins:
     8    pytorch: ["--master=master","--worker=worker","--port=23456"] # Pytorch plugin register
     9  tasks:
    10    - replicas: 1
    11      name: master
    12      policies:
    13        - event: TaskCompleted
    14          action: CompleteJob
    15      template:
    16        metadata:
    17          annotations:
    18            metax-tech.com/gpu-group-size: "64"
    19        spec:
    20          containers:
    21          - image: alpine:3.19
    22            imagePullPolicy: IfNotPresent
    23            name: master
    24            command: ['sh', '-c']
    25            args: ["sleep infinity"]
    26            resources:
    27              limits:
    28                metax-tech.com/gpu: 8
    29          restartPolicy: Never
    30    - replicas: 7
    31      name: worker
    32      template:
    33        spec:
    34          containers:
    35          - image: alpine:3.19
    36            imagePullPolicy: IfNotPresent
    37            name: worker
    38            command: ['sh', '-c']
    39            args: ["sleep infinity"]
    40            resources:
    41              limits:
    42                metax-tech.com/gpu: 8
    
  • 常规 GPU 集群:创建 sample.yaml,用户可参考以下示例编写任务文件。

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
      name: job-demo
    spec:
      minAvailable: 1
      schedulerName: volcano
      policies:
        - event: PodEvicted
          action: RestartJob
      plugins:
        env: []
        ssh: []
        svc: []
      maxRetry: 2
      queue: default
      tasks:
        - replicas: 2
          name: "gpu-vectoradd"
          template:
            spec:
              containers:
                - name: ubuntu
                  image: ubuntu:22.04
                  imagePullPolicy: IfNotPresent
                  command: ['bash', '-c']
                  args: ["sleep 10s"]
                  resources:
                    limits:
                      metax-tech.com/gpu: 2
              restartPolicy: Never
    

1.5.5. 提交任务

在Kubernetes管理节点执行以下命令提交任务。

kubectl create -f sample.yaml

1.5.6. 检查调度结果

在 Kubernetes 管理节点执行以下命令检查任务的调度节点。

kubectl get pod -owide
NAME                         READY   STATUS      RESTARTS   AGE   NODE
sample-pod1                  1/1     Running     0          31s   gpu-node1
sample-pod2                  1/1     Running     0          31s   gpu-node2
...