Skip to main content

1. HAMi项目概述

HAMi整体架构

HAMi (Heterogeneous AI Computing Virtualization Middleware) 是开源的 vGPU与调度系统 https://project-hami.io/ ,目标是为Kubernetes环境下的深度学习/推理任务提供细粒度、灵活的GPU资源管理能力。其思路是:在Kubernetes调度层与GPU driver层能力之间,建立一个智能的中间层,用统一的接口和策略提供给用户。这样,用户提交任务时不需要关心底层细节,只需要声明需要多少GPU算力/显存,HAMi就能动态分配、隔离并调度。

项目信息

核心特性

  • ✅ 显存隔离
  • ✅ 算力配额限制
  • Kubernetes原生集成
  • ✅ 多GPU厂商支持(NVIDIAAMD、昇腾等)
  • ✅ 完善的监控和可观测性
  • ✅ 零侵入,应用无需修改

支持的设备

生产商制造商类型内存隔离核心隔离多卡支持
GPUNVIDIA全部
GPUiluvatar全部
GPUMthreadsMTT S4000
GPUMetaxMXC500
MLUCambricon370, 590
DCUHygonZ100, Z100L
AscendHuawei910B, 910B3, 310P
GCUEnflameS60
XPUKunlunxinP800
DPUTeco检查中进行中进行中

2. HAMi的优势与局限

维度优势 ✅局限 ⚠️
隔离性• 显存隔离,防止OOM相互影响
• 进程崩溃不影响其他容器
• 资源配额强制执行
• 算力隔离较弱,仅能软限制
• 无法像MIG那样硬件级隔离
• 恶意进程可能超出配额
性能• 大规模计算场景影响较小
• 相比内核态方案开销更低
API劫持带来5-15%性能损失
• 小batch推理场景影响较大
易用性Kubernetes原生集成
• 无缝集成K8S调度器
• 支持标准资源请求语法
• 完善的监控和可观测性
API劫持可能影响调试工具
• 错误信息可能不够直观
• 需要理解vGPU机制
兼容性• 多GPU厂商支持(NVIDIAAMD、昇腾等)
• 易于扩展支持新硬件
• 零侵入,应用无需修改
• 某些使用CUDA IPC的应用不兼容
• 直接调用Driver API的应用可能绕过
• 需要针对CUDA版本适配
开源与社区Apache 2.0协议
• 社区活跃,持续更新
• 无版权风险
CNCF沙箱项目
• 相比商业方案技术支持有限
• 部分高级特性需要社区贡献

3. HAMi版本限制

3.1 兼容的CUDA版本

CUDA版本范围支持状态说明
CUDA 9.0+✅ 支持早期版本支持
CUDA 10.x✅ 支持完整支持
CUDA 11.0-11.2✅ 支持完整支持
CUDA 11.3+✅ 支持v2.2版本优化了显存计数机制以兼容CUDA 11.3+编译的任务
CUDA 11.6+✅ 支持v1.1.0.0版本更新以兼容CUDA 11.6Driver 500+
CUDA 12.x✅ 支持完整支持,包括CUDA 12.0-12.6

3.2 NVIDIA驱动版本要求

  • 最低驱动版本>= 440
  • 推荐驱动版本>= 500 (更好的兼容性)
  • 最新驱动版本550+ (完整支持所有特性)

4. HAMi整体架构

HAMi关键组件详解

HAMi采用分层架构设计,由以下四个核心组件协同工作:

  • HAMi Mutating WebhookPod准入控制器,拦截并修改Pod定义
  • HAMi Scheduler Extender:调度器扩展,实现智能GPU资源调度
  • HAMi Device Plugin:设备插件,负责GPU资源注册与分配
  • HAMi Core:容器内运行时库,实现资源隔离与配额控制

3.1 HAMi Mutating Webhook

功能职责

  • 拦截Pod创建请求,检查是否包含GPU资源需求
  • 自动为GPU Pod注入必要的配置和环境变量
  • 设置schedulerNamehami-scheduler,确保由HAMi调度器处理
  • 注入runtimeClassNameLD_PRELOAD等运行时参数

工作流程

  1. Pod提交拦截:当用户提交包含GPU资源请求的Pod时,Webhook首先拦截该请求
  2. 资源字段扫描:检查Pod的资源需求字段,识别是否为HAMi管理的GPU资源
  3. 自动配置注入:为符合条件的Pod自动设置调度器名称和运行时配置
  4. 环境变量预埋:注入LD_PRELOAD等环境变量,为后续的API劫持做准备

