2026/10/23 9:54:13

CubeStudio多集群演进:从单机到多资源组的GPU算力平台实践

CubeStudio多集群演进:从单机到多资源组的GPU算力平台实践 最早跑CubeStudio单机版的时候一台双卡机器加一块共享存储就能把模型开发、训推的流程全部兜住。但等团队多了、项目组多了、GPU卡不够分的时候你很快会发现单机这摊事根本撑不住。要么排队排到天荒地老要么不同项目的环境互相干扰更别提GPU利用率低到让人心慌。我开始做多机扩容、多集群纳管和按项目组分算力是被一张“四卡机只有一块卡在跑、另外三块空转”的资源监控截图刺激到的。花了两三周把架构重排了一遍现在这套东西稳定跑了几十台GPU节点、多个K8s集群各个项目组的配额、优先级、抢占行为都能收敛到可控范围内。这篇就把整个演进过程里真正踩过的坑、验证过的路径和可以直接照抄的配置全部捋一遍。1. 先理清楚从单机到多集群到底要解决哪几层问题很多人一上来就急着装组件、配调度器结果多机节点加了一堆资源还是乱成一锅粥。我自己的经验是先别碰任何命令把“单机—多机—多集群—多资源组”这四层形态想明白比什么都重要。1.1 四个形态各自要突破什么瓶颈我习惯用下面这张表把每个阶段的瓶颈点和核心动作拆开看方便对号入座阶段形态核心瓶颈要解决的问题关键动作单机版单机GPU数量有限算力上限固定把开发、训练、推理在一个节点内跑通部署基础服务打通存储与镜像拉取多机版单节点物理资源不满足多租户排队GPU利用率低任务互相抢占节点加入集群统一GPU可观测与调度多集群版一个集群可纳管的节点和Namespace有限业务隔离、故障域隔离、环境区分控制面统一纳管数据面分散部署多资源组所有项目共用同一份算力池无法差异化保障按项目组/团队划分配额、优先级与费用归属资源组模型调度策略配额管理这张表其实对应了路径依赖你不能在单机没跑稳的前提下直接上多集群因为你会把单机的故障域直接放大到整个集群。更合理的路线是先把单机基线做扎实然后“同构地”往外推多机是在做一个更大集群的“单机”多集群是在做“多个更大集群”的调度而资源组则是在为前两层赋予业务语义。1.2 组件角色要先划分清楚控制面、数据面、存储面在实操里踩过的最大一个坑是把“所有组件堆在一个集群里”。CubeStudio这种平台天然包含三个角色面混在一起会让后续扩容非常痛苦控制面负责用户认证、项目组管理、资源组定义、任务调度决策。这一层需要高可用但负载通常不高用三台不带GPU的小机器就够。数据面负责真正跑GPU任务的节点组一般由装有GPU卡的机器组成。这里只运行业务Pod和必要的DaemonSet不要放控制面组件。存储面负责保存数据集、模型权重、训练日志。建议选用独立的分布式文件系统或对象存储避免和控制面/数据面互相影响。我最初把镜像仓库、MySQL、Redis全部塞在同一台GPU节点上后来发现一旦训练任务把带宽和内存吃满控制面接口直接卡成PPT镜像拉取也变得极不稳定。后来把控制面完全抽出去数据面只保留容器运行时、GPU Device Plugin和监控采集器整个系统的稳定性才真正提升了一个档次。这个思维模式很重要**多机多集群的本质不是“把Pod放到更多机器上”而是“把共享服务与计算资源解耦”。**想通了这一点后面所有配置都会变得很顺。2. 单机扩多机实操把更多GPU卡变成同一个池子第一阶段是把一台GPU机器扩展成多台GPU机器的集群。这里的核心工作不是装K8s而是让新加入的机器立刻变成“同一个池子”里的资源并且能够被CubeStudio正常调度和监控到。2.1 新节点加入集群前的五项体检如果把一台没有做任何预检的裸机直接加进集群大概率会遇到版本不一致、GPU驱动不匹配、防火墙策略挡住通信等一连串问题。我的习惯是先做一轮快速体检确认五项指标操作系统与内核版本是否与现有节点一致尽量使用相同的大版本号避免内核模块兼容性差异。容器运行时版本是否一致特别是containerd与K8s版本的兼容性矩阵差一个小版本都可能出现节点NotReady。GPU驱动与CUDA版本是否满足最低要求直接用nvidia-smi查看驱动版本确认和集群内其他节点一致。是否安装并配置好了GPU Device Plugin所需的软件包比如NVIDIA Container Toolkit保证容器内能访问GPU。网络通信是否打通特别是6443端口、Pod网段和Service网段之间的路由规则。体检通过之后再用标准的节点加入命令把机器接进集群。这一步不追求快追求的是把每个节点的规格信息、GPU型号、显存大小都登记清楚后面分配算力才有依据。2.2 GPU池化和节点打标签让调度器知道每张卡在哪节点加入集群后需要给节点和GPU打好标签否则按项目组分算力的时候完全没法精准匹配到卡片。我的标签体系大概长这样gpu-type: 按GPU型号标记比如一个项目组如果专门做推理可以限定只用某种推理卡。gpu-node-group: 标记节点属于哪个资源池比如“项目A专用池”、“共享池”。storage-class: 标记该节点能够访问的存储类型比如本地盘、高性能共享盘、普通共享盘。maintenance: 标记节点是否处于维护状态避免调度器往上面派新任务。标签不只是给人看的更是给调度器和资源配额用的。后续在CubeStudio资源组配置里可以直接通过nodeSelector来处理也可以配合亲和性做更细的调度策略。这一步如果偷懒后面项目组之间的算力隔离就是一句空话。2.3 多机版反复踩坑的四个问题节点加进来之后不等于一切就自动好用了。实际用下来高频出问题的通常集中在以下几个方面GPU卡在一台机器上只有一部分被识别。原因是节点上残留旧版驱动或Device Plugin版本不对导致K8s上报的可用GPU卡数不准确。处理方法是卸载旧驱动重装统一版本的驱动和插件并重启kubelet。不同节点GPU型号混用任务被调度到不对的卡上。解决办法是给节点打gpu-type标签并在任务模板里显式声明需要的GPU类型。新节点一直陷入NotReady状态。多数原因是容器运行时和kubelet配置不一致或者节点时间偏移过大。我遇到一次很诡异的情况是其中一台机器时钟慢了三分钟直接导致证书校验失败。共享存储没有挂到新节点上。很多GPU任务要读取同一个数据集目录如果新节点没有挂载共享存储训练一开始就会报“目录不存在”的错误。体检清单里必须加入存储挂载检查。多机阶段能做到的事情是算力池有了多个项目可以同时提交任务GPU利用率开始回升。但这个阶段还无法解决“多个项目组互相抢资源”的问题所以下一步要上多集群。3. 多集群纳管实操一个控制面管住所有业务集群多机解决的是“机器的横向扩展”而多集群解决的是“故障域与租户隔离”。当不同项目组对稳定性、安全要求不一致时把所有任务放同一个集群里风险太大。比如一个做对外API推理服务的组如果和一个大量跑批训练实验的组混在一起一个资源争抢或者一个故障都可能互相拖累。3.1 中心管控集群与业务集群的分工我的方案是把系统分成一个“中心管控集群”和若干个“业务集群”管控层不跑GPU任务只做三件事维护全局的用户、项目组、资源组定义。维护与每个业务集群建立信任关系的配置信息。把用户在界面上发起的算力申请翻译成具体业务集群上的工作负载。业务集群则专注于跑任务每个集群有自己独立的K8s API Server、etcd和资源配额。这样的好处是如果某个业务集群因为网络分区或者etcd抖动出问题其他集群完全不受影响。为了把这套关系落地我在CubeStudio里为每个业务集群注册了一个“集群身份”包括集群名称、API Server地址、验证用的证书或Token信息。注册完成后还要为每个业务集群配置允许被纳管的Namespace范围避免业务集群中出现不受管控的角落。3.2 集群注册与统一视图的搭建步骤如果你手里有一套现成的多套K8s集群想要让CubeStudio把它们的资源统一汇聚起来步骤大概是这样的在中心管控集群上安装多集群纳管组件并生成一个用于身份认证的加密配置。登录目标业务集群把对应的只读或管理权限的授权配置安装进去注意权限范围不要给到整个cluster-admin最好限制到指定Namespace。在CubeStudio的管理界面里填写业务集群的API Server地址和授权配置测试连通性。连通后将业务集群里的节点、GPU卡、已分配资源等数据同步到统一视图里让管理员在同一个面板上看到所有集群的实时状态。为每个业务集群设置默认的资源组映射关系说明该集群主要服务于哪些项目组。这里有个非常关键的细节授权配置中的证书与Token一定要设置有效期和自动轮换机制。我之前一次“多集群任务突然全部调度失败”的排障最后发现是一个业务集群的访问Token过期了而监控面板上没有报错只显示“该集群不可用”。排查过程中浪费了大量时间去检查网络和调度器。自从加上自动轮换后这个问题就再没出现过。3.3 跨集群调度应该做到什么程度很多人在多集群纳管后会立刻想“能不能把一个任务同时调度到多个集群”。我的建议是分阶段第一阶段先做到“一个任务在一个集群里跑但可以由管理员手动指定或系统自动选择集群”第二阶段才去做跨集群的GPU池化调度比如某个集群资源不足时自动把新任务调度到另一个集群。第一阶段的实现方式比较简单在任务模板里增加clusterSelector字段CubeStudio会根据集群标签和当前负载来决定投递到哪个集群。第二阶段由于涉及数据分布、文件系统访问延迟、跨集群网络带宽等问题复杂度高很多如果你没有特别强的平台团队不建议一开始就全量铺开。我自己在第二阶段尝试了一段时间发现跨集群调度最大的开销不是调度本身而是数据同步。两个集群如果不在同一个网段而且没有共享存储跨集群跑任务时数据集要先拷贝过去训练中产生的checkpoint还要定期同步回来时间和带宽消耗都非常大。所以我的折衷方案是**业务集群成对绑定一个共用的存储池只有同一存储池内的集群之间才开启跨集群调度。**这样既避免了大规模数据搬迁又能在单集群故障时快速切换。多集群纳管解决的是“多个环境统一管理”的问题。但到了这一步各个项目组虽然在物理和逻辑上被分到了不同集群却缺少统一的“项目组—资源组—配额”的业务语义。下一步需要把按项目组分算力的规则落地。4. 按项目组分算力实操从“资源池”到“资源组”这是整个改造里业务价值最直接、也最容易踩坑的一环。可以理解为算力池是一大堆GPU卡的物理集合但不同项目组不能无差别地从这个池子里领资源。资源组就是给这个池子画上“归属线”和“限额线”。4.1 资源组建模项目组、配额、优先级三层关系我在设计资源组时参考了K8s自带的Namespace ResourceQuota RBAC的经典组合但在上面加了一层CubeStudio的资源组概念来承载“按项目组分算力”的业务逻辑。三层关系大概是这样层级对应实体作用项目组比如算法一组、算法二组、推理服务组确定用户属于哪个业务团队有多少人、预算如何资源组一组GPU规格和数量的配额确定该团队最多能占用多少算力有哪些调度策略调度策略优先级、抢占、排队规则确定繁忙时谁先谁后哪些任务可以被挤掉项目组和资源组之间是多对多的关系一个项目组如果有多个资源组可以分别用于“日常训练”、“紧急任务”、“高优推理”等不同场景。我自己的项目里为每个项目组分配了至少两个资源组一个常规训练组用比较便宜的共享GPU卡一个高优任务组用性能更强的卡且优先级更高。4.2 配额计算和设置方法配额设计不能拍脑袋。每个项目组真正需要的不是“几张卡”而是“几个并发任务”和“每个任务占用多少卡/显存”。我通常按下面的公式估算并发任务数 同时进行实验的算法工程师人数 × 每人的典型并行实验数比如算法一组有8个人平均每人会同时跑2个训练任务那么并发任务数就是16。如果每个任务要用1块32GB显存的GPU卡那么这个项目组的资源组配额就应该至少设置为16卡。实际配置时我会再留20~30%的余量应对突发实验和抢卡高峰。具体到K8s层面的落地我用ResourceQuota来限定每个项目组的资源上限用LimitRange来约束单Pod的资源大小同时用PriorityClass标记任务优先级。这样配置完成后高优任务会在资源紧张时优先调度低优任务的Pod则可以被轻易抢占保障核心业务不被实验任务拖垮。4.3 项目组之间的亲和性与反亲和避免互踩按项目组划分算力之后还有一个非常容易被忽略的问题不同项目组的Pod被调度到了同一台物理机上导致显存和带宽互相抢。比如A组和B组的任务都落在同一张GPU物理机上A组跑一个大模型训练显存占掉大半B组其他任务就被挤到OOM边缘。解决方案是给每个项目组的Pod配置反亲和性规则让同一项目组的不同Pod尽量分散到不同节点不同项目组的Pod尽量避开同一台GPU服务器。具体做法是通过Pod的反亲和和节点选择器来组合实现。但需要注意的是反亲和规则不能配置得太死否则在GPU资源紧张时调度器可能找不出任何满足条件的节点导致任务长时间处于Pending状态。一个实用的折衷办法是先把同一项目组的训练任务用软反亲和能分散就分散分散不了也能接受用调度器自带的binpack策略兜底。4.4 算力分配中的“优先级抢占”玩法除了配额和亲和性真正的算力保障还要靠优先级抢占。CubeStudio的任务调度器里上层有多个PriorityClass。我的配置是这样的高优推理服务PriorityClass值最大几乎不参与抢占。紧急实验任务优先级中等排队时间超过一定阈值可以抢占低优任务。普通批训练任务优先级最低适合跑超参数搜索、模型评估这类不需要即时返回的作业。实际流量高峰期出现过几次“低优任务直接被杀掉”的事件后来我在任务模板里增加了checkpoint和中断恢复的机制保证被抢占的低优任务可以在换一台空闲机器后继续跑不丢失关键轮次的状态。这个点对团队体感影响巨大——用户不在乎被抢占在乎的是被抢占之后我的实验进度还能不能续上。到这里多机、多集群、多资源组的部署路径已经全部走通。下面进入验收和排障阶段把整个系统压到真实负载下验证并整理一套可以随时查“旧账”的记录册。5. 部署后的验收清单、排障实录与最佳实践部署完成后不要急着向团队宣布“算力平台升级完毕”。多机的稳定性、多集群的可靠性、资源组的隔离性都必须用任务打一打、用异常场景压一压才能真正信得过。5.1 验收清单能不能跑通才算数我自己做验收时会走一套固定清单像体检一样跑一遍多机验收分别在多台不同GPU节点上提交不同类型任务确认调度器能把任务分布到不同节点且GPU利用率有监控数据产出。多集群验收在管理中心发起一次“跨集群手动调度”把一个训练任务从集群A指派到集群B确认数据读取、任务启动、日志回流均正常。资源组验收为某个项目组设置一个极小的配额提交超过配额的任务确认超出部分被拒绝或排队且有清晰的中文提示。隔离性验收模拟某个业务集群网络不可用确认中心管控面板能快速标识该集群异常其他集群任务不受影响。存储验收在某个集群上删除并重新创建一组任务确认数据集和模型权重能从共享存储里稳定拉取不会出现数据不一致。验收过程中我最常看到的状态是“所有组件都正常但任务就是跑不动”。这时候不要慌先把时间花在检查调度器是不是因为某个资源组根本没有匹配的节点而无法调度。5.2 高频问题排查速查表把过去遇到的常见问题整理成了一张速查表特别适合大家在排障时快速定位症状大概率原因快速处理任务一直Pending资源组配额不足或节点标签不匹配调度条件查看任务详情里的节点选择条件先扩容或改标签Pod提示GPU不可用GPU Driver或Device Plugin版本不一致检查节点GPU上报数重装统一版本插件跨集群调度失败访问Token过期或网络策略拦截检查集群身份授权有效期刷新Token资源组配额不生效项目组与资源组绑定关系没配好核对项目组所属资源组在管理界面重新绑定节点显示NotReady容器运行时与kubelet配置不一致或时钟偏移对比节点参数同步时间和配置不要指望一次排障就能根治所有问题。我建立了一个“问题日志记录本”每次排障完把现象、根因、解决过程简要记录进去。后面再遇到类似情况翻记录的效率远高于现场重新看日志。5.3 三条最佳实践从能用到好用有几个经验属于“不做也行但做了以后会省很多事”的级别我单独拿出来讲一下。第一给每个资源组配置“容量水位告警”不要等任务大批量排队之后才发现资源不够。我在监控面板配置了三个档位资源使用率超过70%时提示后续任务可能排队超过85%时发出通知95%以上时触发紧急告警。这个做法能让你在用户抱怨之前就提前扩容。第二多集群场景下优先保证“控制面可以一定范围内的不可用”但绝不接受“数据面被打满导致互相拖累”。具体实操上我把网络策略严格限制在“业务集群内部”和“业务集群到存储池”两个方向禁止业务Pod之间跨集群互访从规则层面杜绝了因为网络流量互相干扰引发的稳定性问题。第三存储上的目录规划要提前统一。很多团队在单机阶段并不在意目录结构各自在本地盘上随意放数据。多机多集群后数据如果分散在各节点本地盘任务调度到其他节点就必然读不到数据。我最终定下的规范是所有数据集、模型、日志统一放到共享存储节点本地盘只放临时文件和缓存。这个规范在部署阶段没有强制推行后来靠数据迁移和任务报错教育了所有人。最后再分享一个经验折腾完整个系统后我最大的体会是多机、多集群、多资源组本质上是一套“算力供给系统”的三个切面它们之间不能割裂考虑。很多时候问题出在“你先做了多机等资源不够了才想到多集群最后才做资源组”结果各种组件东拼西凑每个功能都是后来打补丁加上去的权限关系和调度逻辑乱成一团。如果重新来一次我会先花一天把项目组边界、资源组配额关系、集群之间的信任模型全部画出来哪怕简单画在纸上也比直接上手部署要靠谱得多。后续真正的操作反而顺理成章毕竟解决方案已经清晰了剩下的不过是按图索骥。如果你正在规划单机向多机多集群演进我的建议是不要贪多求全先把“多机资源组”做扎实再在此基础上叠加“多集群”。每一步都确认稳定后再往下一个形态推进你会省下大量返工的时间。