2. 版本申明

版本 修改内容 修改时间
v1.0 初始化 8/15/2022
v1.1 格式调整 9/1/2022
v1.2 更新一些格式以及内容 4/17/2024
v1.3 更新一些格式以及内容 8/8/2024
v1.4 更新efsmi支持版本 11/8/2024
v1.5 更新一些内容 12/5/2024
v2.0 gcushare调度器升级 2/27/2025
v2.1 gcushare支持GCU资源隔离 3/10/2025
v2.2 调度插件兼容多版k8s 3/26/2025
v2.3 支持多进程DRS调度 5/13/2025

3. 简介

3.1. 背景

Kubernetes基础设施使用GCU设备时,是不支持多个pod共享GCU的,这样可以实现更好的隔离,保证每个应用的GCU使用不受其它应用的影响,非常适合深度学习模型训练。但是对于想要提高集群中GCU利用率的用户来说,这样通常会造成GCU资源的浪费。比如:

  • 作为集群管理员,在开发过程中,允许多个用户在同一个GCU上共享同一个模型开发环境,以增加集群的GCU使用率。

  • 作为一名应用操作员,希望能够同时在同一个GCU上运行多个推理任务。

针对这些场景,就需要实现GCU设备的共享功能,以满足特定场景下的用户需求。

3.2. 查看版本号

1)执行./gcushare-device-plugin --version,即可查看gcushare-device-plugin版本号;

2)执行./gcushare-scheduler-plugin --version, 即可查看gcushare-scheduler-plugin版本号;

3.3. GCUShare主要组件

GCUShare通过gcushare-scheduler-plugin+gcushare-device-plugin这两个组件实现GCU设备的共享。

1)gcushare-scheduler-plugin:共享GCU的自定义调度插件,主要负责根据用户的资源请求(enflame.com/shared-gcu或enflame.com/drs-gcu),计算可调度的节点,并分配GCU设备。

2)gcushare-device-plugin:共享GCU的k8s设备插件,主要负责向kubelet注册enflame.com/shared-gcu和enflame.com/drs-gcu资源,并负责实际的GCU设备分配工作。

3.4. GCUShare功能概要

1)GCUShare支持调度级别的GCU设备共享(申请enflame.com/shared-gcu),也支持共享GCU的资源隔离(申请enflame.com/drs-gcu);

2)共享调度(申请enflame.com/shared-gcu或enflame.com/drs-gcu)和整卡调度(申请enflame.com/gcu)调度的方式不可以在集群内并存;

3)支持GCU掉卡场景以及卡片重新恢复时,集群内可用共享GCU资源的动态更新;

4)GCUShare依赖于enflame gcu driver和enflame gcu container toolkit,部署GCUShare组件前,必须按顺序部署好这两个依赖组件(gcu-operator2.0已支持GCUShare组件和依赖组件的一键部署);

5)GCUShare提供了inspect接口,用户可以访问该接口来查询集群所有共享GCU的使用情况,从而对整体资源的使用有一个初步的判断;

6)GCUShare支持用户在非DRS场景下自定义共享GCU设备的切片数(sliceCount),在DRS场景下当前只支持1切6;

7)通常组件日志都存储在容器中,一旦容器重启或组件卸载,很容易造成日志丢失。GCUShare组件的日志采用本地持久化存储方式,用户可通过日志自行定位问题;

8)GCUShare支持由用户指定部分节点共享GCU以及部分节点使用资源隔离。

3.5. GCUShare Chart说明

Chart 是 Helm 的应用打包格式。gcushare 的 chart 由一系列文件组成,这些文件描述了 Kubernetes 部署gcushare应用时所需要的资源,比如 Service、Deployment、ClusterRole等。chart 将这些文件放置在预定义的目录结构中,便于 Helm 部署。GCUShare chart 的目录结构以及包含的各类文件如下:

gcushare_<VERSION>/
gcushare-device-plugin/deployments/gcushare-device-plugin-chart/
├── Chart.yaml
├── templates
│   ├── clusterrolebinding.yaml
│   ├── clusterrole.yaml
│   ├── daemonset.yaml
│   └── serviceaccount.yaml
└── values.yaml

gcushare-scheduler-plugin/deployments/gcushare-scheduler-plugin-chart/
├── Chart.yaml
├── templates
│   ├── _helpers.tpl
│   ├── clusterrole.yaml
│   ├── clusterrolebinding.yaml
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── service.yaml
│   └── serviceaccount.yaml
└── values.yaml

注意:使用chart部署gcushare,依赖于主机上安装有helm组件。在部署过程中,如果helm不存在,部署脚本将直接使用kubectl命令进行部署。

4. 安装GCUShare组件

