開源 vGPU 方案:HAMi,實現細粒度 GPU 切分

vgpu-hami.png

本文主要分享一個開源的 GPU 虛擬化方案:HAMi,包括如何安裝、配置以及使用。
相比于上一篇分享的 TimeSlicing 方案,HAMi 除了 GPU 共享之外還可以實現 GPU core、memory 得限制,保證共享同一 GPU 的各個 Pod 都能拿到足夠的資源。

1.為什么需要 GPU 共享、切分等方案?

開始之前我們先思考一個問題,為什么需要 GPU 共享、切分等方案?

或者說是另外一個問題:明明直接在裸機環境使用,都可以多個進程共享 GPU,怎么到 k8s 環境就不行了

推薦閱讀前面幾篇文章:這兩篇分享了如何在各個環境中使用 GPU,在 k8s 環境則推薦使用 NVIDIA 提供的 gpu-operator 快速部署環境。

GPU 環境搭建指南:如何在裸機、Docker、K8s 等環境中使用 GPU

GPU 環境搭建指南:使用 GPU Operator 加速 Kubernetes GPU 環境搭建

這兩篇則分析了 device-plugin 原理以及在 K8s 中創建一個申請 GPU 的 Pod 后的一些列動作,最終該 Pod 是如何使用到 GPU 的。

Kubernetes教程(二一)—自定義資源支持:K8s Device Plugin 從原理到實現

Kubernetes教程(二二)—在 K8S 中創建 Pod 是如何使用到 GPU 的:device plugin&nvidia-container-toolkit 源碼分析

看完之后,大家應該就大致明白了。

資源感知

首先在 k8s 中資源是和節點綁定的,對于 GPU 資源,我們使用 NVIDIA 提供的 device-plugin 進行感知,并上報到 kube-apiserver,這樣我們就能在 Node 對象上看到對應的資源了。

就像這樣:

root@liqivm:~# k 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。

資源申請

然后我們就可以在創建 Pod 時申請對應的資源了,比如申請一個 GPU:

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

apply 該 yaml 之后,kube-scheduler 在調度該 Pod 時就會將其調度到一個擁有足夠 GPU 資源的 Node 上。

同時該 Pod 申請的部分資源也會標記為已使用,不會在分配給其他 Pod。

到這里,問題的答案就已經很明顯的。

  • 1)device-plugin 感知到節點上的物理 GPU 數量,上報到 kube-apiserver
  • 2)kube-scheduler 調度 Pod 時會根據 pod 中的 Request 消耗對應資源

即:Node 上的 GPU 資源被 Pod 申請之后,在 k8s 中就被標記為已消耗了,后續創建的 Pod 會因為資源不夠導致無法調度

實際上:可能 GPU 性能比較好,可以支持多個 Pod 共同使用,但是因為 k8s 中的調度限制導致多個 Pod 無法正常共享。

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

上一篇文章一文搞懂 GPU 共享方案: NVIDIA Time Slicing 中給大家分享了一個 GPU 共享方案。

可以實現多個 Pod 共享同一個 GPU,但是存在一個問題:Pod 之間并未做任何隔離,每個 Pod 能用到多少 GPU core、memory 都靠競爭,可能會導致部分 Pod 占用大部分資源導致其他 Pod 無法正常使用的情況。

今天給大家分享一個開源的 vGPU 方案 HAMi。

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

2. 什么是 HAMi?

HAMi 全稱是:Heterogeneous AI Computing Virtualization Middleware,HAMi 給自己的定位或者希望是做一個異構算力虛擬化平臺。

原 第四范式 k8s-vgpu-scheduler, 這次改名 HAMi 同時也將核心的 vCUDA 庫 libvgpu.so 也開源了。

但是現在比較完善的是對 NVIDIA GPU 的 vGPU 方案,因此我們可以簡單認為他就是一個 vGPU 方案。

整體架構如下:

hami-arch.png

可以看到組件還是比較多的,設計到 Webhook、Scheduler、Device Plugin、HAMi-Core 等等。

這篇文章只講使用,因此架構、原理就一筆帶過,后續也會有相關文章,歡迎關注~。