3.2 HAMi Scheduler Extender

功能职责

  • 扩展Kubernetes默认调度器,实现GPU资源的智能调度
  • 维护集群级别的GPU资源全局视图
  • 根据显存、算力等多维度资源进行节点筛选和打分
  • 支持拓扑感知、资源碎片优化等高级调度策略

调度策略

  1. Filter阶段

    • 过滤显存不足的节点
    • 过滤算力不足的节点
    • 检查GPU型号匹配性
  2. Score阶段

    • 优先选择资源碎片少的节点
    • 考虑GPU拓扑结构,减少跨卡通信
    • 平衡节点负载,避免资源热点
  3. Bind阶段

    • 确定最优节点并绑定Pod
    • 更新资源分配记录到Pod注解

3.3 HAMi Device Plugin

功能职责

  • 发现节点上的GPU资源并向Kubernetes注册虚拟GPU资源
  • 处理PodGPU资源分配请求
  • 从调度结果的注解字段获取分配信息
  • 将相应的GPU设备映射到容器,并注入配额环境变量

工作流程

  1. 启动阶段

    • 扫描节点GPU资源(型号、显存、数量等)
    • 计算可分配的虚拟GPU数量
    • kubelet注册设备资源
  2. 资源分配阶段

    • 接收kubeletAllocate请求
    • Pod注解中读取调度器分配的GPU信息
    • 生成环境变量(显存限制、算力配额等)
    • 挂载HAMi Core库到容器
    • 返回设备列表和环境变量
  3. 监控阶段

    • 定期更新资源状态
    • 上报GPU使用情况
    • 处理设备异常情况

使用示例

apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-example
spec:
schedulerName: hami-scheduler # 使用HAMi调度器
containers:
- name: training-container
image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
command: ["python", "train.py"]
resources:
limits:
nvidia.com/gpu: 1 # 请求1个GPU
nvidia.com/gpumem: 8000 # 请求8GB显存
nvidia.com/gpucores: 50 # 请求50%算力

3.4 HAMi Core (libvgpu.so)

源码仓库:https://github.com/Project-HAMi/HAMi-core

功能职责

  • 通过LD_PRELOAD机制劫持CUDA Runtime API调用
  • 实现显存配额的硬隔离管理
  • 提供算力使用的软限制功能
  • 收集容器级别的GPU使用统计信息

工作原理

HAMi Core是一个动态链接库(libvgpu.so),通过LD_PRELOAD机制在应用程序启动时被加载。它拦截关键的CUDA API调用,在调用真正的CUDA函数之前进行资源检查和配额控制。

核心拦截API

  • cudaMalloc / cudaFree:显存分配与释放
  • cudaMemcpy / cudaMemcpyAsync:显存拷贝操作
  • cudaLaunchKernel:内核函数启动
  • cudaStreamCreate:流管理

算力限制机制

通过监控kernel启动频率和执行时间,实现算力使用的软限制。当容器的算力使用超过配额时,会延迟后续kernel的启动,从而控制整体算力占用。

5. HAMi原理分析

HAMi原理分析

5.1 Pod调度阶段

Kubernetes集群中,HAMi扩展了Pod的调度与运行流程。整个过程可以分为以下几个阶段:

  1. Pod提交与Mutating Webhook拦截

    当用户提交一个带有GPU资源请求的Pod时,请求首先进入API Server。此时Mutating Webhook会拦截Pod对象,对其中的GPU资源声明进行补全和修正,例如:

    • 自动设置schedulerName=hami-scheduler
    • 注入runtimeClassName=nvidia
    • 为容器补齐必要的GPU资源字段和环境变量

    同时,HAMi还会通过Pod的环境变量和容器启动参数注入 LD_PRELOAD,确保在容器启动后,应用程序会自动加载HAMi Core的动态库。这样,就为后续的GPU调度与运行阶段预埋了“劫持” CUDA API的钩子。

    这样,Pod被标记为交由HAMi Scheduler来处理,而不是默认调度器。

  2. HAMi Scheduler调度

    Pod被送入HAMi Scheduler的调度逻辑:

    • Filter 阶段:解析Pod的资源需求,筛选出满足显存、算力等要求的候选节点。
    • Score 阶段:对候选节点进行多维度打分,包括资源利用率、碎片化程度、拓扑结构等。
    • Bind 阶段:选择最优节点,并将Pod绑定到该节点。

    这一流程保证了Pod能够在合适的GPU上运行,并提高集群整体的利用效率。

  3. HAMi Device Plugin与环境变量注入

    Pod被分配到节点后,HAMi Device Plugin接管了容器与GPU的连接过程。与 NVIDIA官方插件相比,HAMi Device Plugin不仅保留了驱动与API的兼容性,还新增了以下能力:

    • 为容器注入显存、算力、任务优先级等控制参数
    • 挂载HAMi Core库,实现对GPU的虚拟化控制
    • 精细化配置CUDA_MEM_LIMITCUDA_CORE_LIMIT等环境变量,实现资源隔离与共享

    最终,Pod内部的应用感知到的GPU是一个受控的虚拟化GPU,既保证了隔离性,也支持资源共享。