安装说明:

  • gcushare-scheduler-plugin组件依赖于gcushare-device-plugin组件,因此需要先安装gcushare-device-plugin组件;

  • 环境提前安装好k8s >= v1.18,docker,helm3,enflame driver,enflame docker等组件。

本手册所使用测试环境安装了单节点k8s集群(version=1.32)。我们称该节点为节点1,下文同。

4.1. 制作gcushare组件镜像

镜像构建工具由"build-image.conf+build-image.sh" 组成,用户可以根据需要修改"build-image.conf"里的内容满足定制化需求, 然后执行 "build-image.sh" 生成容器镜像,基本过程如下:

1)镜像配置文件定制

"build-image.conf"内容如下,用户可以根据实际需要自行完成内容修改:

# Currently supports ubuntu, tlinux, openeuler
OS="ubuntu"

# Currently supports docker, ctr, podman, nerdctl
CLI_NAME="docker"

# The repository name
REPO_NAME="artifact.enflame.cn/enflame_docker_images/enflame"

# The image name
IMAGE_NAME="gcushare-device-plugin"

# The image tag
TAG="latest"

# The namespace used by nerdctl, ctr
NAMESPACE="k8s.io"

2)镜像构建

"build-image.sh" 使用说明如下:

# ./build-image.sh -h
Usage: ./build-image.sh [OPTIONS]...
Description: This script is used to build and save images.

Options:
  --os        Specify the operating system for the image. \
              Currently supports "ubuntu, tlinux and openeuler", default: "ubuntu".
  --cli       Specify the CLI tool for building the image. \
              Currently supports "docker, ctr, podman and nerdctl", default: "docker".
  --repo      Specify the repository for the image that will be built, \
              default: "artifact.enflame.cn/enflame_docker_images/enflame".
  --name      Specify the name of the image that will be built, \
              default: "gcushare-device-plugin".
  --tag       Specify the tag for the image that will be built, default: "latest".
  --namespace Specify the namespace for the image that will be built by \
              nerdctl and ctr, default: "k8s.io".

Examples:
  ./build-image.sh
  ./build-image.sh --cli podman --os ubuntu
  ./build-image.sh --cli nerdctl --os openeuler
  ./build-image.sh --cli ctr --os ubuntu

用户在完成"build-image.conf"里的内容定制化需求后,可以直接执行 "build-image.sh" 生成容器镜像:

# 默认 CLI: docker, OS: ubuntu
./build-image.sh

对于k8s version >=1.24,推荐采用 nerdctl 或 ctr构建:

./build-image.sh --cli nerdctl
或
./build-image.sh --cli ctr

制作gcushare-device-plugin镜像

切换到gcushare-device-plugin安装包目录下,构建镜像:

# 默认 CLI: docker, OS: ubuntu
./build-image.sh

对于k8s version >=1.24,推荐采用 nerdctl 或 ctr构建。

镜像制作成功后,将会自动载入当前节点,并把镜像包保存到images目录下:

gcushare-device-plugin_{VERSION} # docker images|grep gcushare
artifact.enflame.cn/enflame_docker_images/enflame/gcushare-device-plugin   \
latest              8bda9bbd85ea        3 minutes ago       140MB

# ll images/
total 139992
drwxrwxr-x 2 root root      4096 10月 12 16:16 ./
drwxrwxr-x 6 root root      4096 10月 12 15:42 ../
-rw------- 1 root root 143343616 10月 12 16:16 gcushare-device-plugin.tar

也可以指定需要构建的OS镜像,如:

# ubuntu
./build-image.sh --os ubuntu
# tlinux
./build-image.sh --os tlinux

制作gcushare-scheduler-plugin镜像

gcushare-scheduler-plugin使用了kube-scheduler framework技术,该技术在k8s1.24以前还未演进到稳定版本。gcushare调度插件适配了不同版本的k8s,因此在构建镜像时,必须使用version参数来选择gcushare调度插件版本以兼容你的k8s集群。

version参数的可选值:

  • v1: 适用于k8s1.24及以后版本;

  • v1beta1: 适用于k8s1.18,k8s1.20以及k8s1.22版本;

切换到gcushare-scheduler-plugin的安装包目录下,构建镜像:

# 默认 CLI: docker, OS: ubuntu
./build-image.sh --version v1

对于k8s version >=1.24,推荐采用 nerdctl 或 ctr构建。

镜像制作成功后,将会自动载入当前节点,并把镜像包保存到images目录下:

gcushare-scheduler-plugin_{VERSION} # docker images|grep gcushare
artifact.enflame.cn/enflame_docker_images/enflame/gcushare-scheduler-plugin   \
latest              ba7540816cdc        38 seconds ago      130MB
artifact.enflame.cn/enflame_docker_images/enflame/gcushare-device-plugin        \
latest              8bda9bbd85ea        4 minutes ago       140MB