Feature

使用 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% 的算力

相比于上文分享了 TimeSlicing 方案,HAMi 則是實現了 GPU core 和 memory 的隔離。

在開源方案里面已經算是比較優秀的了。

Design

HAMi 實現GPU core 和 memory 隔離、限制是使用的 vCUDA 方案,具體設計如下:

hami-core-design.png

大部分使用 GPU 的應用都是用的 CUDA,HAMi 也是用的 vCUDA 方案,對 NVIDIA 原生的 CUDA 驅動進行重寫,然后掛載到 Pod 中進行替換,然后在自己的實現的 CUDA 驅動中對 API 進行攔截,使用資源隔離以及限制的效果。

例如:原生 CUDA 驅動進行內存分配,只有在 GPU 內存真的用完的時候才會提示 CUDA OOM,但是對于 HAMi CUDA 驅動來說,檢測到 Pod 中使用的內存超過了 Resource 中的申請量就直接返回 OOM,從而實現資源的一個限制。

然后在執行 nvidia-smi 命令查看 GPU 信息時,也只返回 Pod Resource 中申請的資源,這樣在查看時也進行隔離。

ps:需要對 CUDA 和 NVML 的部分 API 攔截。

3. HAMi 部署

HAMi 提供了 Helm Chart 安裝也是比較簡單的。

部署 GPU Operator

需要注意的是 HAMi 會依賴 NVIDIA 的那一套,因此推薦先部署 GPU-Operator。

參考這篇文章 --> GPU 環境搭建指南:使用 GPU Operator 加速 Kubernetes GPU 環境搭建

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

部署 HAMi

首先使用 helm 添加我們的 repo

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

隨后,使用下列指令獲取集群服務端版本

這里使用的是 v1.27.4 版本

kubectl version

在安裝過程中須根據集群服務端版本(上一條指令的結果)指定調度器鏡像版本,例如集群服務端版本為 v1.27.4,則可以使用如下指令進行安裝

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

通過kubectl get pods指令看到 vgpu-device-pluginvgpu-scheduler 兩個pod 狀態為Running 即為安裝成功

root@iZj6c5dnq07p1ic04ei9vwZ:~# 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

自定義配置

官方文檔:HAMi-config-cn.md

你可以在安裝過程中,通過-set來修改以下的客制化參數,例如:

helm install vgpu vgpu-charts/vgpu --set devicePlugin.deviceMemoryScaling=5 ...
  • 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"為不會

我們只是簡單 Demo 就不做任何配置直接部署即可。

4. 驗證

查看 Node GPU 資源

類似于上一篇分享的 TimeSlicing 方案,在安裝之后,Node 上可見的 GPU 資源也是增加了。

環境中只有一個物理 GPU,但是 HAMi 默認會擴容 10 倍,理論上現在 Node 上能查看到 1*10 = 10 個 GPU。

默認參數就是切分為 10 個,可以設置。

$ kubectl get node xxx -oyaml|grep capacity -A 7capacity:cpu: "4"ephemeral-storage: 206043828Kihugepages-1Gi: "0"hugepages-2Mi: "0"memory: 15349120Kinvidia.com/gpu: "10"pods: "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,那么它們可以利用節點上所有可用的資源。

完整 gpu-test.yaml 內容如下:

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%實際顯卡的算力 (可選,整數類型)

Pod 能夠正常啟動

root@iZj6c5dnq07p1ic04ei9vwZ:~# kubectl get po
NAME      READY   STATUS    RESTARTS   AGE
gpu-pod   1/1     Running   0          48s

進入 Pod執行 nvidia-smi 命令,查看 GPU 信息,可以看到展示的限制就是 Resource 中申請的 3000M。

root@iZj6c5dnq07p1ic04ei9vwZ:~# kubectl exec -it gpu-pod -- bash
root@gpu-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

**【Kubernetes 系列】**持續更新中,搜索公眾號【探索云原生】訂閱,文章。


5. 小結

本文主要分享了開源 vGPU 方案 HAMi,并通過簡單 Demo 進行了驗證。

為什么需要 GPU 共享、切分?