5.2 Pod持续运行阶段

Pod启动后,HAMi Core通过LinuxLD_PRELOAD机制直接“嵌入”到应用进程中。

LD_PRELOADLinux动态链接器的一种功能,允许开发者在运行时指定一个自定义的动态链接库,让它在系统标准库之前被加载。这时程序里调用的函数(比如mallocopen,或者在CUDA应用里调用的cudaMalloc)就会先经过自定义库的实现,从而实现“函数劫持”(interception)。HAMi Core正是利用这一点:它通过 LD_PRELOAD 注入一个定制的库到容器应用中,这个库拦截了关键的CUDA Runtime API(如cudaMalloc)。

关键工作流程如下:

  1. 拦截调用:当应用尝试调用cudaMalloc申请显存时,请求首先会进入HAMi Core的拦截逻辑,而不是直接进入CUDA runtime API
  2. 资源校验HAMi Core会读取Pod下发的GPU配置(例如显存上限),检查本次申请是否超限。
  3. 严格控制:若超出限制,则直接拒绝分配并返回错误码;若合法,则放行并记录分配情况。
  4. 持续监管:所有显存分配和释放都会经过这种拦截校验机制,形成一个完整的Pod级“资源沙盒”。

对比NVIDIA MPS仅能在GPU核心算力(SM)维度做时间片调度不同,HAMi Core能进一步在显存维度上做细粒度隔离。这样即便某个应用因为显存泄漏或异常崩溃,也不会像MPS下那样拖垮同节点的其他应用。

6. HAMi配置说明

参考:https://github.com/Project-HAMi/HAMi/blob/master/docs/config_cn.md

6.1 全局设备配置

全局配置通过hami-scheduler-device ConfigMap进行管理,可以通过以下方式更新:

配置项类型默认值说明
nvidia.deviceSplitCount整数10GPU分割数,每张GPU最多可同时运行的任务数
nvidia.deviceMemoryScaling浮点数1.0显存使用比例,可大于1启用虚拟显存(实验功能)
nvidia.migStrategy字符串noneMIG设备策略:none忽略MIGmixed使用MIG设备
nvidia.disablecorelimit字符串false是否关闭算力限制:true关闭,false启用
nvidia.defaultMem整数0默认显存大小(MB),0表示使用全部显存
nvidia.defaultCores整数0默认算力百分比(0-100),0表示可分配到任意GPU100表示独占
nvidia.defaultGPUNum整数1未指定GPU数量时的默认值
nvidia.resourceCountName字符串nvidia.com/gpuvGPU个数的资源名称
nvidia.resourceMemoryName字符串nvidia.com/gpumemvGPU显存大小的资源名称
nvidia.resourceMemoryPercentageName字符串nvidia.com/gpumem-percentagevGPU显存比例的资源名称
nvidia.resourceCoreName字符串nvidia.com/gpucoresvGPU算力的资源名称
nvidia.resourcePriorityName字符串nvidia.com/priority任务优先级的资源名称

6.2 节点级配置

可以为每个节点配置不同的行为,通过编辑hami-device-plugin ConfigMap

配置项类型默认值说明
name字符串-要配置的节点名称
operatingmode字符串hami-core运行模式:hami-coremig
devicememoryscaling浮点数-节点显存超配率
devicecorescaling浮点数-节点算力超配率
devicesplitcount整数-每个设备允许的任务数
filterdevices.uuid字符串列表-要排除设备的UUID列表
filterdevices.index整数列表-要排除设备的索引列表

