技术解读
项目背景与痛点
在 Kubernetes 里,GPU 是最昂贵也最难共享的资源。原生 nvidia.com/gpu 扩展资源只能按整卡计数分配:只要 Pod 申请了 1,就独占一整块 A10,A100 或 3090 也是如此。但现实中大量推理服务、Notebook、CI 任务对显存的需求可能只有 2GB,算力占用不到 5%,整卡分配意味着集群里 90% 的 GPU 周期都在闲置。
现有方案各有短板:NVIDIA MIG 提供硬件级隔离,但只支持 A100/H100 等少数高端卡,切分粒度固定(1g.5gb 之类),中低端卡和消费级卡直接无缘;Device Plugin 的 time-slicing 共享能让多个 Pod 轮流使用同一张卡,但显存完全不隔离,一个任务 OOM 会连带整个卡上的进程;至于手动写 CUDA_VISIBLE_DEVICES 做“约定式共享”,则完全没有调度层面的资源账本,多副本并发下必然超卖。
HAMi(原 k8s-vGPU-scheduler)瞄准的正是这个中间地带:不挑硬件、细粒度切分、带显存与算力二维隔离,并且这套切分要能被调度器识别、被 Kubernetes 当作一等资源来管理。它现在是 CNCF Sandbox 项目,也是国内多厂商异构卡统一纳管的一条现实路径。
核心技术揭秘
HAMi 的关键不在“写一个 device plugin”,而在调度器与运行时库的配合。原生扩展资源只能做整数加减,无法表达“这块卡已被切成 3 份、剩余 6GB 显存和 40% 算力”,因此 HAMi 自己维护了一张节点 GPU 账本,并在调度链路中注入。
拆开看,是四个组件的接力:
hami-scheduler 走 Scheduler Extender(新版本也在向 Scheduler Framework 插件迁移)路线。Filter 阶段它不看整卡数量,而是遍历节点上每块 GPU 的已分配份额,判断“同一张卡上所有容器的显存之和 ≤ 卡容量、算力配额之和 ≤ 100%”。Score 阶段支持 binpack / spread 策略,并考虑了卡间拓扑——同一节点的 GPU 按 NVLink / PCIe 链路分组,尽量避免把跨链路的卡塞进同一个高带宽任务。
hami-webhook 承担两件事:准入阶段把用户声明的 nvidia.com/gpumem、nvidia.com/gpucores 翻译成调度器可识别的虚拟资源;绑定完成后再拦截一次,把调度器写在 Annotation 里的分配结果(GPU UUID、显存额度、算力额度)转成容器环境变量,并把 libvgpu.so 挂进容器。
libvgpu 是隔离的真正执行者,通过 ld.so.preload 劫持 CUDA Driver API:cuMemAlloc 超额直接返回 OOM,cuMemGetInfo 向上层伪装成“我这块卡只有 8GB”,cuDeviceGetCount 让容器只看见被分配的那几张卡。算力侧则通过限制 SM 占用比例与上下文调度来逼近配额。这套是用户态软隔离,不是 MIG 那种硬件分区,精度和安全性都有天花板。
hami-device-plugin 负责设备发现与健康上报,同时为 Ascend、寒武纪、海光、沐曦、天数等国产卡提供统一的抽象层,让上层调度逻辑基本复用。
功能亮点与差异
第一,硬件无关性。MIG 挑卡,HAMi 不挑。3090、4090、A10、T4 这些存量最大的卡都能切,这对已经采购了大量消费级/中端卡的团队是决定性优势。
第二,二维隔离。time-slicing 只解决“能不能共用”,HAMi 解决“共用多少”——显存和算力分别配额,避免了“一个跑满 SM 的邻居把整卡拖垮”。
第三,调度层感知。它不是简单的设备插件共享开关,而是真的把碎片资源纳入调度决策,配合 binpack 能显著降低卡间碎片率。
差距在于隔离强度。libvgpu 依赖 LD_PRELOAD 生效,静态链接 CUDA 的程序、直接用 NVML 或 ioctl 读驱动的进程都能绕过限制;多租户强合规场景下,这不是 MIG 的替代品。
应用场景与落地建议
适合:中小模型在线推理(多个副本共享一张卡)、Dev/Notebook/CI 集群、教学与实验环境、国产卡混合纳管的异构集群、以及 GPU 利用率长期低于 20% 的“证书式”业务。
不适合:大模型训练、对故障隔离有硬性合规要求的金融/多租户场景。
落地时几个坑要提前踩过:
- 驱动与 CUDA 版本一致性。libvgpu 与宿主机驱动版本强绑定,节点驱动版本漂移会导致容器内 CUDA 初始化失败,建议用 DaemonSet 统一镜像并锁定驱动矩阵。
- 超卖要保守。算力配额之和超过 100% 时,延迟抖动会被放大数倍;生产上先按 1:2 到 1:4 的显存超卖比例灰度。
- 监控要双轨。容器内看到的是被伪装的显存视图,真实利用率得从宿主机侧(DCGM/Prometheus)采集,否则容量规划全是错的。
- 调度器是单点。Extender 模式对 apiserver 有额外调用开销,大规模集群建议做高可用部署并关注 Filter 阶段延迟。
- 升级顺序。webhook、scheduler、device-plugin 三者的资源模型必须同版本,滚动升级期间可能出现 Annotation 解析失败导致 Pod 卡在 Pending。
综合评价
优势:切中真实痛点、硬件覆盖面广、调度与运行时联动设计完整、中文社区活跃,是当前“非 MIG 路线”里工程完成度最高的方案之一。
短板:用户态拦截决定了隔离强度上限,安全边界只能靠信任而非机制;跨 CUDA 版本兼容性维护成本高;组件多、排障链路长,出问题时从 Pod Annotation 一路查到 libvgpu 日志并不轻松。
一句话:如果你的集群里躺着一堆利用率个位数的中端卡,HAMi 几乎是当下性价比最高的解法;如果你要的是硬隔离和多租户安全,还是老老实实上 MIG 或整卡独占。


评论