gcushare-scheduler-plugin_{VERSION} # ll images/
total 130400
drwxrwxr-x 2 root root      4096 10月 12 16:21 ./
drwxrwxr-x 5 root root      4096 10月 12 15:41 ../
-rw------- 1 root root 133517824 10月 12 16:21 gcushare-scheduler-plugin.tar

4.2. 安装gcushare组件

安装gcushare-device-plugin

  • gcushare-device-plugin将注册两种资源:enflame.com/shared-gcu和enflame.com/drs-gcu;

  • 修改组件启动时的sliceCount,将作用于enflame.com/shared-gcu资源;

  • gcushare-device-plugin组件安装时,支持用户指定要在哪些节点共享GCU设备。声明使用共享GCU资源的pod只会调度到这些节点上;

在gcushare-device-plugin安装包目录下,执行./deploy.sh一键安装gcushare-device-plugin组件。

gcushare-device-plugin_{VERSION} # ./deploy.sh
Cluster node name list:
[my-cluster-control-plane
my-cluster-control-plane
my-cluster-control-plane2]
Please input gcushare node name and separated by space(if all \
nodes use shared GCU, you can just press Enter):
......

deploy.sh主要做了两件事:

  • 询问并请用户输入需要共享GCU设备的节点名称,并给这些节点自动打上"enflame.com/gcushare": "true"标签。只有打了该标签的节点才会部署gcushare-device-plugin组件;

  • 如果节点安装有helm组件,则使用helm部署gcushare-device-plugin的release;否则使用kubectl直接安装yaml文件。

可以通过查看gcushare-device-plugin的pod信息,来确认gcushare-device-plugin是够运行正常:

gcushare-device-plugin_{VERSION} # kubectl get pod -A
NAMESPACE   NAME                         READY STATUS  RESTARTS AGE
kube-system gcushare-device-plugin-n6c5w 1/1   Running 0        26h
......

再检查下节点的"enflame.com/gcu-count"字段和"enflame.com/shared-gcu"字段是否更新:

gcushare-device-plugin_{VERSION} # kubectl get node
NAME                 STATUS   ROLES                  AGE   VERSION
sse-lab-inspur-048   Ready    control-plane,master   27h   v1.20.0

gcushare-device-plugin_{VERSION} # kubectl describe node sse-lab-inspur-048
......
Capacity:
  cpu:                     80
  enflame.com/drs-gcu:     12            # DRS资源,每张卡仅支持1切6
  enflame.com/gcu-count:   2             # 当前节点有2张GCU卡
  enflame.com/shared-gcu:  12            # 共享资源,每张卡默认支持1切6,可修改启动参数sliceCount进行控制
  ephemeral-storage:       1345603940Ki
  hugepages-1Gi:           0
  hugepages-2Mi:           0
  memory:                  394869612Ki
  pods:                    110
Allocatable:
  cpu:                     80
  enflame.com/drs-gcu:     12
  enflame.com/gcu-count:   2
  enflame.com/shared-gcu:  12
  ephemeral-storage:       1240108589051
  hugepages-1Gi:           0
  hugepages-2Mi:           0
  memory:                  394767212Ki
  pods:                    110

安装gcushare-scheduler-plugin组件

在gcushare-scheduler-plugin安装包目录下,执行./deploy.sh一键安装gcushare-scheduler-plugin组件:

gcushare-scheduler-plugin_{VERSION} # ./deploy.sh

deploy.sh主要做了一件事:

  • 如果节点安装有helm组件,则使用helm部署gcushare-scheduler-plugin的release;否则使用kubectl直接安装yaml文件。

同样的,我们可以通过查询pod确定gcushare-scheduler-plugin运行正常:

gcushare-scheduler-plugin_{VERSION} # kubectl get pod -A
NAMESPACE        NAME                                        \
READY STATUS  RESTARTS AGE
......
kube-system      gcushare-device-plugin-n6c5w                \
1/1   Running 0        26h
kube-system      gcushare-scheduler-plugin-9b57bd745-rxd6r \
1/1   Running 0        26h
......

我们也可以通过简单的接口访问来测试下组件是否能正常提供服务:

# kubectl get svc -A|grep gcushare-scheduler-plugin
kube-system        gcushare-scheduler-plugin       ClusterIP   \
10.96.1.37     <none>        32766/TCP                106s

# curl 10.96.1.37:32766/version
2.0.0

gcushare-scheduler-plugin组件使用service转发访问,端口为32766。访问上述URL,将会返回gcushare-scheduler-plugin版本号信息,说明组件正常运行。

