ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

分子模拟异构算力适配开发教程(14):算力池化入门——Kubernetes Device Plugin 与 HAMi vGPU

分子模拟异构算力适配开发教程(14):算力池化入门——Kubernetes Device Plugin 与 HAMi vGPU 分子模拟异构算力适配开发教程14算力池化入门——Kubernetes Device Plugin 与 HAMi vGPU版本声明块工具/软件KubernetesDevice Plugin 机制 v1.26 起 StableHAMiCNCF 孵化项目语言/环境K8s 集群、gRPC、YAML本文目标读完你能解释一张 GPU 如何从物理卡变成 Pod 里可见的设备并判断 HAMi 的 vGPU 切分对你的 MD 负载是否有价值一句话结论K8s 通过 Device Plugin 协议kubelet 上的 gRPCListAndWatch上报设备清单、Allocate完成容器挂载把异构设备暴露为 extended resource格式vendor-domain/resourcetypeNVIDIA 为nvidia.com/gpuHAMi 在此之上做算力虚拟化——按显存/算力切分 vGPUnvidia.com/gpumem: 3000按 MiB 申请README 原文列出支持 NVIDIA/Ascend/Cambricon/Hygon/Iluvatar/Kunlunxin/MetaX/Moore Threads 八家。〇、本篇要解决的认知问题一张 GPU 从物理卡到 Pod 内可见中间经过哪些环节Device Plugin 的 gRPC 接口各管什么extended resource 的命名格式是什么为什么 GPU 不能像 CPU 那样超卖HAMi 的架构webhook→scheduler extender→device plugin怎么在标准 K8s 上实现 vGPU 切分vGPU 切分对 MD 负载的收益和陷阱是什么铁律 9 的主战场一、机制解析1.1 Device PluginK8s 管异构设备的标准通道为什么这一节对你重要分子模拟一旦从“单机作业”走向“平台化”第 20 篇的完整项目你面对的第一个基础设施问题就是“几十张卡怎么分给几十个用户/任务”——Device Plugin 是所有答案的地基HAMi、昇腾 MindCluster第 15 篇都建在它上面。完整链路官方文档物理 GPU ──(1)注册── kubelet ──(2)上报── API Serverextended resource: nvidia.com/gpu ↑ │ │ (3)Pod 请求 limits.nvidia.com/gpu: 1 device-plugin 进程 ──(4)调度绑定── 调度器 │ └──(5)Allocate gRPC── kubelet 在容器创建时挂载设备/设环境变量各环节的官方语义注册device plugin 进程向 kubelet 的固定 socket/var/lib/kubelet/device-plugins/kubelet.sock该路径硬编码不受 kubelet--root-dir影响发送Registration携带自己的 socket 名、Device Plugin API 版本、要上报的ResourceName。ListAndWatchkubelet 调插件的这个流式接口“returns a stream of List of Devices. Whenever a Device state change or a Device disappears, ListAndWatch returns the new list”——设备的增减与健康状态Healthy/Unhealthy变化实时上报。Allocate“called during container creation so that the Device Plugin can run device specific operations and instruct Kubelet of the steps to make the Device available in the container”——真正把设备给容器的动作。AllocateResponse 可包含 annotations、device nodes设备文件挂载、环境变量、mounts、CDI 设备名CDI 支持 v1.31 GA。完整接口族还有GetDevicePluginOptions、GetPreferredAllocation、PreStartContainer。extended resource 的规则官方 manage-resources 文档命名必须是vendor-domain/resourcetype格式只能整数、不可超卖no overcommit、设备不可在容器间共享——这三条规则直接塑造了 GPU 调度的行为边界也解释了为什么需要 HAMi整卡分配太粗见 1.3。Pod 里的请求方式resources:limits:nvidia.com/gpu:2# 厂商域/资源类型整数1.2 从 CUDA_VISIBLE_DEVICES 说起三层可见性第 4 篇埋的“设备可见性三层关系”在 K8s 语境下的完整版device plugin 的 Allocate 决定容器分到哪些卡挂载设备文件注入环境变量如 CUDA_VISIBLE_DEVICESCUDA/OpenMM 运行时在可见集合内编号应用gmx 的 -gpu_id / OpenMM 的 DeviceIndex在集合内再选。三层各管一段——排障“Pod 里看不到卡/看到编号不对”的问题就是沿这三层逐层核对。1.3 HAMi在标准协议上做“切分”标准 Device Plugin 的粒度是整卡——一张 80GB 的卡跑一个 4GB 需求的小 MD 作业浪费 76GB。HAMiHeterogeneous AI Computing Virtualization Middleware前身 k8s-vGPU-schedulerCNCF 孵化解决切分架构链READMEmutating webhook改 Pod 规格注入调度约束→ scheduler extenderfilter/score/bind 扩展调度器实现按显存/算力的细粒度匹配→ 设备分配写入 pod annotations → device pluginAllocate()按分配结果挂载切分后的设备核心组件 libvgpuHAMi-core 子模块做底层资源限制。请求语法README 原文示例resources:limits:nvidia.com/gpu:1# 1 个 vGPUnvidia.com/gpumem:3000# 3000 MiB 显存安装 HAMi 后节点上nvidia.com/gpu的数值含义变为 vGPU 数README 明确说明此行为。支持矩阵README 原文“NVIDIA, Ascend, Cambricon, Hygon, Iluvatar, Kunlunxin, MetaX, Moore Threads, and other vendors”——覆盖本系列第 1 篇选型表的大半国产厂商昇腾/寒武纪/海光/天数/昆仑芯/沐曦/摩尔线程具体型号支持细节以其文档站project-hami.io/docs/userguide/device-supported为准。调度策略binpack、spread、topology-aware、dynamic MIG与 Volcano/Kueue/GPU Operator 生态集成。1.4 MD 负载的切分收益与陷阱铁律 9 主战场vGPU 切分对 MD 的价值判断这是本篇最重要的工程判断有利场景多用户共享集群、作业显存需求远小于整卡小体系 MD 的显存占用常见 2–8GB、批量短作业第 17 篇的调度吞吐场景——切分后单卡并行多个作业集群吞吐显著提升。陷阱铁律 9切分收益必须实测不能按算力比例外推MD 性能的主导因素是显存带宽每步全体系坐标/力的读写与 PCIe 传输CPU-GPU 协作时切分把这两者一起分了——算力切一半、ns/day 掉一半以上很常见因为带宽争用不是线性切分。另外 GPU-resident 模式第 3 篇对独占显存带宽敏感切分环境下收益可能消失。实操结论切分配置必须过第 12 篇的基准流水线整卡 vs 切分的 ns/day 对比档案里记录切分规格——没有实测数据的切分方案就是赌。二、完整代码与逐行剖析一个“迷你 Device Plugin”骨架——用 Python 实现 ListAndWatch/Allocate 的核心协议教学版展示 gRPC 契约生产用厂商插件#!/usr/bin/env python3迷你 Device Plugin把 2 个虚拟设备上报给 kubelet。 教学目的亲手走一遍 Registration → ListAndWatch → Allocate 协议 理解 K8s 怎么看见异构设备。生产环境请用厂商官方插件 NVIDIA k8s-device-plugin / 昇腾 ascend-device-plugin第 15 篇。 前置pip install grpcio grpcio-tools需要本机有 kubelet 的 device-plugins 目录 普通开发机没有也没关系——脚本带 --dry-run 模式纯本地演示协议。 importjsonimportosimportsocketimportsysimportthreadingimporttimefrompathlibimportPath# Device Plugin API 的 protobufv1beta1。--dry-run 模式不真连 kubelet# 用 dict 模拟协议消息专注展示接口语义。KUBELET_SOCKET/var/lib/kubelet/device-plugins/kubelet.sockPLUGIN_SOCKET/var/lib/kubelet/device-plugins/md-sim-devices.sockRESOURCE_NAMEexample.com/mdgpu# extended resource 格式vendor-domain/resourcetypeclassMiniDevicePlugin:实现 Device Plugin 协议的三步曲。def__init__(self,n_devices:int2,dry_run:boolTrue):self.devices{fmdgpu-{i}:Healthyforiinrange(n_devices)}self.dry_rundry_run# ── 第 1 步Registration向 kubelet 注册自己──────────────────defregister(self)-dict:官方协议发送 socket 名 API 版本 ResourceName。 ResourceName 必须是 vendor-domain/resourcetype 格式—— 这是 Pod YAML 里 limits 键的来源。msg{kubelet_socket:KUBELET_SOCKET,plugin_socket:PLUGIN_SOCKET,api_version:v1beta1,resource_name:RESOURCE_NAME}ifself.dry_run:return{step:Registration,request:msg,result:dry-run 模拟成功}# 真实实现连 KUBELET_SOCKET 发 RegisterRequestgRPCraiseNotImplementedError(生产请用厂商插件本骨架 dry-run 演示)# ── 第 2 步ListAndWatch流式上报设备清单与健康状态────────────deflist_and_watch(self):官方语义Whenever a Device state change or a Device disappears, ListAndWatch returns the new list——长连接流不是一问一答。ifself.dry_run:yield{devices:dict(self.devices),note:首次全量上报状态变化时再推新列表}# 模拟一次状态变化设备 1 变 Unhealthy——如 ECC 错误/掉卡time.sleep(1)self.devices[mdgpu-1]Unhealthyyield{devices:dict(self.devices),note:mdgpu-1 掉了调度器将不再把新 Pod 调到它上面}returnraiseNotImplementedError# ── 第 3 步Allocate容器创建时把设备交给容器─────────────────defallocate(self,device_ids:list[str])-dict:官方语义run device specific operations and instruct Kubelet of the steps to make the Device available in the container。 AllocateResponse 的四件武器官方文档return{device_ids:device_ids,# 武器 1环境变量注入——CUDA_VISIBLE_DEVICES 在这一层被设置env:{CUDA_VISIBLE_DEVICES:,.join(str(i)fori,dinenumerate(device_ids))},# 武器 2设备节点挂载/dev/dri/* 或厂商设备文件device_nodes:[/dev/mdgpu0],# 武器 3mounts驱动库等mounts:[/usr/local/md/lib:/usr/local/md/lib:ro],# 武器 4annotations / CDI 设备名v1.31 GAannotations:{md-sim/allocated-by:mini-plugin},}defmain()-None:dry--dry-runinsys.argvornotPath(KUBELET_SOCKET).exists()pluginMiniDevicePlugin(n_devices2,dry_rundry)print(json.dumps(plugin.register(),ensure_asciiFalse,indent2))print(── ListAndWatch 流 ──)forupdateinplugin.list_and_watch():print(json.dumps(update,ensure_asciiFalse))print(── Allocate假设调度器把 mdgpu-0 分给某 Pod──)print(json.dumps(plugin.allocate([mdgpu-0]),ensure_asciiFalse,indent2))print(\n验证把 RESOURCE_NAME 换成 nvidia.com/gpuPod YAML 写 limits.nvidia.com/gpu:1 —— 这就是 K8s 管 GPU 的全部公开秘密)if__name____main__:main()HAMi 场景下 MD 作业的 Pod 样例对照 1.3 语法# md-job-vgpu.yaml —— HAMi 环境的 MD 作业按显存申请 vGPUapiVersion:v1kind:Podmetadata:name:md-benchmem-01spec:restartPolicy:Nevercontainers:-name:gmximage:your-registry/gromacs-musa:2026.1# 第 9 篇 SCS 思路的自有镜像command:[gmx,mdrun,-s,/data/benchMEM.tpr,-deffnm,/out/md,-nb,gpu,-pme,gpu,-update,gpu,-gpu_id,0]resources:limits:nvidia.com/gpu:1# 1 个 vGPU 槽nvidia.com/gpumem:8000# 8 GiB 显存按 MD 实测需求见铁律 9 演示cpu:8memory:16GivolumeMounts:-{name:data,mountPath:/data}-{name:out,mountPath:/out}volumes:-{name:data,hostPath:{path:/srv/md-data}}-{name:out,emptyDir:{}}# 铁律 9 实测清单上集群前必做# 1. 整卡跑 benchMEM → ns_day_full第 12 篇流水线# 2. vGPU 8000MiB 跑 benchMEM → ns_day_vgpu# 3. 比值 0.5 就要重新评估切分带宽争用非线性——数据进档案再决策逐段剖析list_and_watch的流式语义是协议精髓不是 kubelet 轮询插件而是插件持续推——设备掉线Unhealthy的秒级感知靠它MD 长作业的容错基础第 19 篇故障诊断会用到健康状态这条线。allocate返回的env字段直接解释了第 4 篇的谜题CUDA_VISIBLE_DEVICES 是 device plugin 注入的——K8s 的“分配”与 CUDA 的“可见”在这里对接。YAML 样例的 gpumem8000 不是拍脑袋注释里固化了铁律 9 的三步实测清单——切分规格的合法性由基准流水线的对比数据背书这正是“代码即流程”的写法。三、常见报错与排查问题 1现象——Pod 里nvidia-smi看不到卡 / gmx 报无 GPU 设备。根因沿 1.2 节三层逐层查——最常见是 Pod 没请求 extended resourcelimits 里没写 nvidia.com/gpukubelet 不会挂任何设备其次是 device plugin DaemonSet 没就绪ListAndWatch 没跑起来节点资源数为 0。解法kubectl describe node node看 node 的 Capacity/Allocatable 里有没有 nvidia.com/gpu插件上报的证据kubectl get pod -n plugin-ns看插件 DaemonSet 状态Pod YAML 核对 limits。问题 2现象——装了 HAMi 后之前正常的整卡作业行为变了节点 GPU 数含义变了。根因HAMi 的已知行为变更——节点上nvidia.com/gpu数值变为 vGPU 数README 明示调度语义从整卡变切分。解法集群管理员统一口径HAMi 环境下所有 GPU Pod 走 HAMi 语法gpu gpumem混用旧语义会产生歧义迁移期用标签/节点池隔离 HAMi 节点与非 HAMi 节点。问题 3现象——vGPU 切分后 MD 作业性能暴跌掉到整卡的一半以下。根因铁律 9 的典型现场——MD 是带宽敏感负载切分把算力和带宽一起切了且多 vGPU 争用同一物理卡的带宽/调度槽非线性恶化GPU-resident 模式尤其敏感。解法回到三步实测清单整卡 vs 切分对比数据若比值不可接受该作业改为整卡调度去 gpumem 或标注独占吞吐需求改由“单卡多进程排队”满足第 17 篇的调度器比硬切分对 MD 更友好。问题 4现象——自定义 Device Plugin国产卡注册后节点资源一直 0。根因注册协议三要素有误——socket 路径不在/var/lib/kubelet/device-plugins/kubelet 只认这个硬编码目录ResourceName 格式不是vendor-domain/resourcetypeAPI 版本不匹配。解法对照本文骨架的三步曲逐项检查用ls /var/lib/kubelet/device-plugins/确认插件 socket 建立了kubelet 日志journalctl -u kubelet里找 Registration 拒绝原因。四、动手练习练习 1基础跑本文骨架的--dry-run模式无需 K8s 环境观察三步曲的协议消息流。判定成功标准输出含 Registration 请求含格式正确的 RESOURCE_NAME、两次 ListAndWatch 推送第二次 mdgpu-1 为 Unhealthy、Allocate 响应含 CUDA_VISIBLE_DEVICES 注入能复述设备掉线到调度器感知的链路。练习 2进阶把骨架的 allocate 改成支持“设备偏好”GetPreferredAllocation 语义的简化版当请求 1 个设备且 mdgpu-0 健康时优先给 mdgpu-0模拟 binpack写出你的选择逻辑与理由注释。判定成功标准代码含健康检查分支与偏好序dry-run 输出体现“Unhealthy 设备绝不会被 Allocate”能对照 1.3 节说明 HAMi 的 binpack 策略与此的关系。练习 3思考题无标准答案如果让你为实验室 8 张卡4×NVIDIA 4×摩尔线程设计共享策略哪些负载切分vGPU、哪些独占思考方向验证要点① MD 大体系benchPEP-h 级与短作业第 17 篇吞吐场景的切分收益差异② 混合厂商集群的 ResourceName 设计两个 vendor-domain③ 铁律 9 的实测流程在两种负载上各怎么跑。五、小结与下一篇预告本篇打通了算力池化的地基Device Plugin 三步曲Registration→ListAndWatch 流式健康上报→Allocate 挂载环境注入是 K8s 管一切异构设备的标准通道extended resource 三规则整数/不可超卖/不共享定义了调度边界三层可见性plugin 分配→CUDA_VISIBLE_DEVICES→应用选卡解释了 Pod 里“看得见几号卡”HAMi 用 webhookextenderplugin 三层架构实现 vGPU 切分gpumem 按 MiB支持八家含国产厂商MD 的切分决策必须过基准对比铁律 9——带宽敏感负载的切分收益不能外推。下一篇在 Device Plugin 地基上继续向上Volcano 的批调度PodGroup 的 gang 语义、Queue 配额与昇腾 MindCluster 的 vNPU 切分vir 模板体系——把“设备能分”升级为“作业组能整批调度”MD 多副本任务、增强采样的多 walker 作业都靠它。本篇认知问题回显FAQQ1Kubernetes 的 Device Plugin 机制是怎么工作的Adevice plugin 进程通过 kubelet 固定 socket/var/lib/kubelet/device-plugins/kubelet.sock发送 Registration携带自己的 socket 名、API 版本、ResourceNamekubelet 调 ListAndWatch 流式接口持续获取设备清单与健康状态容器创建时 kubelet 调 Allocate插件通过 AllocateResponse 注入环境变量如 CUDA_VISIBLE_DEVICES、挂载设备节点、mounts 或 CDI 设备名。Q2Pod 里怎么请求 GPU为什么 GPU 不能超卖A在 resources.limits 写 extended resource格式 vendor-domain/resourcetypeNVIDIA 是 nvidia.com/gpu值必须整数K8s 对 extended resource 的规则是只能整数、不可超卖no overcommit、设备不可在容器间共享——因为设备是独占性物理资源不像 CPU 可分时复用。Q3HAMi 是什么怎么申请 vGPUAHAMiHeterogeneous AI Computing Virtualization Middleware前身 k8s-vGPU-schedulerCNCF 孵化是异构算力虚拟化中间件mutating webhook 改写 Pod、scheduler extender 做细粒度调度、device plugin 按分配挂载libvgpu 做底层限制Pod 用 nvidia.com/gpu nvidia.com/gpumemMiB按显存申请 vGPUREADME 列出支持 NVIDIA/Ascend/Cambricon/Hygon/Iluvatar/Kunlunxin/MetaX/Moore Threads。Q4vGPU 切分对分子模拟作业合算吗A不能按算力比例外推——MD 是显存带宽敏感负载切分同时切走算力与带宽且多 vGPU 争用物理卡带宽呈非线性恶化GPU-resident 模式尤其敏感正确做法是实测对比整卡与切分各跑基准测 ns/day比值可接受才用切分大体系/长作业倾向整卡独占吞吐型短作业才考虑切分。
返回列表