当前位置: 首页 > news >正文

HAMi 源码阅读笔记 01:HAMi调度简介

一、HAMi概览

HAMi(异构 AI 计算虚拟化中间件)是一个用于管理 Kubernetes 集群中异构 AI 计算设备的开源平台。在传统 Kubernetes Device Plugin 扩展资源模型下,GPU 通常按整数设备数量暴露给调度器,扩展资源不能像 CPU、Memory 一样天然支持细粒度拆分和超卖;HAMi 通过 MutatingWebhook、Scheduler Extender、Device Plugin 和容器内 HAMi-Core 协作,实现 GPU 显存、算力维度的细粒度声明、调度与限制。 HAMi 让你能像切蛋糕一样把一块 GPU 分给多个 Pod 用。

HAMi的整体架构设计如下图所示。

二、HAMi四个核心组件

可以把HAMi 拆成 4 个逻辑组件:
1)HAMi MutatingWebhook
2)HAMi scheduler-extender
3)HAMi-device-plugin
4)HAMi-Core

2.1 HAMi MutatingWebhook

用户提交 Pod 到 kube-apiserver。MutatingWebhook 扫描 Pod 的资源声明,判断这个 Pod 是否用了 HAMi 管理的资源。如果发现 Pod 申请了 HAMi 管理的 GPU 虚拟化资源(如 nvidia.com/gpumem 等),则将 Pod 的 spec.schedulerName 改写为 hami-scheduler ,交由 HAMi 调度器处理。

2.2 HAMi scheduler-extender

kube-scheduler 在调度过程中调用 extender 的 /filter 和 /bind。/filter 负责根据 Node annotations 里的设备信息、Pod 的 GPU/显存/算力诉求、节点/卡级别的 binpack 或 spread 策略,筛出并选出目标节点与目标设备,并将对应的信息写入到annotations中。

在 HAMi 当前实现中,设备选择和分配结果 annotation 主要在/filter阶段完成;/bind负责进入绑定阶段后的节点锁定、绑定状态 annotation patch,以及调用 Kubernetes API 创建 Binding,把 Pod 绑定到目标节点。

2.3 HAMi-device-plugin

HAMi-device-plugin以 DaemonSet 形式在每个 GPU 节点运行。启动时,它向 Kubelet 报告“虚拟”GPU 资源(将 1 块物理 GPU 虚报为 N 个逻辑 GPU),并将每块 GPU 的详细规格(UUID、显存大小、算力、拓扑等)写入 Node Annotation 中。

在 Pod 启动前(Allocate 阶段),Device Plugin 从 Pod 注解中读取 Scheduler 选定的设备列表,依次挂载对应的 nvidia* 设备文件,并以 hostPath 方式把 libvgpu.so (HAMi-Core 库)和配置文件挂载进容器,同时注入环境变量,完成设备映射和软隔离设置。

2.4 HAMi-Core

作为动态链接库注入容器,同时拦截 CUDA Runtime API (如 `cudaMalloc`) 和 Driver API (如 `cuMemAlloc`)。当应用发起 CUDA API 调用(如申请显存、查询显卡信息)时,请求首先被 `hami-core` 截获。应用以为在跟 NVIDIA 驱动对话,实际上是在跟 HAMi 对话。

用户程序

libvgpu.so(hami-core)

libcuda.so(真实驱动)

nvidia.ko

GPU

三、HAMi调度侧的三个核心入口

3.1 /webhook

HAMi的 webhook 不是调度器真正做节点选择的地方,它是Kubernetes Admission 阶段的一个Mutating Webhook。它的核心作用是:当kube‑apiserver 创建 Pod 时,HAMI webhook 检查这个Pod是否请求了HAMI管理的设备资源;如果请求了,就调用各设备后端的MutateAdmission(...) 修改 Pod,并在必要时把 pod.spec.schedulerName 改成 HAMI 的调度器名称。

3.2 /filter

在 kube-scheduler 调度流程中,当有 Pod 待调度且指定使用 HAMi 调度器时, Kube-scheduler 会触发对 Extender 的 /filter 调用。HAMi 的 /filter 接口会接收当前待调度的 Pod 及所有节点列表,逐节点判断其是否满足 Pod 的资源需求。判断依据主要来自每个节点上的 Node Annotation(由 Device Plugin 更新)中记录的 GPU 规格和已用情况。一般逻辑包括:检查该节点上是否存在可用显存和算力满足 Pod 申请(例如 已分配显存 + 本次请求 ≤ 总显存 ),根据配置的 Binpack 或 Spread 策略选择首选节点等 。