5. 使用共享GCU

注意

  • 申请enflame.com/shared-gcu的pod下文称为gcushare pod;申请enflame.com/drs-gcu的pod下文称为drs pod

  • 申请共享GCU的pod必须明确指定调度器名称为gcushare-scheduler

  • 一个pod内或一个容器内不可以同时申请enflame.com/shared-gcuenflame.com/drs-gcu

  • enflame.com/shared-gcu: 1,表示申请1个共享GCU,实际单位取决于部署gcushare-device-plugin时的共享方式。如果sliceCount=6(默认共享方式),则1表示使用1/6张卡;如果sliceCount=4,则1表示使用1/4张卡。

5.1. inspect脚本

在部署pod申请共享GCU之前,可以先通过inspect脚本来查询节点共享GCU或DRS GCU的使用情况。

# ./inspect.sh -h
Usage: ./inspect.sh <param name> <param value>
Description: This script is used to display the usage of GCU devices.
Param:
    --node      Optional. Query the usage of the GCU device of the specified node, \
                by default, all nodes are queried.
    --drs       Optional. Whether to query the usage of drs GCU, default 'false'
Example:
    ./inspect.sh --node node1 --drs true

5.2. 申请shared GCU场景示例

使用方法:

apiVersion: v1
kind: Pod
metadata:
  name: gcushare-pod-1
  namespace: kube-system
spec:
  schedulerName: gcushare-scheduler # 必须指定调度器名称
  containers:
    - name: pod-gcu-example
      resources:
        limits:
          enflame.com/shared-gcu: 1 # 声明申请一个shared GCU,即1/6张卡

gcushare-scheduler-plugin提供了gcushare pod的示例yaml文件,目录:deployments/example/gcushare-pod.yaml。以下场景的测试文件均为基于该模板修改。

1)部署一个gcushare pod,申请1个shared GCU,pod可以正常运行

example # kubectl create -f gcushare-pod.yaml
pod/gcushare-pod-1 created

example # kubectl get pod -A
NAMESPACE   NAME           READY STATUS  RESTARTS AGE
......
kube-system gcushare-pod-1 1/1   Running 0        4s

可以看到,pod运行正常。然后可以通过kubectl exec命令确认GCU设备是否被成功挂载到容器内:

example # kubectl exec -it gcushare-pod-1 -n kube-system -- ls /dev
core  gcu0vid0  gcu0vid4  gcuctl  pts     stdin            urandom
fd    gcu0vid1  gcu0vid5  mqueue  random  stdout           zero
full  gcu0vid2  gcu0vid6  null    shm     termination-log
gcu0  gcu0vid3  gcu0vid7  ptmx    stderr  tty

可以看到,pod成功挂载了GCU0。

通过inspect.sh可以看到shared gcu的使用情况。输出信息如下所示(为便于注释,这里将输出的json文本转换为了yaml格式):

- name: my-cluster-control-plane    # 节点名称
  totalGCU: 12                      # 当前节点共享GCU总数
  usedGCU: 1                        # 当前节点已经使用的共存GCU总数
  availableGCU: 11                  # 当前节点剩余可用的共存GCU总数
  devices:                          # 每个GCU设备的具体使用信息
    '0':                            # 当前GCU设备的使用情况
      virt: Shared                  # 当前GCU以调度层面共享
      totalGCU: 6                   # 当前GCU可以共享的总数
      usedGCU: 1                    # 当前GCU已经使用的数目
      availableGCU: 5               # 当前GCU剩余可用的数目
      pods:                         # 使用当前GCU的全部pod信息
        - name: gcushare-pod-1
          namespace: kube-system
          uid: 9223275a-2d3f-4e1a-9207-c5576a919f5c
          creationTimestamp: '2025-02-21T02:44:38Z'
          usedGCU: 1
          phase: Running
          containers:
            pod-gcu-example:
              allocated: true
    '1':
      totalGCU: 6
      usedGCU: 0
      availableGCU: 6
      pods: []

2)再部署一个pod,申请1个共享GCU,则该pod将优先使用节点1的GCU0卡。

example # kubectl create -f gcushare-pod-2.yaml
pod/gcushare-pod-2 created

example # kubectl get pod -A
NAMESPACE    NAME             READY STATUS  RESTARTS AGE
......
kube-system  gcushare-pod-1   1/1   Running 0        7s
kube-system  gcushare-pod-2   1/1   Running 0        5s

