1. 先别急着加机器,先清楚单机、多机、多集群、多资源组的关系
很多人第一次接触 CubeStudio 时,都以为它只是某个节点上的一个服务,装在一台 8 卡机器上就够了,先把单机用起来,后面不够再加机器。这个思路本身没有错,但等你真的把单机跑起来,模型变多、项目组变多、算力开始抢的时候,才会发现“单机部署”不是一个安装选项,而是整套调度逻辑的边界。
这篇内容我不讲 CubeStudio 的入门安装,直接讲从单机扩成多机、再纳管多个 K8s 集群、最后按项目组切成多个资源组的完整过程。所有操作都是实际踩过坑之后的复盘,命令、参数、配置基本都是可以直接抄的。
1.1 单机部署到底卡在哪
单机部署典型场景是一台 8 卡 GPU 服务器,里面同时运行了 Kubernetes 控制面、CubeStudio 平台服务、训练任务 Pod、开发机 Pod。听起来好像也没啥问题,K8s 本来就能在同一节点上跑控制面和业务 Pod。
但实际跑起来你会遇到几个很现实的问题。
第一,控制面容错为零。这台机器只要一重启,kube-apiserver、etcd、CubeStudio 控制台全部一起挂,训练任务也得跟着等恢复。节点磁盘一旦被打满,整个平台直接不可用,连排查问题的入口都进不去。
第二,资源竞争非常隐蔽。GPU 卡看起来是够用的,但训练任务吃 CPU、吃内存,跑数据预处理时经常把整台机器 CPU 打满,导致 CubeStudio 的 Web 页面响应慢,调度器调度也慢。单独给平台服务预留资源又觉得浪费,不预留又天天被业务拖垮。
第三,没有容灾。单机模式下,所有数据都在本地盘,节点硬盘坏了,模型代码、训练产物、数据库全没了。很多团队第一版部署根本不装分布式存储,因为单机嘛,本地盘够用。一旦决定扩容,存储问题一定是第一个跳出来找你的。
所以我的建议很直接:如果你已经开始讨论“要不要加第二台机器”,说明单机已经不适合继续撑下去了。这时候不是简单再加一台机器,而是要把 CubeStudio 的部署架构从“单机模式”切换到“控制面与算力分离模式”。
1.2 多机、多集群、多资源组,解决的是三层问题
这三者的关系很容易混,我的理解是它们各自解决一个层面。
多机解决的是“单集群内算力不够”的问题。一个 K8s 集群里加 worker 节点,GPU 总量变大,调度器可以把任务分配到不同物理机。这是最基础的横向扩展。
多集群解决的是“安全边界和故障爆炸半径”的问题。网络隔离、环境隔离、权限隔离,不同的部门或不同的业务线可以各自拥有一套 K8s。CubeStudio 作为控制台,把多个集群的 API Server 接到同一个界面里,用户不需要关心任务到底落在哪个集群,管理员也不需要记住每个集群的 kubeconfig。
多资源组解决的是“算力怎么分给不同项目组”的问题。同一套 K8s 集群里,有算法一组、二组、平台组,还要区分训练资源、开发资源、测试资源。资源组本质上是把物理 GPU 总量切块,每一块有独立配额、独立命名空间、独立权限,谁也别想抢谁的。
多机是物理扩容,多集群是逻辑隔离,多资源组是配额治理。这三层正好对应从小到大、从粗到细的管理粒度。
1.3 我建议的扩张顺序
别一上来就搭五个集群、二十个资源组。扩张顺序应该是:
- 先把单机扩成多机,把算力池做大,验证多节点调度和存储共享。
- 再把第二个、第三个 K8s 集群纳管进来,验证多集群管理和镜像同步。
- 最后才引入资源组,按项目组切配额,做账权和权限治理。
我见过一个团队,第一次部署就直接上多集群多资源组,结果前面两周全部在排查“为什么 Pod 调度不到期望的集群”“为什么配额限制了还是能创建 Pod”。原因就是底层多机和多集群的基础还没磨合一,上来就搞高层抽象,出问题根本没法定位。
2. 多机部署实操:把 CubeStudio 的底座从 1 个节点变成 N 个节点
2.1 节点角色划分与硬件选型
多机部署后,角色必须分开。CubeStudio 本身对硬件要求不高,它是控制面服务,真正消耗 GPU 的是训练任务和开发机 Pod。
我建议的划分方式是:
- 平台控制节点至少 1 台,不需要 GPU,16 核 32G 内存就够,跑 etcd、kube-apiserver、CubeStudio 服务端。
- GPU 工作节点按需扩展,每台 4 卡或 8 卡,最好是同型号同配置的 GPU 卡。如果预算有限,一个集群内 GPU 型号尽量统一到一到两种,不然后面做资源池划分会非常麻烦。
- 存储节点单独规划,不能用某台 GPU 服务器的本地盘承担全部数据。初期可以用 NFS,量大之后换成 Ceph 或托管存储。
如果是从已有的单机开始改,这台机器可以直接当平台控制节点,但要把 GPU 卡从控制面上剥离开。后面我会说怎么用 taint 和 label 实现。
2.2 把新节点加入集群并隔离控制面
假设你已经有一台单机节点,上面跑着 kubeadm 初始化的单节点集群。现在要把另外两台 GPU 机器加进来。
先在控制节点上执行:
kubeadm token create --print-join-command然后到新节点上执行输出的 join 命令。默认情况下,新节点加入后会成为普通 worker 节点,控制节点会被自动打上node-role.kubernetes.io/control-plane标签,并且带有 taint。
关键一步是确认控制节点上的 taint 是存在的,否则训练 Pod 可能被调度到控制节点上,挤占平台服务资源。
kubectl get nodes kubectl describe node <控制节点名> | grep Taints如果没有 taint,手动加上:
kubectl taint nodes <控制节点名> node-role.kubernetes.io/control-plane=:NoSchedule接下来给 GPU 节点打标签和污点,方便后面按资源组调度:
kubectl label node gpu-node-01 gpu-node=true kubectl taint nodes gpu-node-01 gpu-reserved=true:NoSchedule这个 taint 的意思是默认不调度普通任务到这台机器,只有显式声明了 toleration 的任务才能调度进来。这个机制后面在做资源组隔离时会用到。
2.3 网络、存储要在一开始就分开处理
多机部署后,最容易被忽略的就是 CNI 网络插件的选择和 Pod 网段规划。
单机模式你用什么网络插件都行,反正都在一个节点上。多机之后,Calico 和 Cilium 是首选,不建议用过于简单的 VXLAN 模式,因为 GPU 机器之间经常要跑分布式训练,跨节点通信量大,走 VXLAN 封装会带来明显性能损耗。我实测过,在 40G 内网环境下,Calico 直接路由模式和 VXLAN 模式的带宽差距能到 20% 以上。
Pod 网段也要提前规划。这里有个很常见的坑:公司内网分段如果比较碎,比如 10.10.0.0/24、10.11.0.0/24 这种,那 Pod 网段一定不要选 10.10.0.0/16 或者 10.11.0.0/16,很容易和物理网络冲突。我一般用 172.16.0.0/16 作为 Pod 网段,Service 网段用 10.96.0.0/12,这样和绝大多数局域网不冲突。
存储这件事我强调很多次,是因为在单机扩多机的过程中,它是最让人难受的一步。如果之前训练数据都放在单机本地,扩成多机后,新节点上根本没有这些数据。最省事的短期方案是搭一个 NFS 共享,把所有数据和代码放在 NFS 上:
apt install nfs-kernel-server nfs-common在存储节点上配置导出一块路径,比如/data/nfs,然后所有 GPU 节点挂载到相同目录。CubeStudio 侧配置默认存储类指向 NFS 的 provisioner,保证 PVC 在多节点间漂移时仍然能挂载。
多机环境下千万别继续用local-path-provisioner,除非你非常清楚每个任务的存储亲和性。开发机在节点间迁移后,本地盘数据就丢了,这是多机部署中用户反馈最多的问题。
2.4 验证多机调度:Pod 落点、GPU 资源和资源组
节点全部加入后,先检查每个节点的 GPU 资源是否被 kubelet 正确上报:
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, gpu: .status.allocatable}'如果节点安装了 NVIDIA 驱动和 device plugin,你会看到类似nvidia.com/gpu: "8"的输出。如果没有这个键,说明 device plugin 没装好,或者驱动不识别。
之后在 CubeStudio 里创建一个开发机,选择资源组(这时候可能只有一个默认资源组),在 Pod 运行后确认落点:
kubectl get pods -A -o wide | grep <开发机名字>正常情况下 Pod 会被调度到某个带 GPU 的 worker 节点上,调度器不会让它落在平台控制节点。
记住一个经验:多机模式下“能不能调度”看 taint 和 toleration,“愿不愿意调度”看 label 和 nodeSelector,“调度到哪一台”看调度器的打分逻辑。这三件事别混在一起查,否则会浪费时间。
3. 多集群纳管实操:一个 CubeStudio 控制台管理多套 K8s
3.1 需要多集群的三个典型信号
不是每个团队都需要多集群,下面三个信号出现了,就应该考虑多集群纳管。
第一,同一个 GPU 集群里塞了训练、测试、推理等不同环境,且这些环境之间要求严格隔离。有些公司因为审计要求,开发环境和生产环境的 Pod 不能共用一个 K8s,这时候物理隔离比 namespace 隔离更让人放心。
第二,集群规模接近 Kubernetes 的管理上限。虽然 K8s 官方说一个集群可以跑几千个节点,但 etcd、API Server 的压力会非常大。我见过一个集群跑到 600 个节点、大量 GPU Pod 反复调度后,etcd 的延迟从几毫秒涨到几百毫秒,整集群都开始慢。这种时候拆分集群比优化 etcd 参数划算。
第三,跨地域或者跨机房。不同机房之间延迟高,Pod 调度跨机房跑分布式训练几乎不可接受。最合理的做法是每个机房独立一套 K8s,CubeStudio 控制台集中纳管,任务按机房标签调度。
3.2 为每个集群准备最小化纳管凭据
CubeStudio 纳管集群的核心其实是 kubeconfig。只要平台能通过 kubeconfig 访问目标集群的 API Server,它就能往下分发任务、创建 Pod、管理资源组。
但我强烈不建议你把自己本地的管理员 kubeconfig 直接填到平台里。正确做法是为平台账号创建一个独立的 ServiceAccount,赋予它需要的 RBAC 权限。
假设要纳管一个叫cluster-b的集群:
kubectl create namespace platform-system kubectl create serviceaccount cube-admin -n platform-system kubectl create clusterrolebinding cube-admin \ --clusterrole=admin \ --serviceaccount=platform-system:cube-admin拿到 token:
kubectl -n platform-system create token cube-admin --duration=8760h然后用这个 token 拼接一个只对平台使用的 kubeconfig。线上环境建议在 CubeStudio 控制节点上单独存放这个 kubeconfig,不跟着平台页面到处复制。
注意:
create token创建的 token 有时效,生产环境要么配置自动续期,要么使用长期 Secret 中的 token。过期后表现就是集群在控制台里显示“连接失败”,但不会影响已经运行的 Pod。
3.3 在 CubeStudio 里注册集群并建立统一标签体系
在 CubeStudio 的管理页里,注册集群其实就是填入三样东西:集群名字、API Server 地址、kubeconfig 文件。
这里有一个容易被忽略的地方:集群标签。注册集群时,一定要给集群打上统一的标签,比如region=hz、env=prod、gpu-type=a100。因为后面建资源组、选集群时,平台大多依赖标签做过滤和匹配。
我建议的命名规范是:
- 集群名:
{业务}-{环境}-{序号},例如training-prod-01。 - 资源组名:
{部门/项目}_{用途},例如algo1_train、algo2_dev。 - 集群标签:统一用
region、env、tier三个维度。
namespace 的命名和资源组名保持一致,因为在 K8s 层,一个资源组通常就是一个 namespace。命名中间带下划线其实会有点麻烦,我踩过坑,最后统一改用中划线:algo1-train、algo2-dev。K8s 资源名只允许小写字母、数字和中划线,下划线会报错。
3.4 多集群下的调度归属、镜像和存储策略
纳管多个集群之后,用户创建训练任务时,平台怎么决定任务跑到哪个集群?
我建议的规则是:用户不直接选集群,而是选资源组。一个资源组绑定一个集群,这样用户在界面上看到的还是“资源组”这个抽象概念,底层集群是谁对用户是透明的。管理员只需要保证资源组和集群的映射正确。
镜像仓库也要跟着多集群一起改。如果多个集群都在同一个内网,共用一个 Harbor 没问题。一旦跨机房,我会在每个集群里部署一个 registry mirror,先拉镜像到本地,再创建 Pod。否则跨机房拉镜像会非常慢,尤其镜像有几个 GB 的时候。
存储层面,多集群之间如果不共享 NFS,那同一个项目的数据就要考虑同步。最简单的做法是让每个集群挂在同一个对象存储桶上,训练数据通过对象存储读写。如果一定要做跨集群实时共享文件,成本会很高,建议不要轻易尝试。
4. 按项目组分算力:多资源组的原理和配置
4.1 资源组的本质:Namespace + Quota + RBAC
资源组不是一个 K8s 原生对象,而是组合出来的概念。在 CubeStudio 里,一个资源组对应到 K8s 通常是这几样东西的组合:
- 一个独立 Namespace,隔离 Pod、PVC、ConfigMap 等资源。
- 一份 ResourceQuota,限制这个 namespace 能用的 CPU、内存、GPU 总量。
- 至少一个 LimitRange,给每个容器设置默认的资源请求和限制。
- 一套 RBAC 绑定,让对应项目组的用户只能操作自己资源组内的对象。
这个组合关系想清楚之后,排错会非常容易。比如“任务创建失败”但看不到错误信息,先看 ResourceQuota 是否满了;比如“用户能看见别的项目组的 Pod”,先查 RoleBinding 绑定的 namespace 对不对。
创建资源组的最小集,先手动创建 namespace:
kubectl create namespace algo1-train然后对这个 namespace 打上标签,方便 CubeStudio 识别:
kubectl label namespace algo1-train cube.resource-group=algo1-train4.2 配额怎么设计才合理:先算物理账,再算项目账
很多管理员在配额上翻车,是因为拍脑袋定数字。比如两个项目组,一个给 32 卡,一个给 32 卡,结果物理机上总共只有 40 卡,必然有一边创建任务时反复失败。
正确的做法是先盘物理硬件的总账,再按项目优先级切块。
假设一个集群有三台 8 卡 A100 机器,总共 24 张 GPU,单卡显存 80G,每台机器 CPU 是 64 核、512G 内存。
物理账:
| 资源项 | 总量 |
|---|---|
| GPU 卡数 | 24 |
| vCPU 核数 | 192 |
| 内存 | 1536 GiB |
项目账:
| 项目组 | GPU 配额 | CPU 配额 | 内存配额 | 说明 |
|---|---|---|---|---|
| 算法一组 | 12 | 64 vCPU | 512 GiB | 主力训练组 |
| 算法二组 | 8 | 64 vCPU | 512 GiB | 日常训练 |
| 公共开发 | 4 | 64 vCPU | 512 GiB | 开发机、小实验 |
ResourceQuota 的配置示例:
apiVersion: v1 kind: ResourceQuota metadata: name: quota-algo1-train namespace: algo1-train spec: hard: nvidia.com/gpu: "12" requests.cpu: "64" requests.memory: "512Gi" limits.cpu: "128" limits.memory: "1Ti" configmaps: "100" secrets: "100" persistentvolumeclaims: "50"这里有几个细节要注意。
第一,nvidia.com/gpu是 NVIDIA device plugin 暴露的资源名。如果你用的是国产卡或者 vGPU 方案,资源名可能完全不同,要以kubectl describe node里显示的为准。
第二,配额里同时写 requests 和 limits。只写 limits 不写 requests,调度器在判断 Pod 是否超过配额时可能不符合预期。我只设置 requests.cpu 和 requests.memory,limits 稍微留多点,避免训练脚本里偶尔的内存抖动直接把 Pod 杀掉。
第三,configmaps 和 secrets 的配额很容易被忽略。训练代码里如果频繁更新配置,会不断生成新的 ConfigMap。配额的 ConfigMap 上限不设大一点,某天任务创建就会突然失败,而且报错信息非常隐晦。
4.3 资源组权限如何与平台用户体系绑定
配额是上半篇,权限是下半篇。资源组里需要有“谁能往里提交任务”的约束。
K8s 原生做法是在 namespace 里创建 Role 和 RoleBinding。由于 CubeStudio 有自己的用户体系,实际使用时有两种路径:
第一种,平台用户直接映射到 K8s 的 RBAC。这对接成本高,需要平台能向 API Server 冒充用户身份,或者给每个用户都生成单独的 ServiceAccount。
第二种,平台侧统一管理授权,底层集群用平台自己的高权限账号操作。资源组之间的隔离靠配额和 namespace 来实现,平台层再去限制用户能选择的资源组。
实操中第二种更常见,公司内部平台嘛,用户本来就在 CubeStudio 里登录,平台再绑定“用户组-资源组”关系即可。但如果你们有合规审计要求,必须做到 Pod 级别的用户权限隔离,那就得走第一种,给每个用户组建独立的 ServiceAccount 和 kubeconfig。
4.4 配额超过之后会发生什么:实战现象
配额这东西,配置之后一定要测一下,不然等到高峰期才发现问题就晚了。
我实测创建一个超过配额的 Deployment,K8s 不会直接拒绝 Deployment,而是会创建一个 ReplicaSet,但 Pod 永远处于 Pending 状态。kubectl describe pod能看到这样一段:
0/3 nodes are available: 3 Insufficient nvidia.com/gpu.如果配额命中,事件里通常会有:
exceeded quota: quota-algo1-train, requested: nvidia.com/gpu=2, used: nvidia.com/gpu=12, limited: nvidia.com/gpu=12这两种现象完全是不同层面的问题。前者是节点上没有物理 GPU 了,后者是配额已经耗尽,但节点上可能还有资源。排查时先分清是哪种,不要一看到 Pending 就去加机器,结果机器加了任务还是 Pending。
我还建议加一个 LimitRange,给资源组内的容器一个默认的资源约束:
apiVersion: v1 kind: LimitRange metadata: name: limit-range-algo1-train namespace: algo1-train spec: limits: - type: Container default: cpu: "8" memory: "32Gi" defaultRequest: cpu: "2" memory: "8Gi" max: cpu: "64" memory: "256Gi"没有 LimitRange 的情况下,用户创建 Pod 时不写 resources 字段,ResourceQuota 是管不住的,任务会直接使用节点剩余所有 CPU,造成干扰。
5. 完整落地案例:两个集群、三个资源组、一个控制台
5.1 案例背景与物理资源
用一个实际案例把整条链路串起来。
假设现在的环境如下:
- 平台控制节点一台,安装 CubeStudio。
- 集群 A:训练集群,4 台 8 卡 A100 GPU 节点,总共 32 卡。
- 集群 B:推理集群,2 台 4 卡 A10 GPU 节点,总共 8 卡。
- 目标:两个集群都纳入一个 CubeStudio 控制台,按项目组分三个资源组。
资源组规划:
| 资源组 | 目标集群 | GPU 配额 | 定位 |
|---|---|---|---|
| algo1-train | 集群 A | 16 卡 | 算法一组训练 |
| algo2-train | 集群 A | 12 卡 | 算法二组训练 |
| service-infer | 集群 B | 6 卡 | 在线推理服务 |
剩余 4 卡 A100 和 2 卡 A10 作为总余量,不要让任何资源组吃满物理资源。
5.2 步骤一:注册两个集群并打标签
在平台管理页的“集群管理”中,分别上传两套 kubeconfig,然后给集群打上标签:
集群 A: name: training-cluster-a labels: region: hz env: prod tier: train 集群 B: name: inference-cluster-b labels: region: hz env: prod tier: infer这一步操作本身不难,难在标签规范要提前定好。注册完成后,在控制台里能看到两个集群的节点数、GPU 总量和健康状态。
5.3 步骤二:创建三个资源组及配额
这里要做一个关键动作:资源组和集群绑定。algo1-train和algo2-train绑到集群 A,service-infer绑到集群 B。
在集群 A 上创建第一个资源组:
kubectl create namespace algo1-train kubectl label namespace algo1-train cube.resource-group=algo1-train然后应用上一节写好的 ResourceQuota 和 LimitRange,把 GPU 配额设成 16。
第二个资源组照做,配额 12。集群 B 同理,但 GPU 资源名要确认是nvidia.com/gpu还是别的,A10 机器如果也装了同一套 device plugin,资源名应该是一致的。
创建完成后,在平台资源组列表中应该能看到三个资源组并列展示,并且各自的集群标签不一致。用户创建任务时选择不同资源组,调度目标就完全不同。
5.4 步骤三:提交训练任务并确认调度结果
在 CubeStudio 的任务创建页面,选择algo1-train资源组,选择一个 GPU 类型的镜像,提交后马上在节点上确认:
kubectl get pods -n algo1-train -o wide正常情况下 Pod 会落在集群 A 的某个 A100 节点上。你也可以用:
kubectl get pod <任务名> -n algo1-train -o json | jq '.spec.nodeName'拿到具体节点名后,用kubectl describe node看该节点上 GPU 使用量:
kubectl describe node <节点名> | grep -A5 "Allocated resources"如果 Pod 跨到了集群 B,说明资源组绑定有问题,及时检查平台侧的资源组-集群映射,不要继续往下走。
5.5 步骤四:验证配额限制和故障转移
验证配额最简单的方式是手动创建一个超过 16 卡的训练任务。如果资源组配额生效,Pod 会 Pending,并且事件里出现exceeded quota。把这个现象记录到平台 FAQ 里,后续用户再遇到不会慌。
故障转移的验证更有意义。先把集群 A 的某个 GPU 节点kubectl drain掉,模拟机器维护,然后再次提交algo1-train任务。只要配额没满,任务应该调度到集群 A 里其他的 GPU 节点,而不是直接失败。
多集群的容灾在多机之上又容易一层。比如集群 B 挂了,service-infer资源组的所有任务都会失败,但在 CubeStudio 控制台里,其他集群的任务仍然正常运行。这就是多集群隔离的好处:故障爆炸半径被限制在一个集群内,不会全平台瘫痪。
6. 常见问题与避坑实录
6.1 多机后 GPU 驱动不一致导致 Pod 反复 Crash
这是多机部署最容易遇到的第一坑。所有节点的 NVIDIA 驱动版本、CUDA 版本、Container Toolkit 版本不一致时,GPU Pod 经常会启动成功但立即退出,查看日志是:
could not select device driver "" with capabilities: [[utility]]原因就是设备插件上报的资源名存在,但容器运行时无法获取 GPU。解决办法是统一所有节点的驱动版本,并且确认每个节点上都装了 nvidia-container-toolkit:
nvidia-smi nvidia-container-cli info每个节点执行,确保输出正常后再部署 device plugin。别在一号机调好了,二号机只看了一眼 nvidia-smi 就以为没问题,nvidia-smi能显示驱动不代表容器里能用 GPU。
6.2 kubeconfig 过期后资源组全部变灰
纳管集群用的 ServiceAccount token 有时效,过期后整个平台界面里所有绑定到该集群的资源组全部不可用,但已运行的 Pod 不会中断。你能在平台上看到“集群连接失败”。
尽快创建新的 token 并替换 kubeconfig:
kubectl -n platform-system create token cube-admin --duration=8760h为了避免反复踩坑,建议用 Kubernetes 的长期 Secret。创建 ServiceAccount 时手动把 token 写到 Secret 里,不设置自动过期。当然这带来了安全风险,所以只建议在受控内网使用。
6.3 ResourceQuota 误伤系统级任务
给资源组设置配额后,如果 CubeStudio 平台自身也在同一个 namespace 里创建辅助 Pod,比如临时清理任务、数据同步任务,这些也会被配额限制。结果就是用户任务没跑起来,平台的辅助任务先在 Pending。
解决方式:平台系统任务单独用一组命名空间,比如cube-system、cube-monitor,不要和资源组混在一起。如果你已经混了,马上搬家,不然后面每次扩容都得从配额 Pending 里猜为什么。
6.4 开发机调度漂移导致存储找不到
多机之后,开发机如果被调度到另一台 GPU 节点,之前节点本地盘上的代码就都看不到了。这是用户感知最强烈的问题之一。
临时对策是在开发机的 Pod 配置里设置 nodeAffinity,锁定某台机器,但这会让调度灵活性变差。长期对策一定是用共享存储,比如 NFS、CephFS,开发机挂载的是 PVC,PVC 底层是共享存储,这样任意节点都能起来,数据都在。
我在实际环境里见过最离谱的一次,用户手动把开发机删除重建,结果调度器把新开发机放到了另一台机器,用户的整个工作目录全没了,而本地盘数据其实还在旧节点上躺着。这种事情发生一次,团队对整个平台的好感度就没了。
6.5 多集群监控和日志怎么收敛
多个集群意味着多个 Prometheus、多个 Loki、多套 Grafana。最省心的做法是每套集群各自采集,CubeStudio 层面聚合展示,而不是把日志全部汇总到一个中心。
跨集群拉日志看着很爽,实际排错时延迟高、搜索慢、权限还难控。我实践下来的方案是每个集群独立保存 7 到 15 天日志,平台控制台跳转到对应集群的日志页面。用户查问题时,先选时间范围,再看到底哪个集群,最后打开那个集群的日志系统,链路清晰。
6.6 最重要的坑:资源组命名和目录规范
我把这个放在最后,因为它是唯一一个“开始没想好,后面改起来最痛”的问题。
资源组名字一旦被用户大量使用,就不能随便改。改了之后,用户的收藏链接失效、历史任务记录里的资源组显示乱套、权限绑定要全部重做。我开始时就吃了这个亏,第一批资源组叫“训练1组”“训练2组”,后来要接成本核算时发现根本没法按项目聚合,只能重新建资源组并迁数据。
请务必在一开始就定好命名规范。我的建议是:资源组名由“项目代号、环境用途、序号”三部分组成,全部用英文小写和中划线。比如:
- 项目代号:
algo1、algo2、nlp、cv - 环境用途:
train、dev、infer - 完整资源组:
algo1-train、algo1-dev、nlp-infer
同时把资源组和成本核算项目代号绑定。很多团队上来不关注这个,等到月底打开账单发现根本分不清哪笔算力是哪个项目花的,才意识到命名就是成本标签。
我个人在实际操作中的体会是,多机、多集群、多资源组这套体系,真正难的不是敲那几条 kubectl 命令,而是你先要有一个稳定的底座:统一的驱动、可靠的共享存储、成体系的命名规范。把这三件事做在前面,CubeStudio 从单机到多集群会非常顺。如果你正准备这么干,我给的建议是先扩多机,别急着上多集群;等你能把一个资源组的配额、权限、调度都玩明白了,再推第二个集群会轻松很多。