本文主要分享一个开源的 GPU 虚拟化方案:HAMi,包括如何安装、配置以及使用。

相比于上一篇分享的 TimeSlicing 方案,HAMi 除了 GPU 共享之外还可以实现 GPU core、memory 的限制,保证共享同一 GPU 的各个 Pod 都能拿到足够的资源。

本文主要对开源的 vGPU 方案 HAMi 的 GPU Core&Memory 隔离功能进行测试。

为什么需要 GPU 共享、切分等方案?

开始之前我们先思考一个问题,为什么需要 GPU 共享、切分等方案?

或者说是另外一个问题:明明直接在裸机环境使用,都可以多个进程共享 GPU,怎么到 k8s 环境就不行了。

推荐阅读前面几篇文章:这两篇分享了如何在各个环境中使用 GPU,在 k8s 环境则推荐使用 NVIDIA 提供的 gpu-operator 快速部署环境。

K8S项目实践(08): 在ECS、Docker、K8s 等环境中使用 GPU

K8S项目实践(09): 使用 GPU Operator搭建AI算力环境

这两篇则分析了 device-plugin 原理以及在 K8s 中创建一个申请 GPU 的 Pod 后的一些列动作,最终该 Pod 是如何使用到 GPU 的。

K8S项目实践(10): device-plugin原理到实现

K8S项目实践(11): Pod 是如何使用到 GPU 的及源码分析

看完之后,大家应该就大致明白了。

资源感知

首先在 k8s 中资源是和节点绑定的,对于 GPU 资源,我们使用 NVIDIA 提供的 device-plugin 进行感知,并上报到 kube-apiserver,这样我们就能在 Node 对象上看到对应的资源了。

就像这样:

[root@k8s-master1 ~]# kubectl  describe node k8s-worker1 | grep Capacity: -A8
Capacity:
  cpu:                   4
  ephemeral-storage:     123460788Ki
  hugepages-1Gi:         0
  hugepages-2Mi:         0
  lixueduan.com/gopher:  2
  memory:                9922140Ki
  nvidia.com/gpu:        1
  pods:                  110
[root@k8s-master1 ~]# 

可以看到,该节点除了基础的 cpu、memory 之外,还有一个nvidia.com/gpu: 1 信息,表示该节点上有 1 个 GPU。

资源申请

然后我们就可以在创建 Pod 时申请对应的资源了,比如申请一个 GPU:

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  containers:
  - name: cuda-vectoradd
    image: "nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2"
    resources:
      limits:
        nvidia.com/gpu: 1
    command: ["nvidia-smi"]

apply 该 yaml 之后,kube-scheduler 在调度该 Pod 时就会将其调度到一个拥有足够 GPU 资源的 Node 上。

同时该 Pod 申请的部分资源也会标记为已使用,不会再分配给其他 Pod。

picture 0

到这里,问题的答案就已经很明显的。

  • 1)device-plugin 感知到节点上的物理 GPU 数量,上报到 kube-apiserver
  • 2)kube-scheduler 调度 Pod 时会根据 pod 中的 Request 消耗对应资源 即:Node 上的 GPU 资源被 Pod 申请之后,在 k8s 中就被标记为已消耗了,后续创建的 Pod 会因为资源不够导致无法调度。

实际上:可能 GPU 性能比较好,可以支持多个 Pod 共同使用,但是因为 k8s 中的调度限制导致多个 Pod 无法正常共享。

因此,我们才需要 GPU 共享、切分等方案。

上一篇文章K8S项目实践(12): GPU共享方案Time Slicing中给大家分享了一个 GPU 共享方案。

可以实现多个 Pod 共享同一个 GPU,但是存在一个问题:Pod 之间并未做任何隔离,每个 Pod 能用到多少 GPU core、memory 都靠竞争,可能会导致部分 Pod 占用大部分资源导致其他 Pod 无法正常使用的情况。

今天给大家分享一个开源的 vGPU 方案 HAMi。

ps:NVIDIA 也有自己的 vGPU 方案,但是需要 license

什么是 HAMi?