example # kubectl exec -it gcushare-pod-2 -n kube-system -- ls /dev
core  gcu0vid0  gcu0vid4  gcuctl  pts     stdin            urandom
fd    gcu0vid1  gcu0vid5  mqueue  random  stdout           zero
full  gcu0vid2  gcu0vid6  null    shm     termination-log
gcu0  gcu0vid3  gcu0vid7  ptmx    stderr  tty

可以看到,pod2也成功绑定了GCU0卡。查看节点的GCU使用信息:

gcushare-scheduler-plugin_{VERSION} # ./inspect.sh --node my-cluster-control-plane

输出如下:

{
  "name": "my-cluster-control-plane",
  "totalGCU": 12,
  "usedGCU": 2,
  "availableGCU": 10,
  "devices": {
    "0": {
      "virt": "Shared",
      "totalGCU": 6,
      "usedGCU": 2,
      "availableGCU": 4,
      "pods": [
        {
          "name": "gcushare-pod-1",
          "namespace": "kube-system",
          "uid": "9223275a-2d3f-4e1a-9207-c5576a919f5c",
          "creationTimestamp": "2025-02-21T02:44:38Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        },
        {
          "name": "gcushare-pod-2",
          "namespace": "kube-system",
          "uid": "cec755a6-a074-4b2a-822c-0a16b5479a20",
          "creationTimestamp": "2025-02-21T09:37:01Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        }
      ]
    },
    "1": {
      "totalGCU": 6,
      "usedGCU": 0,
      "availableGCU": 6,
      "pods": []
    }
  }
}

注意:在满足pod申请资源的前提下,gcushare-scheduler-plugin将优先为pod分配剩余可使用共享GCU数目更少的GCU设备。

3)部署第3个pod,申请6个共享GCU,pod将占一张整卡。

example # kubectl create -f gcushare-pod-3.yaml
pod/gcushare-pod-3 created

example # kubectl get pod -A
NAMESPACE    NAME            READY STATUS    RESTARTS  AGE
......
kube-system  gcushare-pod-1  1/1   Running   0         9s
kube-system  gcushare-pod-2  1/1   Running   0         7s
kube-system  gcushare-pod-3  1/1   Running   0         5s

example # kubectl exec -it gcushare-pod-3 -n kube-system -- ls /dev
core  gcu1vid0  gcu1vid4  gcuctl  pts     stdin            urandom
fd    gcu1vid1  gcu1vid5  mqueue  random  stdout           zero
full  gcu1vid2  gcu1vid6  null    shm     termination-log
gcu1  gcu1vid3  gcu1vid7  ptmx    stderr  tty

可以看到pod3使用了GCU1卡。查看节点GCU使用情况:

{
  "name": "my-cluster-control-plane",
  "totalGCU": 12,
  "usedGCU": 8,
  "availableGCU": 4,
  "devices": {
    "0": {
      "virt": "Shared",
      "totalGCU": 6,
      "usedGCU": 2,
      "availableGCU": 4,
      "pods": [
        {
          "name": "gcushare-pod-1",
          "namespace": "kube-system",
          "uid": "9223275a-2d3f-4e1a-9207-c5576a919f5c",
          "creationTimestamp": "2025-02-21T02:44:38Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        },
        {
          "name": "gcushare-pod-2",
          "namespace": "kube-system",
          "uid": "cec755a6-a074-4b2a-822c-0a16b5479a20",
          "creationTimestamp": "2025-02-21T09:37:01Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        }
      ]
    },
    "1": {
      "virt": "Shared",
      "totalGCU": 6,
      "usedGCU": 6,
      "availableGCU": 0,
      "pods": [
        {
          "name": "gcushare-pod-3",
          "namespace": "kube-system",
          "uid": "c6481294-373a-4c7e-89f1-7070e13986b6",
          "creationTimestamp": "2025-02-21T09:58:07Z",
          "usedGCU": 6,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        }
      ]
    }
  }
}

4)部署pod4,使用8个共享GCU,此时pod将无法调度到节点,因为GCUShare限定了单个pod最大可申请的显存数为单张整卡。

example # kubectl create -f gcushare-pod-4.yaml
pod/gcushare-pod-4 created

example # kubectl get pod -A
NAMESPACE    NAME            READY STATUS  RESTARTS AGE
......
kube-system  gcushare-pod-1  1/1   Running 0        11s
kube-system  gcushare-pod-2  1/1   Running 0        9s
kube-system  gcushare-pod-3  1/1   Running 0        7s
kube-system  gcushare-pod-4  0/1   Pending 0        6s

查看pod事件,显示单个GCU卡显存不足。

example # kubectl describe pod gcushare-pod-4 -n kube-system
Name:         gcushare-pod-4
Namespace:    kube-system
......
Events:
  Type     Reason            Age   From                Message
  ----     ------            ----  ----                -------
  Warning  FailedScheduling  15s   gcushare-scheduler  0/1 nodes are available: \
  1 pod(name: gcushare-pod-4, uuid: f8d4ee96-aa37-426d-89dd-4aecfd295e0d) request \
  gcu: 8, but it is insufficient of node: my-cluster-control-plane. preemption: 0/1 \
  nodes are available: 1 No preemption victims found for incoming pod.

5.3. 申请DRS GCU场景示例

使用方法:

apiVersion: v1
kind: Pod
metadata:
  name: gcushare-pod-1
  namespace: kube-system
spec:
  schedulerName: gcushare-scheduler # 必须指定调度器名称
  containers:
    - name: pod-gcu-example
      resources:
        limits:
          enflame.com/drs-gcu: 1 # 声明申请一个共享GCU,即1/6张卡

gcushare-scheduler-plugin提供了drs pod的示例yaml文件,目录:deployments/example/drs-pod.yaml。以下场景的测试文件均为基于该模板修改。

1)部署一个pod,申请1个drs GCU,pod可以正常运行

example # kubectl create -f drs-pod.yaml
pod/drs-pod-1 created

example # kubectl get pod -A
NAMESPACE   NAME           READY STATUS  RESTARTS AGE
......
kube-system drs-pod-1 1/1   Running 0        4s

通过efsmi命令可以查看gcushare为该pod创建的drs实例:

# efsmi
......
+-----------------------------------------------------------------------------+
| GCU instances:                                                              |
|----------------------------------+----------------------------+-------------|
| GCU        Name           ID     | Mem (Usage/Total)          | SIP         |
+----------------------------------+----------------------------+-------------+
|  0         1g.7gb         1      |     0MiB /  7948MiB        | 4           |
+----------------------------------+----------------------------+-------------+

也可以通过inspect.sh查看drs gcu的使用情况:

# ./inspect.sh --drs true --node my-cluster-control-plane

输出如下(为便于注释,这里将输出的json文本转换为了yaml格式):

name: my-cluster-control-plane
totalGCU: 12
usedGCU: 1
availableGCU: 11
devices:
  '0':
    totalGCU: 6
    usedGCU: 0
    availableGCU: 6
    pods: []
  '1':
    virt: DRS
    totalGCU: 6
    usedGCU: 1
    availableGCU: 5
    pods:
      - name: drs-pod-1
        namespace: kube-system
        uid: e1b83d13-0373-4b34-acd4-c34f02538ce0
        creationTimestamp: '2025-05-14T07:00:34Z'
        usedGCU: 1
        phase: Running
        containers:
          pod-gcu-example:
            allocated: true
            request: 1              # pod申请1个DRS GCU
            profileID: '0'          # pod使用的profile ID
            profileName: 1g.7gb     # pod使用的profile name
            instanceID: '1'         # 为pod创建的instance ID

可以看到pod成功申请到了GCU1(注意这里的GCU1是efsmi所看到的GCU0)。

2)部署pod2,申请3个drs GCU,pod可以正常运行

