3. KubeRay CRD体系解析

KubeRay 把 Ray 的运行时形态抽象成一组 Kubernetes 自定义资源(CRD)。理解这套 CRD,本质上是在理解“谁负责创建 Ray 集群、谁负责提交作业、谁负责对外提供在线服务”这三个问题的边界。KubeRay 最常用的三个 CRD 是 RayCluster、RayJob 和 RayService,它们并非互相替代,而是覆盖了从“长期存在的算力底座”到“一次性批处理”再到“在线推理服务”的连续场景。

一、三个 CRD 的职责边界

RayCluster 是最基础的资源,它描述一个 Ray 集群的期望状态:Head 节点如何部署、Worker Group 有哪些、每组副本数与资源规格如何。它只负责“把集群拉起来并维持住”,不关心你在集群上跑什么。因此它适合作为共享算力池,被多个作业或服务复用。

RayJob 在 RayCluster 之上增加了“作业”语义。它既可以引用一个已存在的 RayCluster,也可以自己内嵌一个集群模板,由控制器按需创建集群、提交 entrypoint、等待结束,再根据 shutdownAfterJobFinishes 决定是否回收集群。它解决的是“提交一次、跑完即止”的批处理需求。

RayService 则面向在线服务。它同时管理一个 RayCluster 和一个 Serve 应用配置,通过 serveConfigV2 声明推理图(deployment、application),并借助零停机升级机制在旧集群与新集群之间切换流量。它适合模型推理、在线特征服务等需要长期可用、可滚动升级的场景。

KubeRay 三大 CRD 的职责与生命周期 RayCluster 长期算力底座 • headGroupSpec(Head 规格) • workerGroupSpecs[](副本/资源) • rayVersion / enableAutoscaler • 生命周期:创建 → 常驻 → 手动删除 适用:共享算力池、多作业复用 RayJob 一次性批处理 • entrypoint(作业命令) • clusterSelector / rayClusterSpec • shutdownAfterJobFinishes • 生命周期:创建 → 提交 → 完成 → 回收 适用:训练、数据批处理、CI 任务 RayService 在线推理服务 • serveConfigV2(应用图) • rayClusterConfig(集群模板) • upgradeStrategy(零停机升级) • 生命周期:创建 → 常驻 → 滚动升级 适用:模型推理、在线特征服务 可引用 可引用 KubeRay Operator 统一调谐 监听 CRD → 创建/更新 StatefulSet、Service、ConfigMap → 维持期望状态 RayCluster 是底座;RayJob 与 RayService 在其上叠加作业/服务语义 生命周期对比 RayCluster:常驻,手动伸缩/删除 RayJob:跑完即回收(可配置) RayService:常驻,滚动升级

二、字段结构的关键差异

三个 CRD 的字段设计直接反映了它们的定位。RayCluster 的核心是 spec.headGroupSpec 与 spec.workerGroupSpecs,前者定义 Head Pod 的模板、容器镜像、资源请求,后者是一个数组,每个元素包含 groupName、replicas、minReplicas、maxReplicas 和 template。当开启自动伸缩时,minReplicas 与 maxReplicas 才生效,控制器会依据 Ray 的 autoscaler 指标调整副本数。

RayJob 的关键字段是 entrypoint、runtimeEnvYAML、jobId、submissionMode 以及 shutdownAfterJobFinishes。submissionMode 可取 K8sJobMode 或 HTTPMode:前者把提交动作封装成 Kubernetes Job,适合与 K8s 原生调度配合;后者由 Operator 直接通过 Ray Dashboard 的 HTTP 接口提交,链路更短。若 shutdownAfterJobFinishes 为 true 且未引用外部集群,作业结束后 Operator 会删除自动创建的 RayCluster,避免资源空转。

RayService 的字段分为两半:rayClusterConfig 描述集群模板,serveConfigV2 描述 Serve 应用。后者是一段 YAML 字符串,内部包含 applications 列表,每个应用有 name、import_path、route_prefix 和 deployments。upgradeStrategy 控制升级行为,常用 type: NewCluster 配合 maxSurge,先拉起新集群、待其健康后再切流量、最后回收旧集群,从而实现零停机。

三、生命周期与状态机

RayCluster 的状态字段 status.state 会经历 Ready、NotReady 等阶段,并附带 head 与 workers 的就绪信息。它没有“完成”概念,除非被删除或缩容到零。

RayJob 的状态更丰富:status.jobStatus 会从 Pending 进入 Running,最终落到 Succeeded 或 Failed;同时 status.jobDeploymentStatus 记录集群准备与提交阶段。排查时先看 jobDeploymentStatus 是否卡在 WaitingForCluster,再看 jobStatus 是否已进入 Running,能快速区分“集群没起来”和“作业本身失败”。

RayService 的状态包含 activeServiceStatus 与 pendingServiceStatus,分别对应当前承载流量的集群和正在升级的新集群。当新集群的 Serve 应用健康后,二者角色互换,旧集群被清理。观察 status.conditions 中的 Ready 与 UpgradeInProgress,可以判断服务是否处于可用状态。

四、选型建议与常见误区

选型可以遵循一条简单原则:需要长期复用、多个作业共享同一套算力,选 RayCluster;一次提交、跑完即止、希望自动回收,选 RayJob;需要对外暴露 HTTP 接口、要求滚动升级不中断,选 RayService。

常见误区有两个。其一,用 RayJob 内嵌集群模板跑长周期服务,作业结束后集群被回收,服务随之中断;正确做法是改用 RayService 或让 RayJob 引用一个常驻的 RayCluster。其二,把 RayService 当成普通 Deployment 使用,忽略 serveConfigV2 中 route_prefix 与 deployments 的对应关系,导致请求 404。建议在提交前用 kubectl get rayservice -o yaml 核对 activeServiceStatus 中的路由与副本数,确认与预期一致后再接入流量。

实践提示:调试 RayJob 时,可先设置 shutdownAfterJobFinishes: false 保留集群,待确认作业逻辑无误后再改为 true 启用自动回收,避免反复重建集群带来的等待。