外国网站 游戏设定图,最好看免费观看高清大全电影,基础建设的意义,wordpress建英文站前言
为什么需要 GPU 共享、切分等方案#xff1f;
在使用GPU的过程中我们会发现#xff0c;直接在裸机环境使用#xff0c;都可以多个进程共享 GPU#xff0c;怎么到 k8s 环境就不行了#xff1f;
1. 资源感知
在 k8s 中资源是和节点绑定的#xff0c;对于 GPU 资源…前言
为什么需要 GPU 共享、切分等方案
在使用GPU的过程中我们会发现直接在裸机环境使用都可以多个进程共享 GPU怎么到 k8s 环境就不行了
1. 资源感知
在 k8s 中资源是和节点绑定的对于 GPU 资源我们使用 NVIDIA 提供的 device-plugin 进行感知并上报到 kube-apiserver,这样我们就能在 Node 对象上看到对应的资源。
kubectl describe node gpu01|grep Capacity -A 7
Capacity:cpu: 128ephemeral-storage: 879000896Kihugepages-1Gi: 0hugepages-2Mi: 0memory: 1056457696Kinvidia.com/gpu: 8pods: 110
该节点除了基础的 cpu、memory 之外还有一个nvidia.com/gpu: 8 信息表示该节点上有 8 个 GPU 。
2. 资源申请
apiVersion: v1
kind: Pod
metadata:name: gpu-pod
spec:containers:- name: gpu-containerimage: nvidia/cuda:11.0-base # 一个支持 GPU 的镜像resources:limits:nvidia.com/gpu: 1 # 申请 1 个 GPUcommand: [nvidia-smi] # 示例命令显示 GPU 的信息restartPolicy: OnFailure
kube-scheduler 在调度该 Pod 时就会将其调度到一个拥有足够 GPU 资源的 Node 上。同时该 Pod 申请的部分资源也会标记为已使用不会再分配给其他 Pod。
总结一下 1device-plugin 感知到节点上的物理 GPU 数量上报到 kube-apiserver 2kube-scheduler 调度 Pod 时会根据 pod 中的 Request 消耗对应资源 即Node 上的 GPU 资源被 Pod 申请之后在 k8s 中就被标记为已消耗了后续创建的 Pod 会因为资源不够导致无法调度。 实际上可能 GPU 性能比较好可以支持多个 Pod 共同使用但是 k8s 中的调度限制导致多个 Pod 无法正常共享。因此我们才需要 GPU 共享、切分等方案。
什么是 HAMi
https://github.com/Project-HAMi/HAMi
HAMi 全称是Heterogeneous AI Computing Virtualization MiddlewareHAMi 给自己的定位或者希望是做一个异构算力虚拟化平台。原第四范式 k8s-vgpu-scheduler, 这次改名 HAMi 同时也将核心的 vCUDA 库 libvgpu.so 也开源了。但是现在比较完善的是对 NVIDIA GPU 的 vGPU 方案因此我们可以简单认为他就是一个 vGPU 方案。
整体架构 特性
使用 HAMi 最大的一个功能点就是可以实现 GPU 的细粒度的隔离可以对 core 和 memory 使用 1% 级别的隔离。
apiVersion: v1
kind: Pod
metadata:name: gpu-pod
spec:containers:- name: ubuntu-containerimage: ubuntu:18.04command: [bash, -c, sleep 86400]resources:limits:nvidia.com/gpu: 1 # 请求1个vGPUsnvidia.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% 的算力
设计
HAMi 实现 GPU core 和 memory 隔离、限制是使用的 vCUDA 方案 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 中申请的资源这样在查看时也进行隔离。 HAMi 部署
HAMi 提供了 Helm Chart 安装
1. 部署 GPU Operator
HAMi 会依赖 NVIDIA 的那一套因此推荐先部署 GPU-Operator
此处留着补充
部署好 GPU Operator 之后再部署 HAMi。
2. 部署 HAMi
# 添加repo仓库helm repo add hami-charts https://project-hami.github.io/HAMi/# 获取k8s版本kubectl version# 在安装过程中须根据集群服务端版本上一条指令的结果指定调度器镜像版本例如集群服务端版本为 v1.27.4则可以使用如下指令进行安装helm install hami hami-charts/hami --set scheduler.kubeScheduler.imageTagv1.27.4 -n kube-system# 通过 kubectl get pods 指令看到 vgpu-device-plugin 与 vgpu-scheduler 两个 pod 状态为Running 即为安装成功kubectl get pods -n kube-system|grep hami
hami-device-plugin-b6mvj 2/2 Running 0 42s
hami-scheduler-7f5c5ff968-26kjc 2/2 Running 0 42s 3. 自定义配置
官方文档
HAMi-config-cn.md: https://github.com/Project-HAMi/HAMi/blob/master/docs/config_cn.md
在安装过程中通过-set来修改以下的客制化参数例如
helm install vgpu vgpu-charts/vgpu --set devicePlugin.deviceMemoryScaling5 ... devicePlugin.deviceSplitCount整数类型预设值是 10。GPU 的分割数每一张 GPU 都不能分配超过其配置数目的任务。若其配置为 N 的话每个 GPU 上最多可以同时存在 N 个任务。 devicePlugin.deviceMemoryScaling: 浮点数类型预设值是 1。NVIDIA 装置显存使用比例可以大于 1启用虚拟显存实验功能。对于有 M 显存大小的 NVIDIA GPU如果我们配置devicePlugin.deviceMemoryScaling参数为 S 在部署了我们装置插件的 Kubenetes 集群中这张 GPU 分出的 vGPU 将总共包含 S * M 显存。 devicePlugin.migStrategy: 字符串类型目前支持none“与“mixed“两种工作方式前者忽略 MIG 设备后者使用专门的资源名称指定 MIG 设备使用详情请参考 mix_example.yaml默认为none devicePlugin.disablecorelimit: 字符串类型true为关闭算力限制false为启动算力限制默认为false scheduler.defaultMem: 整数类型预设值为 5000表示不配置显存时使用的默认显存大小单位为 MB scheduler.defaultCores: 整数类型(0-100)默认为 0表示默认为每个任务预留的百分比算力。若设置为 0则代表任务可能会被分配到任一满足显存需求的 GPU 中若设置为 100代表该任务独享整张显卡 scheduler.defaultGPUNum: 整数类型默认为 1如果配置为 0则配置不会生效。当用户在 pod 资源中没有设置 nvidia.com/gpu 这个 key 时webhook 会检查 nvidia.com/gpumem、resource-mem-percentage、nvidia.com/gpucores 这三个 key 中的任何一个 key 有值webhook 都会添加 nvidia.com/gpu 键和此默认值到 resources limit 中。 resourceName: 字符串类型, 申请 vgpu 个数的资源名, 默认: nvidia.com/gpu resourceMem: 字符串类型, 申请 vgpu 显存大小资源名, 默认: nvidia.com/gpumem resourceMemPercentage: 字符串类型申请 vgpu 显存比例资源名默认: nvidia.com/gpumem-percentage resourceCores: 字符串类型, 申请 vgpu 算力资源名, 默认: nvidia.com/cores resourcePriority: 字符串类型表示申请任务的任务优先级默认: nvidia.com/priority 除此之外容器中也有对应配置 GPU_CORE_UTILIZATION_POLICY: 字符串类型default, force, disable 代表容器算力限制策略 default为默认force为强制限制算力一般用于测试算力限制的功能disable为忽略算力限制 ACTIVE_OOM_KILLER: 字符串类型true, false 代表容器是否会因为超用显存而被终止执行true为会false为不会 4. 验证
查看 Node GPU 资源
环境中只有一个物理 GPU但是 HAMi 默认会扩容 10 倍理论上现在 Node 上能查看到 1*10 10 个 GPU。 默认参数就是切分为 10 个可以设置 kubectl get node xxx -oyaml|grep capacity -A 7capacity:cpu: 4ephemeral-storage: 206043828Kihugepages-1Gi: 0hugepages-2Mi: 0memory: 15349120Kinvidia.com/gpu: 10pods: 110 验证显存和算力限制 使用以下 yaml 来创建 Pod注意 resources.limit 除了原有的 nvidia.com/gpu 之外还新增了 nvidia.com/gpumem 和 nvidia.com/gpucores用来指定显存大小和算力大小。 nvidia.com/gpu请求的 vgpu 数量例如 1 nvidia.com/gpumem 请求的显存数量例如 3000M nvidia.com/gpumem-percentage显存百分百例如 50 则是请求 50%显存 nvidia.com/priority: 优先级0 为高1 为低默认为 1。 对于高优先级任务如果它们与其他高优先级任务共享 GPU 节点则其资源利用率不会受到 resourceCores 的限制。换句话说如果只有高优先级任务占用 GPU 节点那么它们可以利用节点上所有可用的资源。 对于低优先级任务如果它们是唯一占用 GPU 的任务则其资源利用率也不会受到 resourceCores 的限制。这意味着如果没有其他任务与低优先级任务共享 GPU那么它们可以利用节点上所有可用的资源。 apiVersion: v1
kind: Pod
metadata:name: gpu-pod
spec:containers:- name: ubuntu-containerimage: ubuntu:18.04command: [bash, -c, sleep 86400]resources:limits:nvidia.com/gpu: 1 # 请求1个vGPUsnvidia.com/gpumem: 3000 # 每个vGPU申请3000m显存 可选整数类型nvidia.com/gpucores: 30 # 每个vGPU的算力为30%实际显卡的算力 可选整数类型
kubectl exec -it gpu-pod -- bash
rootgpu-pod:/# nvidia-smi
[HAMI-core Msg(16:139711087368000:libvgpu.c:836)]: Initializing.....
Mon Apr 29 06:22:16 2024
-----------------------------------------------------------------------------------------
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|---------------------------------------------------------------------------------------
| 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:07.0 Off | 0 |
| N/A 33C P8 15W / 70W | 0MiB / 3000MiB | 0% Default |
| | | N/A |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
||
| No running processes found |
-----------------------------------------------------------------------------------------
[HAMI-core Msg(16:139711087368000:multiprocess_memory_limit.c:434)]: Calling exit handler 16
最后的日志就是 HAMi 的 CUDA 驱动打印
[HAMI-core Msg(16:139711087368000:multiprocess_memory_limit.c:434)]: Calling exit handler 16
HAMi 大致实现原理
通过替换容器中的 libvgpu.so 库实现 CUDA API 拦截最终实现对 GPU core 和 memory 的隔离和限制。
参考资料
第四范式 k8s-vgpu-scheduler: https://github.com/4paradigm/k8s-vgpu-scheduler
本文搜集来自开源 vGPU 方案HAMi,实现细粒度 GPU 切分