example # kubectl create -f drs-pod-2.yaml
pod/drs-pod-2 created

example # kubectl get pod -A
NAMESPACE   NAME           READY STATUS  RESTARTS AGE
......
kube-system drs-pod-1 1/1   Running 0        20s
kube-system drs-pod-2 1/1   Running 0        4s

查看节点drs gcu的使用情况:

{
  "name": "my-cluster-control-plane",
  "totalGCU": 12,
  "usedGCU": 4,
  "availableGCU": 8,
  "devices": {
    "0": {
      "totalGCU": 6,
      "usedGCU": 0,
      "availableGCU": 6,
      "pods": []
    },
    "1": {
      "virt": "DRS",
      "totalGCU": 6,
      "usedGCU": 4,
      "availableGCU": 2,
      "pods": [
        {
          "name": "drs-pod-1",
          "namespace": "kube-system",
          "uid": "e1b83d13-0373-4b34-acd4-c34f02538ce0",
          "creationTimestamp": "2025-05-14T07:00:34Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true,
              "request": 1,
              "profileID": "0",
              "profileName": "1g.7gb",
              "instanceID": "1"
            }
          }
        },
        {
          "name": "drs-pod-2",
          "namespace": "kube-system",
          "uid": "1b4a1976-0850-496b-a9bc-47ff40a11d09",
          "creationTimestamp": "2025-05-14T07:00:50Z",
          "usedGCU": 3,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true,
              "request": 3,
              "profileID": "1",
              "profileName": "3g.23gb",
              "instanceID": "2"
            }
          }
        }
      ]
    }
  }
}

可以看到pod2也成功申请到了GCU1。

3)部署pod3,申请2个drs GCU,pod无法调度

