如何在kubernetes环境中共享GPU
随着人工智能和大模型的快速发展,云上GPU资源共享变得必要,因为它可以降低硬件成本,提升资源利用效率,并满足模型训练和推理对大规模并行计算的需求。
在kubernetes内置的资源调度功能中,GPU调度只能根据“核数”进行调度,但是深度学习等算法程序执行过程中,资源占用比较高的是显存,这样就形成了很多的资源浪费。
目前的GPU资源共享方案有两种。一种是将一个真正的GPU分解为多个虚拟GPU,即vGPU,这样就可以基于vGPU的数量进行调度;另一种是根据GPU的显存进行调度。
本文将讲述如何安装kubernetes组件实现根据GPU显存调度资源。
系统信息
- 系统:centos stream8 
- 内核:4.18.0-490.el8.x86_64 
- 驱动:NVIDIA-Linux-x86_64-470.182.03 
- docker:20.10.24 
- kubernetes版本:1.24.0 
1. 驱动安装
请登录nvida官网自行安装:https://www.nvidia.com/Download/index.aspx?lang=en-us
2. docker安装
请自行安装docker或其他容器运行时,如果使用其他容器运行时,第三步配置请参考NVIDA官网 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installation-guide
注意:官方支持docker、containerd、podman,但本文档只验证过docker的使用,如果使用其他容器运行时,请注意差异性。
3. NVIDIA Container Toolkit 安装
- 设置仓库与GPG Key
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
- 开始安装
sudo dnf clean expire-cache --refresh
sudo dnf install -y nvidia-container-toolkit
- 修改docker配置文件添加容器运行时实现
sudo nvidia-ctk runtime configure --runtime=docker
- 修改/etc/docker/daemon.json,设置nvidia为默认容器运行时(必需)
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
- 重启docker并开始验证是否生效
sudo systemctl restart docker
sudo docker run --rm --runtime=nvidia --gpus all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi
如果返回如下数据,说明配置成功
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.51.06    Driver Version: 450.51.06    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| 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 T4            On   | 00000000:00:1E.0 Off |                    0 |
| N/A   34C    P8     9W /  70W |      0MiB / 15109MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
4. 安装K8S GPU调度器
- 首先执行以下yaml,部署调度器
# rbac.yaml
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: gpushare-schd-extender
rules:
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - update
      - patch
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - bindings
      - pods/binding
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - get
      - list
      - watch
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gpushare-schd-extender
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: gpushare-schd-extender
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: gpushare-schd-extender
subjects:
  - kind: ServiceAccount
    name: gpushare-schd-extender
    namespace: kube-system
# deployment yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: gpushare-schd-extender
  namespace: kube-system
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: gpushare
      component: gpushare-schd-extender
  template:
    metadata:
      labels:
        app: gpushare
        component: gpushare-schd-extender
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
    spec:
      hostNetwork: true
      tolerations:
        - effect: NoSchedule
          operator: Exists
          key: node-role.kubernetes.io/master
        - effect: NoSchedule
          key: node-role.kubernetes.io/control-plane
          operator: Exists
        - effect: NoSchedule
          operator: Exists
          key: node.cloudprovider.kubernetes.io/uninitialized
      nodeSelector:
        node-role.kubernetes.io/control-plane: ""
      serviceAccount: gpushare-schd-extender
      containers:
        - name: gpushare-schd-extender
          image: registry.cn-hangzhou.aliyuncs.com/acs/k8s-gpushare-schd-extender:1.11-d170d8a
          env:
            - name: LOG_LEVEL
              value: debug
            - name: PORT
              value: "12345"
# service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: gpushare-schd-extender
  namespace: kube-system
  labels:
    app: gpushare
    component: gpushare-schd-extender
spec:
  type: NodePort
  ports:
    - port: 12345
      name: http
      targetPort: 12345
      nodePort: 32766
  selector:
    # select app=ingress-nginx pods
    app: gpushare
    component: gpushare-schd-extender