6.3 调度策略配置

通过Helm Chart参数配置调度策略:

helm install vgpu vgpu-charts/vgpu --set scheduler.defaultSchedulerPolicy.nodeSchedulerPolicy=binpack
配置项类型默认值说明可选值
scheduler.defaultSchedulerPolicy.nodeSchedulerPolicy字符串binpack节点调度策略:binpack尽量集中,spread尽量分散binpack/spread
scheduler.defaultSchedulerPolicy.gpuSchedulerPolicy字符串spreadGPU调度策略:binpack尽量集中,spread尽量分散binpack/spread

6.4 Pod注解配置

Podmetadata.annotations中指定:

注解类型说明示例值
nvidia.com/use-gpuuuid字符串指定只能使用的GPU UUID列表,使用逗号分隔GPU-AAA,GPU-BBB
nvidia.com/nouse-gpuuuid字符串指定不能使用的GPU UUID列表,使用逗号分隔GPU-AAA,GPU-BBB
nvidia.com/use-gputype字符串指定只能使用的GPU型号,支持多个型号使用逗号分隔A100,V100Tesla V100-PCIE-32GB
nvidia.com/nouse-gputype字符串指定不能使用的GPU型号(黑名单),支持多个型号使用逗号分隔1080,2080NVIDIA A10
hami.io/gpu-scheduler-policy字符串Pod级别的GPU调度策略binpack/spread
hami.io/node-scheduler-policy字符串Pod级别的节点调度策略binpack/spread
nvidia.com/vgpu-mode字符串指定使用的vGPU类型hami-core/mig

使用示例

# 示例1: 指定单个GPU型号
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-single-type
annotations:
nvidia.com/use-gputype: "Tesla V100-PCIE-32GB"
hami.io/gpu-scheduler-policy: "binpack"
spec:
schedulerName: hami-scheduler
containers:
- name: app
image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 8000
---
# 示例2: 指定多个GPU型号(白名单),任务只会调度到A100或V100上
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-multi-type
annotations:
# 使用逗号分隔多个型号
nvidia.com/use-gputype: "NVIDIA-GeForce-RTX-4090,NVIDIA-GeForce-RTX-5090"
hami.io/gpu-scheduler-policy: "binpack"
spec:
schedulerName: hami-scheduler
containers:
- name: app
image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 8000
---
# 示例3: 排除特定GPU型号(黑名单),任务不会调度到1080或2080上
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-blacklist
annotations:
# 使用逗号分隔多个型号
nvidia.com/nouse-gputype: "NVIDIA-H20,NVIDIA-H200"
spec:
schedulerName: hami-scheduler
containers:
- name: app
image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 8000

6.5 容器环境变量配置

在容器的env中指定:

环境变量类型默认值说明可选值
GPU_CORE_UTILIZATION_POLICY字符串default算力限制策略:default默认,force强制限制,disable忽略限制default/force/disable
CUDA_DISABLE_CONTROL布尔false是否屏蔽容器层资源隔离,一般用于调试true/false

使用示例

apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
schedulerName: hami-scheduler
containers:
- name: app
image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
env:
- name: GPU_CORE_UTILIZATION_POLICY
value: "force"
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 8000
nvidia.com/gpucores: 50

7. HAMi With Volcano

Volcano原生支持HAMi vGPU,但需要启用对应的deviceshare 插件,具体配置如下:

kind: ConfigMap
apiVersion: v1
metadata:
name: volcano-scheduler-configmap
namespace: volcano-system
data:
volcano-scheduler.conf: |
actions: "enqueue, allocate, backfill"
tiers:
- plugins:
- name: priority
- name: gang
- name: conformance
- plugins:
- name: drf
- name: deviceshare
arguments:
deviceshare.VGPUEnable: true # 启用 vgpu
- name: predicates
- name: proportion
- name: nodeorder
- name: binpack

同时需要替换NVIDIA Device Pluginhttps://github.com/Project-HAMi/volcano-vgpu-device-plugin ,具体参考:https://project-hami.io/zh/docs/userguide/volcano-vgpu/NVIDIA-GPU/how-to-use-volcano-vgpu

8. 参考资料