example # kubectl create -f drs-pod-2.yaml
pod/drs-pod-2 created

example # kubectl get pod -A
NAMESPACE   NAME           READY STATUS  RESTARTS AGE
......
kube-system drs-pod-1 1/1   Running 0        20s
kube-system drs-pod-2 1/1   Running 0        4s
kube-system drs-pod-3 0/1   Pending 0        1s

查看pod事件:

# kubectl describe pod drs-pod-3 -n kube-system
......
Events:
  Type     Reason            Age    From                Message
  ----     ------            ----   ----                -------
  Warning  FailedScheduling  58s    gcushare-scheduler  running \
  "GCUShareSchedulerPlugin" filter plugin: configmap: \
  drs-pod-3.kube-system.db79de52.my-cluster-control-plane.configmap \
  filter node: my-cluster-control-plane for pod(name: drs-pod-3,\
  uuid: db79de52-b004-4796-b629-7d7e9d98e638) failed: configmap:\
  drs-pod-3.kube-system.db79de52.my-cluster-control-plane.configmap\
  pod exit container request: 2g, but the profile associated with it does not exist

可以看到,即使drs gcu资源充足,但不存在支持申请2/6的profile,pod无法调度(当前申请DRS时,仅支持1/6,3/6或6/6)。

5.4. 混合部署模式

gcushare支持既部署gcushare pod,又部署drs pod。即,先部署一个gcushare pod,再部署一个drs pod是允许的。

先部署1个gcushare pod申请1个shared gcu

# kubectl create -f example/gcushare-pod.yaml
pod/gcushare-pod-1 created

# kubectl get pod -A
NAMESPACE    NAME            READY  STATUS   RESTARTS  AGE
kube-system  gcushare-pod-1  1/1    Running  0         2s
......

再部署1个drs pod申请3个shared gcu

# kubectl create -f example/drs-pod.yaml
pod/drs-pod-1 created

# kubectl get pod -A
NAMESPACE    NAME       READY  STATUS   RESTARTS  AGE
kube-system  drs-pod-1  1/1    Running  0         2s
......

查看shared gcu的使用情况:

./inspect.sh --node my-cluster-control-plane
{
  "name": "my-cluster-control-plane",
  "totalGCU": 6,
  "usedGCU": 1,
  "availableGCU": 5,
  "devices": {
    "0": {
      "virt": "Shared",
      "totalGCU": 6,
      "usedGCU": 1,
      "availableGCU": 5,
      "pods": [
        {
          "name": "gcushare-pod-1",
          "namespace": "kube-system",
          "uid": "57ac2683-be74-45fc-9d77-63e9bfe33c76",
          "creationTimestamp": "2025-05-14T07:24:01Z",
          "usedGCU": 1,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true
            }
          }
        }
      ]
    }
  }
}

可以看到gcushare pod占用了GCU0,由于drs pod占用了GCU1,因此GCU1对gcushare pod已不再可用。

可以通过drs参数查看drs gcu的使用情况:

./inspect.sh --node my-cluster-control-plane --drs true
{
  "name": "my-cluster-control-plane",
  "totalGCU": 6,
  "usedGCU": 3,
  "availableGCU": 3,
  "devices": {
    "1": {
      "virt": "DRS",
      "totalGCU": 6,
      "usedGCU": 3,
      "availableGCU": 3,
      "pods": [
        {
          "name": "drs-pod-1",
          "namespace": "kube-system",
          "uid": "1d79daf8-e77a-439b-8f3b-901d09d7b2a7",
          "creationTimestamp": "2025-05-14T07:33:25Z",
          "usedGCU": 3,
          "phase": "Running",
          "containers": {
            "pod-gcu-example": {
              "allocated": true,
              "request": 3,
              "profileID": "1",
              "profileName": "3g.23gb",
              "instanceID": "1"
            }
          }
        }
      ]
    }
  }
}

同样,由于gcushare pod占用了GCU0,因此GCU0对drs pod来说也不再可用。

注意,未被任何pod占用的GCU对drs pod和gcushare pod来说都是可用的,遵循先到先得原则。

5.5. 修改GCU的共享切片数

GCUShare支持用户指定shared gcu的共享切片数。如果你想要将每个GCU切分成4份,那么在安装gcushare-device-plugin组件前,只需要修改gcushare-device-plugin-chart中values文件的sliceCount字段即可:

gcushare-device-plugin_{VERSION} # vim gcushare-device-plugin-chart/values.yaml
# Default values for gcushare-device-plugin-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

sliceCount: 4             # sliceCount表示将单个GCU设备共享为指定份数
...