- 在/etc/kubernetes目录下添加调度策略配置文件
#scheduler-policy-config.yaml
---
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: /etc/kubernetes/scheduler.conf
extenders:
    # 不知道为什么不支持svc的方式调用,必须用nodeport
  - urlPrefix: "http://gpushare-schd-extender.kube-system:12345/gpushare-scheduler"
    filterVerb: filter
    bindVerb: bind
    enableHTTPS: false
    nodeCacheCapable: true
    managedResources:
      - name: aliyun.com/gpu-mem
        ignoredByScheduler: false
    ignorable: false
上面的 http://gpushare-schd-extender.kube-system:12345 注意要替换为你本地部署的{nodeIP}:{gpushare-schd-extender的nodeport端口},否则会访问不到
查询命令如下:
kubectl get service gpushare-schd-extender -n kube-system -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}'
- 修改kubernetes调度配置 /etc/kubernetes/manifests/kube-scheduler.yaml
1. 在commond中添加
 - --config=/etc/kubernetes/scheduler-policy-config.yaml
2. 添加pod挂载目录
在volumeMounts:中添加
- mountPath: /etc/kubernetes/scheduler-policy-config.yaml
  name: scheduler-policy-config
  readOnly: true
在volumes:中添加
- hostPath:
      path: /etc/kubernetes/scheduler-policy-config.yaml
      type: FileOrCreate
  name: scheduler-policy-config
注意:这里千万不要改错,否则可能会出现莫名其妙的错误
示例如下:


- 配置rbac及安装device插件
kubectl create -f https://raw.githubusercontent.com/AliyunContainerService/gpushare-device-plugin/master/device-plugin-rbac.yaml
kubectl create -f https://raw.githubusercontent.com/AliyunContainerService/gpushare-device-plugin/master/device-plugin-ds.yaml
5. 在GPU节点上添加标签
kubectl label node <target_node> gpushare=true
6. 安装kubectl Gpu 插件
cd /usr/bin/
wget https://github.com/AliyunContainerService/gpushare-device-plugin/releases/download/v0.3.0/kubectl-inspect-gpushare
chmod u+x /usr/bin/kubectl-inspect-gpushare
7. 验证
- 使用kubectl查询GPU资源使用情况
# kubectl inspect gpushare
NAME                                IPADDRESS     GPU0(Allocated/Total)  GPU Memory(GiB)
cn-shanghai.i-uf61h64dz1tmlob9hmtb  192.168.0.71  6/15                   6/15
cn-shanghai.i-uf61h64dz1tmlob9hmtc  192.168.0.70  3/15                   3/15
------------------------------------------------------------------------------
Allocated/Total GPU Memory In Cluster:
9/30 (30%)
- 创建一个有GPU需求的资源,查看其资源调度情况
apiVersion: apps/v1
kind: Deployment
metadata:
  name: binpack-1
  labels:
    app: binpack-1
spec:
  replicas: 1
  selector: # define how the deployment finds the pods it manages
    matchLabels:
      app: binpack-1
  template: # define the pods specifications
    metadata:
      labels:
        app: binpack-1
    spec:
      tolerations:
        - effect: NoSchedule
          key: cloudClusterNo
          operator: Exists
      containers:
        - name: binpack-1
          image: cheyang/gpu-player:v2
          resources:
            limits:
              # 单位GiB
              aliyun.com/gpu-mem: 3
8. 问题排查
如果在安装过程中发现资源未安装成功,可以通过pod查看日志
kubectl get po -n kube-system -o=wide | grep gpushare-device
kubecl logs -n kube-system <pod_name>
参考地址:
NVIDA官网container-toolkit安装文档: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker
阿里云GPU插件安装:https://github.com/AliyunContainerService/gpushare-scheduler-extender/blob/master/docs/install.md
如何在kubernetes环境中共享GPU的更多相关文章
- 业务零影响!如何在Online环境中巧用MySQL传统复制技术【转】
		业务零影响!如何在Online环境中巧用MySQL传统复制技术 这篇文章我并不会介绍如何部署一个MySQL复制环境或keepalived+双主环境,因为此类安装搭建的文章已经很多,大家也很熟悉.在这篇 ... 