在 k8s 中使用默認 device plugin 時,GPU 資源和物理 GPU 是一一對應的,導致一個物理 GPU 被一個 Pod 申請后,其他 Pod 就無法使用了。

為了提高資源利用率,因此我們需要 GPU 共享、切分等方案。

HAMi 大致實現原理

通過替換容器中的 libvgpu.so 庫,實現 CUDA API 攔截,最終實現對 GPU core 和 memory 的隔離和限制。

更加詳細的原理分析,可以期待后續文章~

最后在貼一下相關文章,推薦閱讀:

  • GPU 環境搭建指南:如何在裸機、Docker、K8s 等環境中使用 GPU

  • GPU 環境搭建指南:使用 GPU Operator 加速 Kubernetes GPU 環境搭建

  • Kubernetes教程(二一)—自定義資源支持:K8s Device Plugin 從原理到實現

  • Kubernetes教程(二二)—在 K8S 中創建 Pod 是如何使用到 GPU 的:device plugin&nvidia-container-toolkit 源碼分析

  • 一文搞懂 GPU 共享方案: NVIDIA Time Slicing

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86503.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86503.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86503.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PlayDiffusion上線:AI語音編輯進入“無痕時代”

在語音合成與語音編輯領域,一個長期存在的挑戰是如何在修改語音內容的同時,保持原始語音的自然性、連貫性和說話人特征。近日,一款名為 PlayDiffusion 的新型 AI 語音修復模型應運而生,成功實現了這一目標。 PlayDiffusion 是一個…

2025年能源電力系統與流體力學國際會議 (EPSFD 2025)

2025年能源電力系統與流體力學國際會議(EPSFD 2025)將于本年度在美麗的杭州盛大召開。作為全球能源、電力系統以及流體力學領域的頂級盛會,EPSFD 2025旨在為來自世界各地的科學家、工程師和研究人員提供一個展示最新研究成果、分享實踐經驗及…

微信小程序前端面經

一、技術棧與編碼能力(10min) 1. Vue 3 & Composition API Q1:請解釋一下 ref 和 reactive 的區別?你在項目中是如何使用的? 答:ref是包裝一個原始值或對象,通過.value訪問,r…

rknn toolkit2搭建和推理

安裝Miniconda Miniconda - Anaconda Miniconda 選擇一個 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh進行安裝 下面配置一下載源 # 清華大學源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…

WordPress插件:AI多語言寫作與智能配圖、免費AI模型、SEO文章生成

厭倦手動寫WordPress文章?AI自動生成,效率提升10倍! 支持多語言、自動配圖、定時發布,讓內容創作更輕松! AI內容生成 → 不想每天寫文章?AI一鍵生成高質量內容!多語言支持 → 跨境電商必備&am…

Houdini POP入門學習07 - 分組

使用PopGroup可對粒子進行分組操作,并通過表達式從而更靈活的處理粒子行為。 1.創建box作為發射器,連接popnet節點。 2.雙擊進入popnet,添加popwind添加向上風力。現在播放粒子可見粒子向上方移動。 3.添加popgroup進行分組,開啟…

機器學習復習3--模型評估

