拆解Flex:ai本地虚拟化的3大核心组件:CUDA劫持、GPU设备插件与Volcano调度扩展
【免费下载链接】flexaiFlex:ai是一个面向AI容器场景的开源项目,其核心能力包含两大部分,分别是XPU虚拟化和多级智能调度。其中XPU虚拟化分为本地XPU虚拟化和跨节点拉远虚拟化,本地XPU虚拟化支持将1台服务器上的XPU算力卡虚拟化分割出多个虚拟算力单元,实现单张算力卡在多个容器的共享。跨节点拉远虚拟化支持通过RDMA或TCP网络访问远端节点上的算力卡。多级智能调度支持对切分出的虚拟卡进行Binpack等资源级调度,以及对AI训推任务进行分时调度等能力。项目地址: https://gitcode.com/ModelEngine/flexai
🚀Flex:ai是一个面向 AI 容器场景的开源项目,其本地 GPU 虚拟化能力可将 1 张算力卡切分为最多 20 个虚拟 GPU(vGPU),实现多容器共享同一张卡。本文将拆解支撑该能力的 3 大核心组件:CUDA 劫持、GPU 设备插件与Volcano 调度扩展,帮你快速理解 GPU 算力切分、显存隔离与 Binpack 资源调度的完整链路,适合刚接触 K8s GPU 共享与 XPU 虚拟化的新手阅读。
Flex:ai 本地虚拟化:一张 GPU 卡如何"变"出 20 个 vGPU?
传统 K8s 集群中,一张 GPU 卡只能被一个 Pod 独占,大量推理小任务排队等待整卡,资源利用率极低。Flex:ai 的本地 XPU 虚拟化解决的正是这个问题:
| 能力 | 说明 |
|---|---|
| 🎯 算力切分 | 单卡切分为 1~20 个 vGPU,每个 vGPU 可设定算力百分比(5% 的倍数) |
| 🧠 显存隔离 | 按 Gi 为单位限制每个 vGPU 可用显存(vgpu-memory.1Gi) |
| ⚡ 资源级调度 | 对虚拟卡做 Binpack 等调度策略,提升装箱率 |
| ⏱️ 分时调度 | 面向 AI 训推任务的时间维度调度 |
整套能力由 3 个组件协作完成:
- CUDA 劫持(client-update):让容器内的 CUDA 调用受到算力/显存限制;
- GPU 设备插件(gpu-device-plugin):把 vGPU 作为 K8s 资源注册给 kubelet;
- Volcano 调度扩展(vc-scheduler + huawei-xpu.so 插件):决定哪个 vGPU 任务调度到哪张卡。
三者关系可以概括为:设备插件"卖资源"、调度器"分资源"、CUDA 劫持"限资源"。
组件一:CUDA 劫持——让容器"看不见"整卡
工作原理:备份、替换、监控三连
CUDA 劫持是 Flex:ai 本地虚拟化的"执行层"。它通过 DaemonSet 以节点级方式部署 cuda-client-update.sh,对系统中的 CUDA 驱动库做三件事(详见 cuda-client-update.sh#L44-L64):
- 备份:将原始
libcuda.so备份到/opt/xpu/lib/libcuda-original.so; - 替换:用包装库 libcuda_direct.so 顶替系统 CUDA 库,容器内所有 CUDA API 调用都被"劫持"到该库;
- 监控:主循环每 5 秒通过 SHA256 比对校验文件,自动修复被覆盖的文件并维护 gpu-monitor 监控工具(见 cuda-client-update.sh#L93-L115)。
算力限流:PID 控制器动态调节
被劫持后,vGPU 的算力上限由 GpuCoreLimiter 实现:它内置一个 PID 控制器,以约 167ms 为周期观测当前容器的 GPU 实际占用,动态计算注入的延迟量,把利用率"钉"在申请的vgpu-cores百分比上下波动。显存侧则由 memory_limiter.h 完成限制。CUDA 层面的钩子实现位于 cuda_hooks.cpp。
💡 简单说:你申请 20% 算力 + 3Gi 显存,劫持层就保证该容器"最多只能用这么多",其他容器的性能不受影响。
组件二:GPU 设备插件——把 vGPU 注册为 K8s 资源
vGPU 资源模型:3 个关键字段
设备插件 gpu-device-plugin 通过 K8s Device Plugin 接口(xpu.sock)向 kubelet 注册三类虚拟资源(定义见 gpu.go#L28-L33):
| 资源名 | 含义 | 取值 |
|---|---|---|
huawei.com/vgpu-number | 申请的 vGPU 卡数 | 1 起,≤ 节点物理卡数 |
huawei.com/vgpu-cores | 算力切分百分比 | 0~100,5 的倍数 |
huawei.com/vgpu-memory.1Gi | 显存占用 | 单位 Gi |
高可用的注册机制
插件主循环 main.go#L34-L63 值得新手学习:它通过 inotify 监听 kubelet 的kubelet.sock,kubelet 重启后自动重连;同时启动设备缓存(DeviceCache)与一个 gRPC PIDs 服务(service_impl.go),供容器内的xpu-client-tool查询该进程绑定的 vGPU 配置——这正是劫持层拿到"我的算力/显存限额"的来源。
📦 部署侧通过 Helm Chart 一键拉起:gpupool/values.yaml 中同时定义了gpuDevicePlugin、gpuClientUpdate、xpuExporter三个组件,对应模板见 gpu-device-plugin-daemonset.yaml 与 gpu-client-update-daemonset.yaml。
组件三:Volcano 调度扩展——虚拟卡的 Binpack 智能调度
设备插件解决了"资源从哪来",而"任务调度到哪张卡"由 Volcano 完成。Flex:ai 在标准 Volcano(controller + scheduler + webhook 三件套)基础上做了 XPU 扩展,编译产物为 huawei-xpu.so、vc-scheduler、vc-controller-manager 与 vc-webhook-manager,一键部署清单位于 volcano-development.yaml(其中调度器镜像配置见 volcano-development.yaml#L4198)。
它的两个核心角色:
- Binpack 资源级调度:
huawei-xpu.so作为 Volcano 调度插件,让 vGPU 任务尽量"装进"同一张物理卡,减少碎片,最大化剩余卡的可用度; - Webhook 准入改造:
vc-webhook-manager自动把 Pod 的调度器改写为 Volcano,并注入 PodGroup 等元数据,业务方无需关心调度细节。
3 大组件协同:一次 vGPU 申请的全链路
当一个 Pod 申请 vGPU 资源时,三个组件按以下顺序接力:
- 申请:Pod YAML 中声明
huawei.com/vgpu-*资源(见下文示例); - 准入:Volcano webhook 拦截请求,改写 schedulerName 并补全调度元数据;
- 调度:
vc-scheduler加载huawei-xpu.so插件,按 Binpack 策略为 vGPU 挑选物理卡与节点; - 分配:GPU 设备插件从该卡的可用 vGPU 中分配额度,容器内
xpu-client-tool经 gRPC 拿到核心/显存限额; - 限流:CUDA 劫持层(
libcuda_direct.so)依据 PID 控制器持续限算力、按配额限显存,gpu-monitor可实时查看利用率是否贴合设定值。
resources: requests: huawei.com/vgpu-number: 1 huawei.com/vgpu-cores: 20 huawei.com/vgpu-memory.1Gi: 3 limits: huawei.com/vgpu-number: 1 huawei.com/vgpu-cores: 20 huawei.com/vgpu-memory.1Gi: 3⚠️ 规格限制:一张 GPU 卡最多切 1~20 个 vGPU;单容器申请的 vGPU 数不超过节点物理卡数。
快速上手:Flex:ai 本地虚拟化部署关键步骤
完整教程见 GPU-Virtual-Service/README.md,新手只需记住 4 步:
- 环境准备:openEuler 22.03(cgroup v1)+ K8s 1.31.1 + NVIDIA 驱动与 container-toolkit,并配置容器运行时;
- 拉起调度组件:导入
vc-controller/vc-scheduler/vc-webhook-manager镜像后执行kubectl apply -f volcano-development.yaml; - 拉起虚拟化组件:打包 gpupool Helm Chart(
helm package gpupool),给节点打gpupool.com/gpu-ready=true标签后helm install; - 验证效果:部署 vLLM 推理服务后,用
watch nvidia-smi观察整卡占用,或在容器内执行gpu-monitor -p 1确认利用率在vgpu-cores设定值附近波动。
延伸:Flex:ai 的完整版图——不止本地虚拟化
本地虚拟化之外,Flex:ai 还包含跨节点拉远虚拟化(基于 RDMA/TCP 通过网络访问远端节点的算力卡)。gpu-remoting 子项目通过LD_PRELOAD注入 CUDA hook 库,将容器内的 CUDA 调用透明转发到远端服务器执行,并配套共享内存存储模块加速数据管道。
Flex:ai 拉远虚拟化存储模块代码结构图:
其共享内存设计通过Shared_Memory在渲染端(renderer)与计算端(compute)之间传递 batch 数据与模型参数,避免重复拷贝:
总结:3 个组件,各管一段
| 组件 | 解决的问题 | 关键文件 |
|---|---|---|
| CUDA 劫持 | 容器内算力/显存限流 | cuda-client-update.sh |
| GPU 设备插件 | vGPU 资源注册与分配 | cmd/main.go |
| Volcano 扩展 | vGPU 的 Binpack 调度与准入 | volcano-development.yaml |
对于新手而言,理解 Flex:ai 本地虚拟化的最佳路径是:先跑通 Helm 部署 → 再读设备插件的资源注册逻辑 → 最后看劫持层的 PID 限流实现。三者各司其职,共同把"一张卡独占"变成了"一张卡 20 用",让 AI 推理集群的 GPU 利用率真正提了上去。🎉
【免费下载链接】flexaiFlex:ai是一个面向AI容器场景的开源项目,其核心能力包含两大部分,分别是XPU虚拟化和多级智能调度。其中XPU虚拟化分为本地XPU虚拟化和跨节点拉远虚拟化,本地XPU虚拟化支持将1台服务器上的XPU算力卡虚拟化分割出多个虚拟算力单元,实现单张算力卡在多个容器的共享。跨节点拉远虚拟化支持通过RDMA或TCP网络访问远端节点上的算力卡。多级智能调度支持对切分出的虚拟卡进行Binpack等资源级调度,以及对AI训推任务进行分时调度等能力。项目地址: https://gitcode.com/ModelEngine/flexai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考