3.3 /bind

/bind负责进入绑定阶段后的确认操作。HAMi 会对目标节点执行锁定,给 Pod 标记bind-phase=allocating,然后通过 Kubernetes API 创建 Binding 对象,把 Pod 绑定到/filter已经选出的目标节点。

四、Pod从创建到绑定的完整链路

综合以上各环节,Pod 从创建到最终运行的完整流程可以总结如下。

4.1 Pod 创建请求提交

用户首先提交一个需要 GPU/vGPU 资源的 Pod 到 Kubernetes API Server。

例如 Pod 中声明了如下资源:

resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 1024

这里的含义是:该 Pod 希望申请 1 个 HAMi 管理的 GPU 分配单位,并申请 1024 MiB 的显存资源。


4.2 Admission Webhook 检查

Pod 创建请求进入 kube-apiserver 后,在真正写入 etcd 之前,kube-apiserver 会调用 HAMi 的 MutatingWebhook,也就是 HAMi 的/webhook接口。

Webhook 会检查这个 Pod 是否申请了 HAMi 管理的 GPU/vGPU 资源。

如果发现 Pod 使用了 HAMi 管理的资源,Webhook 会对 Pod 进行修改,最关键的修改是将:

spec.schedulerName

改为:

hami-scheduler

这样这个 Pod 后续就不会走默认调度器逻辑,而是交给配置了 HAMi Scheduler Extender 的调度器处理。

需要注意的是,/webhook阶段不负责选择节点,也不负责选择 GPU 设备。它只是判断这个 Pod 是否需要进入 HAMi 调度流程。


4.3 kube-scheduler 调用 HAMi/filter

由于 Pod 的schedulerName已经被设置为hami-scheduler,所以 kube-scheduler 在调度这个 Pod 时,会调用 HAMi Scheduler Extender 的/filter接口。

HAMi 的/filter会根据 Pod 的资源请求,结合每个节点上的设备信息进行判断。

这些设备信息主要来自 Node Annotation,通常是由 HAMi Device Plugin 写入的,例如节点上有哪些 GPU、每张 GPU 的 UUID、总显存、总算力、健康状态、已经使用了多少显存和算力等。

/filter阶段,HAMi 会完成以下事情:

1. 解析 Pod 申请的 GPU / 显存 / 算力资源 2. 读取各个节点的 GPU 设备信息 3. 统计当前节点和设备的已使用资源 4. 判断哪些节点、哪些 GPU 能满足 Pod 的请求 5. 根据 binpack 或 spread 策略进行打分 6. 选出目标节点和目标 GPU 设备 7. 将分配结果写入 Pod Annotation 8. 返回目标节点给 kube-scheduler

所以更准确地说,HAMi 的/filter不只是“过滤节点”,它还会完成节点选择、设备选择和分配结果 annotation 写入。


4.4 HAMi/bind完成 Pod 绑定

/filter返回目标节点后,kube-scheduler 会继续调用 HAMi Scheduler Extender 的/bind接口。

/bind的主要作用是将 Pod 绑定到/filter选出的目标节点上。

在这个阶段,HAMi 会执行一些绑定前后的处理,例如:

1. 对目标节点加锁,避免并发调度冲突 2. 给 Pod 标记 bind-phase=allocating 3. 创建 Kubernetes Binding 对象 4. 将 Pod 绑定到目标 Node

Binding 成功后,Pod 的spec.nodeName就会被设置为目标节点。此时,调度阶段基本结束,Pod 会进入目标节点,由该节点上的 kubelet 负责后续容器创建流程。

需要注意:在 HAMi 当前实现中,具体 GPU UUID 的选择和分配 annotation 主要是在/filter阶段完成的,而不是等到/bind阶段才开始选择 GPU。


4.5 kubelet 调用 HAMi Device Plugin 执行 Allocate

Pod 被绑定到目标节点后,目标节点上的 kubelet 会开始创建 Pod 中的容器。

由于这个 Pod 申请了 HAMi 管理的 GPU 资源,所以 kubelet 会调用该节点上的 HAMi Device Plugin,执行Allocate操作。

Device Plugin 会读取 Pod Annotation 中的分配结果,知道这个 Pod 被分配到了哪张 GPU、分配了多少显存、多少算力。

然后 Device Plugin 会为容器注入运行所需的设备和配置,主要包括:

1. 挂载对应的 NVIDIA 设备文件,例如 /dev/nvidia* 2. 挂载 HAMi-Core 的 libvgpu.so 3. 挂载相关配置文件 4. 注入显存限制环境变量 5. 注入算力限制环境变量