修改后保存values文件,然后再部署gcushare-device-plugin组件即可生效。使用方式不变:

示例1:

enflame.com/shared-gcu: 1             # 表示申请1/4张卡。

示例2:

enflame.com/shared-gcu: 2             # 表示申请2/4张卡。

注意

  • 该功能仅对shared gcu生效,不支持显存隔离;

  • sliceCount是在部署组件前要确定好的,如果你已经部署成功了gcushare相关组件,那么在运行过程中,请不要再去修改sliceCount字段,否则可能会造成调度异常。

  • 如果在运行过程中一定要修改sliceCount字段,必须先把正在使用shared GCU的pod全部清除,然后重新安装gcushare的两个组件。

5.6. 查看日志

通常组件的运行日志都存放在容器中,这样就容易带来一些问题,一是一旦容器重启或者组件被卸载,会造成日志的丢失;二是难以根据异常信息找到代码的调用栈。这些问题都将增大故障排查的复杂程度,而用户则完全无从下手进行排查,进而大大增大了开发人员的运维负担。而GCUShare提供了日志的本地存储功能,如果你的组件运行异常,或者使用GCUShare出现了问题,都可以通过查看日志,进行初步定位。

日志存放目录:/var/log/enflame/gcushare。

1)查看gcushare-scheduler-plugin组件日志:

/var/log/enflame/gcushare # vim gcushare-scheduler-plugin.log

2)查看gcushare-device-plugin组件日志:

/var/log/enflame/gcushare # vim gcushare-device-plugin.log

6. 组件卸载

通过release目录下delete.sh一键卸载gcushare组件。

6.1. gcushare-scheduler-plugin卸载

gcushare-scheduler-plugin_{VERSION} # ./delete.sh

6.2. gcushare-device-plugin卸载

gcushare-device-plugin_{VERSION} # ./delete.sh

组件卸载后,节点上的"enflame.com/gcushare": "true"标签将自动清除。

注意,如果仍然存在drs pod在运行,将遇到以下提示:

# ./delete.sh
Warning!!! The following pods are found to be using drs instance:

name: drs-pod-1, namespace: kube-system
If you delete these pods after the gcushare device plugin is uninstalled, \
the corresponding drs will not be automatically cleaned up.
It is recommended to delete these pods before uninstalling the gcushare device plugin,\
otherwise the remaining drs cannot be used by gcushare again until you manually \
delete these remaining drs.
Continue uninstalling gcushare device plugin?(y/yes, n/no)

此时,建议输入n/no退出卸载流程,然后先删除所有drs pod后重新卸载gcushare设备插件。因为gcushare设备插件负责drs instance的创建,删除等工作,如果先卸载了gcushare设备插件,然后卸载drs pod时,会残留drs instance无法自动清理,后续再部署drs pod时,会导致资源不足,除非你手动删除残留的drs资源。

7. 常见问题

1)按卡调度和共享调度为什么不可以共存?

整卡调度和共享调度采用的是两个完全没有关联的k8s设备插件。二者有自己的调度逻辑,而且无法感知到对方的调度记录,若同时存在,将造成调度混乱。

2)gcushare如何实现底层的显存分配?

用户部署pod申请drs gcu后,设备插件将向底层runtime传递相应的环境变量,实现底层的隔离。

3)组件卸载后,已经使用共享GCU的pod业务会受影响吗?

  • 卸载gcushare调度插件没有影响;

  • 卸载gcushare设备插件对gcushare pod没有影响;但会影响drs pod,因此卸载gcushare设备插件前请先删除所有drs pod。

4)gcushare组件重启后是否会影响后续的调度?

不会。gcushare调度pod时,可以实时获取到集群上申请共享GCU的pod信息,通常不会出现数据不一致的场景。

5)gcushare支持单个pod内多个容器申请共享GCU吗?

支持,但单个pod内所有申请共享GCU的容器的申请总和不得超过单张GCU卡的内存大小。

6)gcushare在运行过程中,如果掉了一张卡需要重启gcushare吗?或者如果卡片重新恢复了,需要重启gcushare吗?

这两种场景都不需要重启gcushare,gcushare可以自动适应掉卡以及卡片恢复等场景。

7)可以手动创建drs吗?

在使用gcushare的DRS功能时,请不要手动创建DRS,所有GCU设备均应交给gcushare自动化管理,否则可能造成调度混乱。

8. 已知问题

1)在k8s1.22版本中,使用gcushare部署多容器pod申请共享GCU时存在kubelet多调用一次Allocate接口的现象,导致pod容器创建失败。该问题经验证,确认属于k8s1.22版本存在的问题,在k8s其它版本中暂未发现。如果遇到该问题,建议升级k8s到1.24及以上版本。