k8s-vgpu-scheduler 设备注册协议逆向图解Node/Pod 注解握手全流程一篇看懂【免费下载链接】k8s-vgpu-schedulerOpenAIOS vGPU device plugin for Kubernetes is originated from the OpenAIOS project to virtualize GPU device memory, in order to allow applications to access larger memory space than its physical capacity. It is designed for ease of use of extended device memory for AI workloads.项目地址: https://gitcode.com/gh_mirrors/k8s/k8s-vgpu-scheduler前言vGPU 调度器靠什么看见GPUk8s-vgpu-schedulerHAMi是一个 Kubernetes vGPU 设备调度项目核心能力是GPU 显存虚拟化让多个 Pod 共享一张物理 GPU并按显存/算力比例硬限制每个容器的用量还可以用主机内存做 swap 实现显存超卖。它和 kube-scheduler 最大的不同在于GPU 是可拆分、可记账的共享资源调度器必须实时掌握每张卡的分片数、显存上限、算力上限和健康状态。它是怎么做到不依赖任何私有 API 的答案很Kubernetes——全程只用 Node 和 Pod 的 annotations注解完成注册、心跳、握手和调度决策。本文从源码层面逆向这套协议从节点上的 device-plugin 如何把设备规格贴到 Node 注解到 scheduler 如何用握手判断节点存活再到调度结果如何写回 Pod 注解交给设备插件执行分配全流程图解如下。上图即 HAMi 的整体架构MutatingWebhook 负责把请求 GPU 的 Pod 切换给 HAMi schedulerscheduler 作为 extender 注册 Filter/Score 方法并写出调度决策定制版 DevicePlugin 按决策执行分配见 docs/develop/design.md。一、协议总览两条注解信道整套协议只依赖两类对象上的注解可以概括为两条信道信道载体方向作用设备注册信道Node annotationsdevice-plugin → scheduler上报每张卡的规格、心跳握手调度决策信道Pod annotationsscheduler → device-plugin下发分到哪张卡、分多少设备注册时序图出自官方协议文档 docs/develop/protocol.md二、Node 侧device-plugin 如何上报设备规格每个 GPU 节点上的 HAMi device-plugin 会每 30 秒patch 两条 Node 注解以 NVIDIA 为例HAMi.sh/node-handshake-nvidia: Reported_{本机当前时间戳} HAMi.sh/node-register-nvidia: {设备1}:{设备2}:...:{设备N}每条设备信息的编码格式为 7 个逗号分隔字段{设备UUID},{分片数 Count},{显存上限 Devmem},{算力上限 Devcore},{设备型号 Type},{Numa},{是否健康 Health}实际例子该节点有 2 张 V100-32G 和 2 张寒武纪 MLU370-X4HAMi.sh/node-nvidia-register: GPU-00552014-5c87-89ac-b1a6-7b53aa24b0ec,10,32768,100,NVIDIA-Tesla V100-PCIE-32GB,0,true:GPU-0fc3eda5-e98b-a25b-5b0d-cf5c855d1448,10,32768,100,NVIDIA-Tesla V100-PCIE-32GB,0,true:各字段正好映射到 pkg/api/device_register.go 中的DeviceInfo结构体Id / Count / Devmem / Devcore / Type / Numa / Health。编解码逻辑在 pkg/util/util.go 的EncodeNodeDevices/DecodeNodeDevices中实现。多设备厂商怎么区分每种芯片有独立的注解前缀定义在各厂商 device 包中并注册进全局映射表 pkg/device/devices.go厂商握手注解 (handshake)注册注解 (register)NVIDIA4pd.io/node-handshake4pd.io/node-nvidia-register寒武纪 MLU4pd.io/node-handshake-mlu4pd.io/node-mlu-register海光 DCU4pd.io/node-handshake-dcu4pd.io/node-dcu-registerdevice-plugin 侧的写入动作例如 NVIDIA 插件在 pkg/device-plugin/nvidiadevice/nvinternal/plugin/register.go 中写入Reported 当前时间MLU 与 DCU 插件分别在 pkg/device-plugin/mlu/register.go、pkg/device-plugin/hygon/dcu/register.go 中做同样的事。三、握手机制Reported ↔ Requesting 的对表节点和调度器分布在两台机器上时钟不可能完全对齐。如果只看 register 注解的时间戳判断存活时钟漂移就会导致节点被误判离线。HAMi 的解法是双向互打时间戳device-plugin 每 30s 把握手注解置为Reported_节点时间scheduler 每 30s 遍历节点发现Reported后用调度器自己的时钟把该注解改写成Requesting_调度器时间下一轮 device-plugin 发现被改成Requesting再回写Reported_节点时间完成一次回合。于是 scheduler 判断存活的标准变成如果注解停留在Requesting_xxx且当前调度器时间比注解里的时间戳超出了阈值文档中为 5 分钟说明节点侧的 device-plugin 早已不在应答该节点设备被标记为 unavailable超时清理逻辑见 pkg/scheduler/scheduler.go 的RegisterFromNodeAnnotatons。节点设备彻底消失时如 GPU 掉卡、插件退出scheduler 还会把注解改写为Deleted_时间戳并从本地设备表删除形成Reported → Requesting → Deleted的完整状态机。 逆向视角这套谁最后写入谁说了算 时间戳仲裁的无锁设计本质上是把lease 租约思想压进了两条字符串注解里不需要 etcd watch 长连接重启后自愈。四、Scheduler 侧从注解构建集群 GPU 视图HAMi scheduler 启动后在 pkg/scheduler/scheduler.go 中建立两个内存账本nodeManagerpkg/scheduler/nodes.gomap[节点名] - NodeInfo{Devices []DeviceInfo}数据源就是上一节解析出的 Node 注册注解podManagerpkg/scheduler/pods.gomap[Pod UID] - podInfo{NodeID, Devices}通过 informer 监听所有带4pd.io/vgpu-node注解的 Pod 维护。每当有 Pod 请求 GPU 资源进入 Filter/Score 时getNodesUsage会做两件事从 nodeManager 拉出每个节点每张卡的总容量Count / Totalmem / Totalcore / Health遍历 podManager 中已分配 Pod 的注解把每份已分走的显存/算力累加到对应卡的 Used 字段上得到剩余可用量。也就是说GPU 余量 Node 注解的总量 − Pod 注解中已承诺的量两条信道在此汇合调度决策完全建立在注解数据之上。五、Pod 侧调度决策如何写回 Pod 注解节点选出来后Filter 过滤 Score 打分打分策略见 pkg/scheduler/score.goscheduler 一次性 patch 三条 Pod 注解常量定义见 pkg/util/types.go4pd.io/vgpu-node: {选中的节点名} 4pd.io/vgpu-time: {unix 时间戳} 4pd.io/devices-to-allocate: {容器1请求}:{容器2请求}:...其中每段容器请求的格式是{设备UUID},{设备类型关键字},{显存请求MB},{算力请求}。例如双容器 Pod 分别申请 3G 和 5G 显存4pd.io/devices-to-allocate: GPU-0fc3eda5-...,NVIDIA,3000,0:GPU-0fc3eda5-...,NVIDIA,5000,0: 4pd.io/vgpu-node: node67-4v100 4pd.io/vgpu-time: 1705054796Pod 调度决策时序图同样出自 docs/develop/protocol.mdBind 阶段上锁与 bind-phasescheduler 在 Bind 时pkg/scheduler/scheduler.go 的Bind方法还会追加两条注解4pd.io/bind-phase: allocating—— 标记进入分配中4pd.io/bind-time—— 记录绑定时间防止重复处理。同时通过节点锁pkg/util/nodelock/nodelock.go对该节点加锁避免同一节点上并发分配互相踩脚。六、Device-plugin 侧按注解逐容器消费配额Pod 落到节点后kubelet 调 device-plugin 的 Allocate。HAMi 的定制版插件并不一次全给而是读取4pd.io/devices-to-allocate注解DecodePodDevices按容器顺序解码为每个容器取它名下的设备段GetNextDeviceRequest据此生成环境变量显存/算力上限和挂载每成功分配一个容器就把该段从注解中划掉EraseNextDeviceTypeFromAnnotation注解中所有段清空后把4pd.io/bind-phase改为success并释放节点锁失败则改为failed逻辑见 pkg/device/devices.go。bind-phase字段因此构成第三重状态机allocating → success / failed配合 scheduler 的 informer 可以实时观察分配进度。七、端到端全流程一张图串起来把上面六步连起来一次完整的注解握手如下[节点 device-plugin] [HAMi scheduler] [kubelet/DP] │ 每30s: Reported_节点时间 │ │ │──node 注解──► scheduler 读注册注解 │ │ │ 改写 Requesting_调度时间 │ │◄──心跳回合── 建立 Node 设备视图 │ │ │ │ Pod 请求 GPU 到达 │ │ │ Filter/Score: 节点总量-已承诺量 │ │ │──Pod 注解: vgpu-node │ │ │ devices-to-allocate bind-phase │ │ │◄────────────────────────────────── │ │ │ Bind: 上节点锁、创建 Binding │ │ 按容器解码注解、设置限额环境变量 │ │ │◄────────────────────────────┼──────── 逐容器 Allocate ───────────┤ │ 划掉已分配段 │ bind-phase success │对应运行的真实系统效果可以看这张 HAMi 共享 GPU 使用示例八、逆向要点小结 机制注解 Key以 NVIDIA 为例值形态逆向结论设备注册4pd.io/node-nvidia-register7 字段逗号串:分隔多卡静态规格30s 刷新心跳握手4pd.io/node-handshakeReported_/Requesting_/Deleted_ 时间戳双方互写时钟超时判离线调度决策4pd.io/vgpu-node节点名Filter/Score 的输出去向分配清单4pd.io/devices-to-allocate按容器分段的 UUID限额DP 逐容器消费并划掉分配状态4pd.io/bind-phaseallocating/success/failed节点级串行化 进度可观测这套协议最值得借鉴的三点无状态存储、注解即协议——所有跨组件信息都压缩进可 patch 的字符串重启任意组件都能从 etcd 全量重建时间戳互打解决时钟漂移——存活判断只依赖同侧时钟差永远不直接比较两台机器的绝对时间容量 注册总量 − 已承诺量——用 Pod 注解做承诺账本天然支持超卖与记账。延伸阅读协议文档docs/develop/protocol.md设计文档与流程图docs/develop/design.md配置项说明含调度策略docs/config.md调度核心源码pkg/scheduler/注解编解码pkg/util/util.go、pkg/util/types.go各厂商 device-plugin 注册逻辑pkg/device-plugin/nvidiadevice/nvinternal/plugin/register.go【免费下载链接】k8s-vgpu-schedulerOpenAIOS vGPU device plugin for Kubernetes is originated from the OpenAIOS project to virtualize GPU device memory, in order to allow applications to access larger memory space than its physical capacity. It is designed for ease of use of extended device memory for AI workloads.项目地址: https://gitcode.com/gh_mirrors/k8s/k8s-vgpu-scheduler创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考