
openFuyao v25.09 的部署实践我前前后后折腾了大概两周才敢放到生产上。这套平台解决的核心问题就一句话把 GPU、NPU、甚至纯 CPU 计算节点上的异构算力统一收进一个调度平面按业务需求动态分配。这篇内容不是官方文档的复读是我从环境盘点到跑通第一个真实任务的完整记录包括我踩过的坑、改过的参数、以及最后在 valhalla 项目上实际用起来的效果。如果你正准备做企业内部的算力纳管或者被“GPU 利用率常年不到 40%”折磨过这篇应该能帮你省不少时间。我这次的目标环境不算复杂3 台控制节点加 5 台计算节点计算节点里混了 NVIDIA 的 A100、几张消费级 RTX 4090还有一批国产 NPU 加速卡。以前这些资源是分开管的训练归训练、推理归推理、NPU 那边自己一套调度谁也别想借谁的算力。openFuyao v25.09 上线的意义就是把这些“算力孤岛”连成一张池子。1. 为什么我最终决定把 openFuyao v25.09 部署到生产集群1.1 算力碎片化手里有卡却用不上的尴尬先说一个真实场景。我们团队同时跑着三个方向大模型微调要 A100在线推理服务要低延迟的 NPU还有一堆数据处理任务只需要 CPU。过去的管理方式是每个方向单独维护一套资源池调度器各自为政。结果就是A100 在训练任务间隙闲着NPU 那边排队排到天荒地老CPU 节点的资源被浪费了大半。最夸张的时候整个机房的 GPU 平均利用率只有 35% 左右。这不是个别现象。异构算力调度这件事说起来容易做起来难。难在哪儿不同加速卡的资源模型不一样GPU 看显存和算力NPU 看它的内部计算单元CPU 还要考虑 NUMA 拓扑和内存带宽。你没法用一套“几核几 G”的模板去描述所有资源。openFuyao 的做法是把这些异构设备抽象成标准化的资源对象通过设备插件把不同硬件的差异“消化”掉上层调度器只认统一的资源视图。这就是我最初对这套平台产生兴趣的原因。1.2 openFuyao 的定位与 v25.09 版本特性openFuyao 是个开源的企业级异构算力调度平台名字取自“扶摇直上九万里”的扶摇目标是让算力像水一样流动起来。它和直接基于 Kubernetes 原生调度器做资源管理不太一样它对 GPU、NPU 这类设备做了更深一层的抽象支持显存切分、设备拓扑感知、按业务配额划分算力池。v25.09 这个版本从 Release Notes 看主要做了几件事调度器框架重构、节点资源拓扑上报机制增强、GPU 显存隔离方案改进以及 Web 控制台的操作体验优化。我实际用下来感触最深的是拓扑感知调度。过去在 Kubernetes 里申请多卡 GPU 任务Pod 可能被调度到 PCIe 带宽吃紧的节点v25.09 的调度器会把 NUMA 节点、PCIe Switch 拓扑纳入决策尽量把多卡通信放在同一颗 CPU 的 PCIe 控制器下这对多卡训练任务影响非常明显。还有一点值得提它对国产 NPU 的支持不是做做样子而是通过开放的设备插件协议接入这一点对企业用户很重要——训练用 NVIDIA推理用国产卡这种组合越来越常见。1.3 什么场景适合参考这篇实践坦白说不是所有团队都需要上 openFuyao。如果你们公司就几台 GPU手动分配也能凑合那这个平台带来的管理成本反而高。但如果你的环境满足以下任一条件我建议认真看一下有超过 20 张异构加速卡且分属不同品牌或不同代际多个业务团队共享算力需要配额管理和优先级抢占正在建设统一的 AI 基础设施平台希望把训练、推理、数据处理放在同一套调度体系里有多集群统一管理的诉求我这次的部署规模是中小型的但整条路径和企业级部署没什么区别证书、存储、网络、设备插件、调度策略、监控告警一个都不能少。2. 部署前一定要做好的四件事2.1 硬件与系统环境盘点部署前我花了一天时间把所有节点的硬件信息摸了一遍。这一步看似基础但后面大多数问题都源于这里没做细。最好整理成一张表至少包含以下字段节点角色、CPU 型号与核数、内存大小、加速卡型号与数量、操作系统版本、内核版本、磁盘类型。系统层面控制节点我用了 Ubuntu 22.04 LTS计算节点混合了 Ubuntu 22.04 和 openEuler 22.03。这里要特别提醒不同 Linux 发行版对设备插件的依赖库影响很大尤其 NPU 的驱动和用户态 runtime 往往只针对特定发行版做过验证。openFuyao 的设备插件默认以容器方式运行但底层还是要调用宿主机上的驱动和 runtime 库所以节点上的驱动版本一定要和加速卡匹配。NVIDIA 那边就是 nvidia-driver 和 CUDA 版本对得上NPU 那边还要确认固件版本和 runtime 版本。磁盘方面控制面的 etcd 和数据库一定要放在 SSD 上。我一开始图省事放在机械盘的 NFS 卷上结果 etcd 的 fsync 延迟高得离谱控制面时不时抖动。后来换成本地 NVMe 盘问题立刻消失。计算节点不需要太大的系统盘但是给容器和镜像留的空间要够尤其是要拉大模型镜像的节点/var/lib/containerd 至少预留 500GB。2.2 容器运行时与基础组件准备openFuyao v25.09 推荐在 Kubernetes 集群之上部署所以你要先准备一个可用的 K8s 环境。我这边是 K8s v1.28 版本Helm v3。容器运行时用的 containerd版本不太老就行。控制面组件通过 Helm Chart 一键拉起计算面以 DaemonSet 的方式跑 Agent 和设备插件。GPU 节点的容器 runtime 需要额外处理。NVIDIA 那边要装 nvidia-container-toolkit装完之后 containerd 的配置里需要加入 nvidia 的 runtime 配置段。这一步不做好GPU 设备插件虽然能发现卡但 Pod 起来之后在容器里执行 nvidia-smi 会报错。NPU 节点也有类似的 runtime 要求只是不同厂家的安装方式差异很大有的给 RPM 包有的给 tar 包还需要自己配环境变量。我的建议是先把每一类节点的容器运行时调试到“能在普通 Pod 里看到加速卡设备”的程度再开始装 openFuyao。验证方法很简单起一个特权 Pod 进去看一眼设备文件在不在。另外openFuyao 的镜像需要从发布包导入到你们自己的镜像仓库。v25.09 的离线发布包里有 images 目录里面是完整的镜像列表和导出文件。我这边用的 Harbor在每台节点上配置了 docker registry mirror同时把镜像同步到了 Harbor 的项目空间里。如果节点数量多这一步不做离线同步后面部署时全节点拉镜像能把带宽打满。2.3 拿到 v25.09 后的版本核对与镜像加载发布包下载下来先别急着解压部署花十分钟做两件事校验文件完整性和核对版本。openFuyao 的发布包带了 SHA256 校验文件我习惯先跑一遍 sha256sum -c。版本核对也很重要v25.09 对应的 Helm Chart 版本是 25.9.0容器镜像的 tag 统一是 v25.09。Agent 和 Server 的版本必须保持一致这是个非常容易踩的坑——我一开始图省事先升级了控制面Agent 还留在旧版结果 Agent 注册后握手失败节点状态反复横跳查了半天才发现是版本不匹配。镜像加载的路径我再说细一点。离线包里每个镜像压缩文件对应一个镜像名和 tag解压后用 ctr -n k8s.io images import 或 docker load 导入都行。如果你有 Harbor更推荐的方法是直接把镜像推送到 Harbor然后通过 Helm values 里的 imageRegistry 参数指向 Harbor。这样后续节点扩容时只需要从内网拉取速度快也不依赖外网。2.4 网络、存储与时钟同步规划网络规划没那么复杂但一定要提前想清楚。控制面组件之间通信用 8443/TCP节点 Agent 上报用 10250/TCP动态端口范围我放到了 30000-32767这些要在防火墙和安全组里放行。节点之间如果有 Docker Bridge 网络注意叠加网络别冲突我用的是 Calico IPIP 模式Pod 网段选了 10.244.0.0/16。存储方面openFuyao 依赖 etcd、PostgreSQL 和 Redis。PostgreSQL 存业务数据比如队列、任务和配额配置Redis 做缓存和会话管理。这三个组件的持久化我全部用了 StorageClass 动态供应底层是 Longhorn 提供的有副本的块存储。时钟同步是很多人忽视的坑。调度和监控对时间敏感度很高节点时间偏差超过 500ms 会导致任务状态乱跳。我在所有节点上配了 chrony统一指向内网的 NTP 服务器并在部署后连续观察了两天确保时间误差控制在 50ms 以内。3. 从零完成 openFuyao v25.09 部署3.1 控制面组件部署顺序与配置我推荐用 Helm 方式部署步骤清晰也方便回滚。先把 Chart 包拉下来helm repo add openfuyao https://charts.openfuyao.example.com helm pull openfuyao/openfuyao --version 25.9.0 tar zxvf openfuyao-25.9.0.tgz解压后重点修改 values-prod.yaml。我的生产配置长这样global: clusterName: prod-fuyao imageRegistry: harbor.internal.example.com imagePullSecrets: - name: harbor-key server: replicas: 3 resources: requests: cpu: 2 memory: 4Gi storage: postgres: storageClass: longhorn size: 100Gi redis: storageClass: longhorn size: 20Gi auth: mode: token tokenSecret: fuyao-admin-token scheduler: replicas: 2 strategy: binpack topologyAware: true etcd: replicas: 3 storageClass: longhorn size: 50Gi部署命令helm install openfuyao ./openfuyao-25.9.0.tgz -n openfuyao -f values-prod.yaml --timeout 15m安装过程大概 5 分钟。装完检查一下 Pod 状态kubectl -n openfuyao get pods我第一次部署时卡在 etcd 那里Pod 一直 CrashLoopBackOff。看日志是磁盘 IO 延迟太高——storageClass 配成了 NFS。后来改成 Longhorn 本地副本才稳定下来。这里多说一句etcd 对延迟极其敏感官方建议 SSD 不是说着玩的机械盘上跑生产级 etcd 就是在给自己埋雷。控制面起来之后先用命令行工具验证一下集群健康openfuyao-cli cluster status如果显示 Online说明控制面基本正常。3.2 节点代理接入与算力注册控制面就绪后开始接入计算节点。每个计算节点上以 DaemonSet 方式运行 openfuyao-agent负责资源上报、任务执行和状态回传。Agent 接入需要认证令牌在控制面生成后保存到 Secret 里kubectl -n openfuyao create secret generic fuyao-agent-token \ --from-literaltokenxxxxxxxxxxxxxxxxxxxx然后给需要接入的节点打标签。这是为了区分节点上的算力类型。比如 GPU 节点打 gpuonNPU 节点打 npuon纯 CPU 节点不用打标签kubectl label node gpu-node-01 gpuon gpu-typea100 kubectl label node npu-node-01 npuon接着应用 Agent 的 DaemonSetkubectl apply -f openfuyao-agent-ds.yamlopenfuyao-agent-ds.yaml 里有个关键参数 resourceReportInterval默认是 15 秒我改成 10 秒调度时资源信息更实时。Agent 起来之后去控制台或命令行查看节点状态openfuyao-cli node list正常会看到每个节点状态为 Ready并显示每类加速卡的数量和已分配资源。如果你看到节点状态是 NotReady多半是版本不一致或者 Token 不对参考第五部分的排查方法。3.3 异构加速卡设备插件启用节点 Agent 注册成功只代表机器在编了加速卡真正能被调度还需要设备插件把资源上报给调度器。这一步是 openFuyao 和原生 Kubernetes 的最大区别之一。GPU 节点的设备插件通过 Helm value 控制devicePlugins: gpu: enabled: true runtime: nvidia sharedMode: true sharedMemory: 8GisharedMode 意味着开启动态显存切分一张 80GB 的 A100 可以被切成多个小份给不同任务用而不是一次只能被一个任务独占。这功能对提高卡利用率太关键了。根据我实测开了显存切分之后单卡利用率平均提高了 20 个百分点因为很多推理任务只吃 8GB 显存过去为了一个 8GB 的任务把整张 A100 锁死太浪费了。NPU 设备的接入方式更开放。openFuyao 提供了设备插件 SDKNPU 厂商可以基于 SDK 写插件。我这边用的厂商插件以独立 DaemonSet 方式部署的kubectl apply -f npu-device-plugin.yaml插件起来之后在节点上应该能看到类似 openfuyao.io/npu 的资源出现在可分配列表里。确认方法kubectl describe node npu-node-01 | grep openfuyao我当时遇到的问题是设备插件总是显示 0 个可用设备。后来排查到是插件容器里缺少对宿主机设备文件的访问权限需要在 DaemonSet 里把 /dev 以 hostPath 方式挂载进去同时设置 privileged: true。这一步不需要什么奇技淫巧但文档里写得比较隐晦我花了两个晚上才定位到。3.4 第一个调度任务的验证所有节点 Ready 之后提交第一个测试任务验证全链路。我写了一个简单的 ComputeJob 来申请一张 GPUapiVersion: openfuyao.io/v1beta1 kind: ComputeJob metadata: name: training-demo namespace: ai-lab spec: replicas: 1 template: spec: containers: - name: trainer image: registry.example.com/ai/train-demo:latest resources: limits: nvidia.com/gpu: 1 command: [nvidia-smi]提交之后马上看调度事件kubectl get events --field-selector involvedObject.nametraining-demo正常的事件序列是SCHEDULED → BINDING → READY。如果卡在 SCHEDULED 不动大概率是资源不满足或标签没对上。我的第一次提交就卡了半小时原因很简单节点的 gpu-type 标签是 a100但我创建的 ComputeJob 里没有指定标签选择器调度器没找到节点。后来在 spec 里加上 nodeSelector 就正常了。任务跑完之后去控制台看资源用量曲线。如果曲线有变化说明资源上报链路也是通的。到这里一套基础版 openFuyao 平台就算部署完成了。4. 异构算力调度策略与最佳实践4.1 调度策略配置优先级、拓扑与装箱部署完成只是开始真正体现平台价值的是调度策略怎么配。openFuyao v25.09 的调度器支持多种策略最常用的两个是 binpack装箱和 spread离散。binpack 会把任务尽量集中到少数节点上好处是空闲节点可以休眠或他用省电省成本spread 则把任务打散到不同节点降低单点故障影响范围。我这边默认用 binpack同时开了拓扑感知。拓扑感知调度对多卡任务影响很大。原理不复杂调度器会通过设备插件上报的 PCIe Switch 和 NUMA 信息优先把多张卡分配在同一 PCIe Switch 下的节点避免跨 NUMA 访问带来的性能损失。配置方式scheduler: strategy: binpack topologyAware: true topologyKey: openfuyao.io/pcie-switch我个人建议推理类任务开 binpack训练类任务开 spread。如果你不是特别清楚怎么选先用 binpack观察一段时间再看要不要调。4.2 算力隔离与配额管理多点团队共享集群之后配额管理就是头等大事。openFuyao 支持在 namespace 维度配置 ResourceQuota也可以创建更细粒度的立付资源池。我给两个团队分别建了资源池A 团队 20 张 GPU 和 8 个 NPUB 团队 10 张 GPU剩下 10 张 GPU 作为公共缓冲池。配置示例apiVersion: openfuyao.io/v1beta1 kind: ResourcePool metadata: name: team-a-gpu-pool spec: quota: nvidia.com/gpu: 20 openfuyao.io/npu: 8 selector: nodeLabels: pool: core-compute有了配额池之后各团队只能在自己池子里抢资源不会出现一个团队把整个集群的算力全部占满的情况。配额超了任务会排队而不是直接失败这个设计比我之前见过的很多平台要合理。4.3 一档实测数据参考部署完成后我做了个 7 天对比统计。之前的平台 GPU 平均利用率在 35%~40% 浮动切换到 openFuyao 之后由于可以动态切分显存和优先级抢占利用率爬到了 62%~68%。注意我这里说的是“利用率”不是“毛利率”而且样本量比较小不代表所有场景都能到 60% 以上。但至少说明算力池化加动态切分这个方向确实能把资源榨得更干。任务排队时间也明显缩短了。之前训练任务在高峰期平均要等 40 分钟拿到资源现在因为队列可以优先调度常用的微调任务基本 5 分钟内能排上。这还只是我 5 台计算节点的小环境规模再大一点优势只会更明显。5. 常见问题与排查记录5.1 设备插件启动失败这是我被卡最久的问题值得单独拎出来说。现象是 gpu-device-plugin Pod 一直 CrashLoopBackOff日志报错类似failed to initialize NVML: Driver/library version mismatch原因几乎可以锁定是宿主机上的 NVIDIA 驱动版本和插件容器里依赖的库版本不一致。排查方法nvidia-smi如果宿主机上 nvidia-smi 都执行不了先修驱动。如果宿主机正常插件还不起来看插件容器的挂载路径是否完整。我最后是通过把宿主机的 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 挂载进插件容器解决的。NPU 插件的报错类型更杂常见的有设备节点权限不足。先确认容器里能不能看到设备文件kubectl exec -n openfuyao npu-plugin-pod -- ls /dev | grep accel看不到就是 hostPath 没挂对看到但初始化失败就是 runtime 库问题。这个没有捷径对着厂商文档挨个对版本。5.2 调度的任务一直 PendingPending 的原因就几种资源不足、标签不匹配、污点未容忍、配额不足。排查顺序我建议这样kubectl describe pod pod-name看 Events 的最后几条。如果报 “0/5 nodes are available: insufficient nvidia.com/gpu”就是真的没资源了去确认其他节点是否有空闲 GPU。如果你确定有资源但调度器就是不给再看节点上的资源是否被错误地预留了。我踩过一个坑某个节点的 GPU 显示可用数量为 0原因是设备插件上报的显存总量算错了刷新后恢复正常。这种情况重启一下设备插件 Pod 通常能解决。5.3 监控数据与真实负载对不上监控数据不准也是高频问题。openFuyao 的 GPU 利用率指标依赖 DCGM默认采集周期是 15 秒所以你在面板上看到的曲线有十几秒的延迟是正常的不是故障。如果你需要更实时的数据可以在设备插件里启用 profiling 模式devicePlugins: gpu: dcgmExporter: enabled: true interval: 5s另外还要注意面板上的“显存使用量”显示的是分配量不是实际占用量。一个任务申请了 16GB 显存但实际只用 8GB面板上显示的还是 16GB 已分配。这不是 bug而是为调度决策服务的语义。看真实占用要用 DCGM 的 memory usage 指标。5.4 其他典型问题速查现象原因处理Agent 上报节点 NotReadyServer 与 Agent 版本不一致统一升级到 v25.09节点列表里看不到加速卡设备插件未部署或上报失败检查 /dev 挂载和 runtime 版本任务失败且报 token 失效Secret 里的 token 被轮换重新生成并同步到 Agentetcd 频繁 leader 切换磁盘 IO 延迟过高迁到 SSD 或本地 NVMe长时间运行后调度变慢etcd 数据量过大开启压缩策略并调整 defrag 周期还有一个值得说的openFuyao 的证书默认有效期是 1 年到期前一定要记得 renew不然控制面 HTTPS 接口会随机失败。我在生产环境里用 CronJob 自动触发证书轮换提前两个月就把告警接上了。6. valhalla 项目上的实际落地记录6.1 valhalla 是什么以实际案例验证平台能力valhalla 是我们内部一个多模型混合推理服务的代号。它的特点是对算力类型要求特别杂前置的数据需要 CPU 预处理主模型推理要 GPU还有一部分结构化数据抽取走了 NPU 加速。以前这个服务要跨三个资源池调度部署一次要协调三个团队非常痛苦。openFuyao 部署完成后我把 valhalla 作为第一个试点迁了过去。目标很明确验证异构算力能不能在一个平台内稳定编排。6.2 通过 openFuyao 跑通 valhalla 的关键节点valhalla 整体被拆成三个子任务预处理、推理、抽取。在 openFuyao 里我通过工作流类型的 CRD 把它们串联起来每个环节声明不同的资源需求apiVersion: openfuyao.io/v1beta1 kind: ComputePipeline metadata: name: valhalla-main namespace: ai-srv spec: stages: - name: preprocess resources: cpu: 4 memory: 16Gi - name: inference resources: nvidia.com/gpu: 1 memory: 32Gi - name: extract resources: openfuyao.io/npu: 1这种编排方式的好处是三个阶段可以在不同节点上并行执行跑在 GPU 节点上的任务不会因为等待 NPU 节点空闲而阻塞。以前跨资源池调度时一个环节卡住整个服务就停了现在每个阶段独立排队整体吞吐明显提升。6.3 这段实操下来的心得valhalla 迁移之后最直观的变化是发布流程简化了。原来发布一次要分别通知三个团队、改三套配置现在只需更新一套 Pipeline 定义。GPU 节点的平均利用率从 40% 提到接近 60%NPU 那边也用得更满了。踩坑的地方当然也有Pipeline 的失败重试策略初期配置得不好导致某个阶段失败后整个流程反复重启后来加了超时上限和失败告警问题才收敛。还有一个经验上线前一定要做完整的压测因为异构调度平台在任务量上去之后的行为和空闲时完全不同——队列深度、调度吞吐、设备插件上报频率都会成为瓶颈。最后再分享一个小技巧这次部署下来我最后悔没提前做的一件事是在项目启动的第一天就建立一套完整的节点资源基线数据。不是简单记一下每台机器有几张卡而是要把每类卡在空载、满载、混合负载下的性能和时延数据记录下来。原因很简单调度平台上线之后你要回答“调度策略到底有没有效果”这个问题没有基线数据就只能靠感觉拍脑袋。如果你也准备部署 openFuyao v25.09我的建议是先把前两周的监控数据老老实实存下来哪怕先用 Prometheus 默认的抓取周期。后面优化调度策略、调整配额、说服团队迁移时这些数据就是你最有说服力的依据。毕竟算力调度平台这种东西真正难的不是装起来而是装完之后让人相信它确实有用。