誤差與過擬合 我們將學習器對樣本的實際預測結果與樣本的真實值之間的差異稱為:誤差(error)。 誤差定義: ①在訓練集上的誤差稱為訓練誤差(training error)或經驗誤差(empirical error&#x…

Docker 鏡像上傳到 AWS ECR:從構建到推送的全流程

一、在 EC2 實例中安裝 Docker(適用于 Amazon Linux 2) 步驟 1:連接到 EC2 實例 ssh -i your-key.pem ec2-useryour-ec2-public-ip步驟 2:安裝 Docker sudo yum update -y sudo amazon-linux-extras enable docker sudo yum in…

MobileNet 改進:基于MobileNetV2和SSPP的圖像分類

1.創新點分析 在計算機視覺領域,高效的圖像分類模型一直是研究熱點。 本文將詳細解析一個結合了MobileNetV2和空間金字塔池化(SSPP)的深度學習模型實現。 模型概述 這個代碼實現了一個輕量級但功能強大的圖像分類器,主要包含兩個核心組件: MobileNetV2作為特征提取器 自定…

Java中List的forEach用法詳解

在 Java 中,List.forEach() 是 Java 8 引入的一種簡潔的遍歷集合元素的方法。它基于函數式編程思想,接受一個 Consumer 函數式接口作為參數,用于對集合中的每個元素執行操作。 基本語法 java 復制 下載 list.forEach(consumer); 使用示…

涂鴉T5AI手搓語音、emoji、otto機器人從入門到實戰

“🤖手搓TuyaAI語音指令 😍秒變表情包大師,讓萌系Otto機器人🔥玩出智能新花樣!開整!” 🤖 Otto機器人 → 直接點明主體 手搓TuyaAI語音 → 強調 自主編程/自定義 語音控制(TuyaAI…

計算機視覺與深度學習 | 基于MATLAB的相機標定

基于MATLAB的相機標定:原理、步驟與代碼實現 相機標定 基于MATLAB的相機標定:原理、步驟與代碼實現MATLAB相機標定完整流程1. 準備工作2. 采集標定圖像3. 導入圖像并檢測角點4. 生成世界坐標5. 執行相機標定6. 分析標定結果7. 應用標定結果校正圖像相機標定關鍵概念相機參數類…

物聯網專業核心課程以及就業方向

物聯網專業作為信息技術與產業應用深度融合的交叉學科,其課程體系覆蓋硬件、軟件、網絡、數據等全鏈條技術,就業方向則隨智能技術普及呈現多元化趨勢。以下是基于最新行業動態與教育實踐的系統分析: 📚 一、物聯網專業核心課程體系…

mac 安裝homebrew (nvm 及git)

mac 安裝nvm 及git 萬惡之源 mac 安裝這些東西離不開Xcode。及homebrew 一、先說安裝git步驟 通用: 方法一:使用 Homebrew 安裝 Git(推薦) 步驟如下:打開終端(Terminal.app) 1.安裝 Homebrew…

vue3 定時器-定義全局方法 vue+ts

1.創建ts文件 路徑&#xff1a;src/utils/timer.ts 完整代碼&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 創建定時器con…

線性代數證明:把行列式的某一行(列)的k倍加到另一行(列),行列式的值不變

線性代數證明 把行列式的某一行&#xff08;列&#xff09;的k倍加到另一行&#xff08;列&#xff09;&#xff0c;行列式的值不變&#xff1a; 注意五角星的位置要用到另一條性質&#xff1a;若行列式的某一行&#xff08;列&#xff09;的元素都是兩數之和&#xff0c;則可以…

webrtc 在線測試, 如何在線拉流測試

1. 如下所示&#xff0c;使用騰訊提供的網頁即可&#xff0c;非常贊&#xff0c;測試直播拉流 webrtc協議 WebRTC Player Demo 2.截圖&#xff1a;

基于Flask前后端分離智慧安防小區系統

基于Flask前后端分離智慧安防小區系統 本項目是一個基于前后端分離架構的智慧安防小區管理系統&#xff0c;采用現代化的技術棧和完善的功能設計&#xff0c;旨在提供一個高效、安全的小區管理解決方案。 技術架構 前端技術棧 基于Vue 3框架開發參考Geeker-Admin項目的基礎…

深入解析 Linux 死鎖:原理、原因及解決方案

深入解析 Linux 死鎖&#xff1a;原理、原因及解決方案 目錄 **深入解析 Linux 死鎖&#xff1a;原理、原因及解決方案**前言&#xff1a;一次凌晨 3 點的 “服務器崩潰”&#xff0c;揭開死鎖的致命性一、死鎖的基礎&#xff1a;資源與競爭的 “導火索”1.1 資源&#xff1a;死…

C學習--內存管理

#靈感# 當計算機執行一個程序時&#xff0c;必須有一種方法來存儲程序本身和運算所得的數據。 總的來講&#xff0c;計算機硬件中任何能夠存儲和檢索信息的部分都是存儲設備。當前運行的程序存放的存儲器稱為主存儲器&#xff08;primary storage&#xff09;&#xff0c;常常…