HAMi 全称是:Heterogeneous AI Computing Virtualization Middleware,HAMi 给自己的定位或者希望是做一个异构算力虚拟化平台。

原 第四范式 k8s-vgpu-scheduler, 这次改名 HAMi 同时也将核心的 vCUDA 库 libvgpu.so 也开源了。

但是现在比较完善的是对 NVIDIA GPU 的 vGPU 方案,因此我们可以简单认为他就是一个 vGPU 方案。

整体架构如下:

picture 1

可以看到组件还是比较多的,涉及到 Webhook、Scheduler、Device Plugin、HAMi-Core 等等。

这篇文章只讲使用,因此架构、原理就一笔带过,后续也会有相关文章,欢迎关注~。

特性

使用 HAMi 最大的一个功能点就是可以实现 GPU 的细粒度的隔离,可以对 core 和 memory 使用 1% 级别的隔离。

具体如下:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu:18.04
      command: ["bash", "-c", "sleep 86400"]
      resources:
        limits:
          nvidia.com/gpu: 1 # 请求1个vGPUs
          nvidia.com/gpumem: 3000 # 每个vGPU申请3000m显存 (可选,整数类型)
          nvidia.com/gpucores: 30 # 每个vGPU的算力为30%实际显卡的算力 (可选,整数类型)
  • nvidia.com/gpu:请求一个 GPU
  • nvidia.com/gpumem:只申请使用 3000M GPU Memory
  • nvidia.com/gpucores:申请使用 30% 的 GPU core,也就是该 Pod 只能使用到 30% 的算力 相比于上文分享了 TimeSlicing 方案,HAMi 则是实现了 GPU core 和 memory 的隔离。

在开源方案里面已经算是比较优秀的了。

特性

HAMi 实现GPU core 和 memory 隔离、限制是使用的 vCUDA 方案,具体设计如下: picture 2

HAMi 使用的是软件层面的 vCUDA 方案,对 NVIDIA 原生的 CUDA 驱动进行重写(libvgpu.so),然后挂载到 Pod 中进行替换,然后在自己的实现的 CUDA 驱动中对 API 进行拦截,实现资源隔离以及限制的效果。

例如:原生 libvgpu.so 在进行内存分配时,只有在 GPU 内存真的用完的时候才会提示 CUDA OOM,但是对于 HAMi 实现的 libvgpu.so 来说,检测到 Pod 中使用的内存超过了 Resource 中的申请量就直接返回 OOM,从而实现资源的一个限制。

然后在执行 nvidia-smi 命令查看 GPU 信息时,也只返回 Pod Resource 中申请的资源,这样在查看时也进行隔离。

ps:需要对 CUDA 和 NVML 的部分 API 拦截。

HAMi 部署

HAMi 提供了 Helm Chart 安装也是比较简单的。

部署 GPU Operator

需要注意的是 HAMi 会依赖 NVIDIA 的那一套,因此推荐先部署 GPU-Operator。

参考这篇文章 –> K8S项目实践(09): 使用 GPU Operator搭建AI算力环境

部署好 GPU Operator 之后在部署 HAMi。

准备镜像

crictl pull ghcr.io/stackhpc/kube-webhook-certgen:v1.1.1

ctr -n k8s.io image tag  ghcr.io/stackhpc/kube-webhook-certgen:v1.1.1  liangjw/kube-webhook-certgen:v1.1.1

部署 HAMi

首先使用 helm 添加我们的 repo

helm repo add hami-charts https://project-hami.github.io/HAMi/

随后,使用下列指令获取集群服务端版本 > 这里使用的是 v1.28.15版本

kubectl version

在安装过程中须根据集群服务端版本(上一条指令的结果)指定调度器镜像版本,例如集群服务端版本为 v1.28.5,则可以使用如下指令进行安装

helm install hami hami-charts/hami --set scheduler.kubeScheduler.imageTag=v1.28.5 -n kube-system

通过kubectl get pods指令看到 vgpu-device-plugin 与 vgpu-scheduler 两个pod 状态为Running 即为安装成功

微信扫一扫

作者:mospan
微信关注:墨斯潘園
本文出处:http://mospany.github.io/2024/02/05/hami-vgpu-split/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。