这个阶段可以理解为:调度器已经决定“用哪张卡”,而 Device Plugin 负责在容器启动前把这张卡和相关限制真正注入进去。


4.6 容器启动,HAMi-Core 生效

容器启动后,HAMi-Core 的核心库libvgpu.so会被加载到容器进程中。

当用户程序在容器中调用 CUDA 相关接口时,例如申请显存、查询显卡信息、提交 GPU 计算任务,请求会先被libvgpu.so拦截。

整体调用链可以理解为:

用户程序 ↓ CUDA Runtime API / CUDA Driver API ↓ libvgpu.so ↓ 真实的 NVIDIA 驱动库 libcuda.so ↓ nvidia.ko 内核驱动 ↓ 物理 GPU

HAMi-Core 会根据 Device Plugin 注入的环境变量和配置,对容器可使用的 GPU 显存和算力进行限制。

例如,当容器申请的显存超过 HAMi 分配给它的额度时,HAMi-Core 可以让 CUDA 调用返回 OOM;当容器的 GPU 使用超过设定算力比例时,HAMi-Core 可以通过控制 kernel launch 的节奏来限制其使用量。


4.7 最终效果

经过以上流程后,用户程序仍然像正常 CUDA 程序一样运行,不需要修改业务代码。

但是从底层来看,HAMi 已经完成了以下工作:

1. Webhook 负责识别 Pod 是否需要 HAMi 调度 2. Scheduler Extender 负责选择节点和 GPU 设备 3. Device Plugin 负责将设备和限制配置注入容器 4. HAMi-Core 负责在容器内拦截 CUDA 调用并限制资源使用

最终效果是:多个 Pod 可以共享同一块物理 GPU,并且每个 Pod 只能使用自己被分配到的显存和算力额度。

本人运维小白,欢迎大佬批评指正。

http://www.rkmt.cn/news/1496672.html

相关文章:

  • 金融行业常用哪些数据分析模型?风控、授信、客户分层框架汇总
  • 基础知识(从零开始学C语言)
  • Tcl语言:file命令的使用方式
  • 【MATLAB】基于模型预测控制的车辆圆轨迹跟踪方法研究
  • ngx_signal_worker_processes
  • 北京看守所律师事务所:驻所法律服务与常规代理有何本质区别? - 品牌2026
  • 丽水缙云县黄金回收指南:避开陷阱,多拿上千元 - 专业黄金回收
  • 细说KISS、YAGNI原则
  • 论文精读:基于GIS与地理探测器的西南喀斯特石漠化空间分布及驱动因子分析
  • 制造业领域:2026年值得关注的手推式/驾驶式/全自动工业扫地机制造商 - 企业推荐官【官方】
  • 2026义乌UV双喷服务机构整理推荐 - 奔跑123
  • 通诚无忧-通辽信息港信息平台运营策略:打造用户喜爱的通辽市本地服务社区
  • Playwright视觉比较(图片比对测试)
  • 第76篇 | HarmonyOS 保险箱详情页:私密照片如何浏览、恢复和导出
  • Kotlin单表达式函数在安卓开发中的精简艺术
  • 手把手教你用MATLAB复现圆柱绕流POD分解:从Brunton的代码到自己的流场图
  • AgentWatch MCP 服务说明文档
  • 基于 LlamaIndex + DeepSeek + Streamlit 搭建智能问答系统
  • 2026最新渭南市黄金回收价格一览表 回收避坑攻略靠谱商家推荐 - 余生黄金回收
  • UVM源码探秘:start_item的sequencer参数怎么用?解锁更灵活的sequence驱动方式
  • 10kV配网故障识别:波形分析全攻略
  • 【国产电脑python编译器配置】麒麟V10系统anaconda配置pycharm
  • 人工智能专业术语详解(I)
  • Vue3自定义指令实战:从拖拽到权限按钮,3个真实项目案例手把手教学
  • STM32F4实战:5分钟搞定CANopen快速SDO通信,读取节点数据就这么简单
  • 云南大学考研辅导班正规机构,全维度榜单推荐 - 推荐评测师
  • 弹窗交互:AlertDialog与CustomDialog的创建与关闭(11)
  • 【提示词工程】提示词工程笔记:从核心思想到实战代码
  • Got timeout reading communication packets解决方法
  • 微信投票小程序怎么用丨图文视频投票制作全过程(海投票实时更新) - 微信投票小程序