- 如何在windows环境中搭建apache+subversion(ZT)
		我一直有一个想法就是在本机上象scm一样的搭建一个subversion服务器,然后每天写完代码的时候提交一下,这种感觉好好哦,之前我在windows环境中搭建过纯subversion的服务器兴奋过一阵 ... 
- (23/24) webpack实战技巧:如何在webpack环境中使用Json
		在webpack1或者webpack2版本中,若想在webpack环境中加载Json文件,则需要加载一个json-loader的loader进来的.但是在webpack3.x版本中,则不需要在另外引入 ... 
- JDK 9 发布仅数月,为何在生产环境中却频遭嫌弃?
		千呼万唤始出来,在经历了整整一年的跳票之后,Java 9 终于在 9 月 21 日拨开云雾,露出真正的面目.对众多 Java 程序员来说,这一天无疑是一个重大的日子,首先 Java 开发者们再也不用羡 ... 
- (转)如何在maven环境中设置JVM参数
		有时候我们需要设定maven环境下的JVM参数,以便通过maven执行的命令或启动的系统能得到它们需要的参数设定.比如:当我们使用jetty:run启动jetty服务器时,在进行热部署时会经常发生:J ... 
- 如何在virtualenv环境中安装指定的python版本
		指定python版本:virtualenv -p python执行文件路径 自定义虚拟环境名称.如果文件路径有空格,用引号. 如果不指定python版本,则默认使用环境变量中的python ... 
- conda常用命令,如何在conda环境中安装gym库?
		查看已安装的环境: conda info -e 或 conda env list 创建新环境gymlab: conda create -n gymlab python=3.5 激活环境gymlab: ... 
- openstack镜像如何在vmware 环境中运行
		1.云镜像文件下载地址: http://sahara-files.mirantis.com/sahara-juno-spark-1.0.0-ubuntu-14.04.qcow2(安装有sahara-s ... 
- helm在kubernetes环境中搭建
		1.安装helm 1.1.安装helm客户端 各个版本的helm:https://github.com/helm/helm/releases wget https://get.helm.sh/helm ... 
- 如何在spring环境中做单元测试
		在测试类的上方加入以下注解 @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:spring.xm ... 
随机推荐
- 一个专为量化投资开发的强化学习算法框架:ElegantRL
			链接: https://github.com/AI4Finance-Foundation/ElegantRL 这是一个专为量化投资开发的强化学习算法框架. 相关论文: ElegantRL-Podrac ... 
- Apache DolphinScheduler 3.2.2 版本正式发布!
			Apache DolphinScheduler 3.2.2 版本正式发布! 近日,Apache DolphinScheduler 发布了 3.2.2 版本.此版本主要基于 3.2.1 版本进行了 bu ... 
- springboot2集成oauth2坑二(The bean 'scopedTarget.oauth2ClientContext', defined in class path resource )
			码云地址:https://gitee.com/lpxs/lp-springcloud.git 有问题可以多沟通:136358344@qq.com. 由于使用Enableoauth2sso注解一直报错, ... 
- Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
			Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程 Xorbits Inference (Xinference) 是一个开源平台,用 ... 
- 手把手教Linux驱动10-platform总线详解
			platform总线是学习linux驱动必须要掌握的一个知识点. 本文参考已发布:Linux 3.14内核 一.概念 嵌入式系统中有很多的物理总线:I2c.SPI.USB.uart.PCIE.APB. ... 
- k8s pvc扩容
			#查看是否支持扩容 $ kubectl get sc ** -o yaml ··· allowVolumeExpansion: true #拥有该字段表示允许动态扩容 ··· #找到需要扩容的pvc ... 
- C++技能树
- PG数据库导致断电/重启无法正常启动问题排查
			PG数据库导致断电/重启无法正常启动问题排查 一.问题 数据库断电后,启动PG数据库后无法正常启动,报"psql: could not connect to server: No such ... 
- java_GUI
			package GUi;import java.awt.*;import static java.awt.Color.red;public class GuI { public static void ... 
- echarts x轴下绘制表
			效果图: 把下面代码复制到官网实例的js代码编辑中即可预览( 附连接:Examples - Apache ECharts) let map = { 销售单价: [2200.0,4000.9,700.0 ... 
