Ray 已经成为 AI Infra 和 MLOps 场景中常见的分布式计算框架。它可以承载离线训练、批处理、强化学习、在线推理以及 Ray Serve 服务。与此同时,越来越多团队也已经把计算资源、任务调度、权限隔离、监控告警和日志系统统一到了 Kubernetes 上。
这带来一个自然的问题:如何在 Kubernetes 上稳定运行 Ray?
如果只是启动一个 Ray 集群,方式有很多;但如果要在生产环境长期运行 Ray,需要解决的问题远不止“Pod 能不能起来”。平台团队还要关心集群生命周期、任务提交、服务升级、弹性伸缩、故障恢复、权限边界、日志指标和历史追踪。KubeRay 的价值就在这里:它把 Ray 的集群、任务和服务抽象成 Kubernetes 原生资源,让 Ray 可以进入 Kubernetes 的声明式运维体系。
从生产实践看,KubeRay 的关键在于把整体架构、对象选择、部署链路、运行排障、可观测、弹性伸缩和生产加固放到同一套平台化语境中理解。
1. 为什么 Ray on Kubernetes 需要 KubeRay
在很多团队里,Ray 和 Kubernetes 的结合并不是一开始就为了“上 KubeRay”,而是从具体业务需求开始的。
例如,训练团队希望用 Ray 做分布式训练;数据团队希望用 Ray 执行批处理和 ETL;推理团队希望用 Ray Serve 承载模型服务;平台团队则希望所有计算任务都运行在 Kubernetes 上,统一使用已有的资源池、权限、日志、监控和弹性能力。
Ray 提供分布式计算能力,Kubernetes 提供基础设施管理能力。真正困难的是两者之间的生命周期和运维边界:
- 谁负责创建和销毁 Ray 集群?
- Ray worker 节点或进程异常退出后,集群是否能自动恢复到期望规模?
- 离线任务结束后,集群资源是否能自动回收?
- 在线服务升级时,如何避免直接中断流量?
- Dashboard、Job API、GCS 故障分别会影响哪些链路?
- GPU 等异构资源如何和节点池、调度约束、驱动环境、镜像依赖配合?
- Ray 集群销毁后,历史任务、日志和指标还能不能查?
如果这些问题都靠脚本和人工约定解决,平台很快会变得难以维护。KubeRay 提供的核心能力,是把这些对象和流程变成 Kubernetes 原生的声明式资源。
一句话概括:
KubeRay 将 Ray 中的集群、任务和服务等概念抽象成 RayCluster、RayJob、RayService 等 Kubernetes 原生资源,并由 Operator 负责把声明式配置协调成真实的 Ray 运行环境。
从生产视角看,KubeRay 主要提供三类价值。
| 价值 | 说明 | 生产意义 |
|---|---|---|
| 生命周期管理 | 通过 Operator 管理 Head、Worker、Service、Status | 避免手工维护 Ray 集群 |
| Kubernetes 生态集成 | 复用 Namespace、RBAC、调度、Ingress、NetworkPolicy、日志、监控 | 让 Ray 纳入平台治理体系 |
| 生产能力补齐 | 通过 RayJob、RayService、Autoscaler、History 等能力支持任务和服务 | 支撑离线、在线、多租户和弹性场景 |
因此,KubeRay 不是单纯的安装工具。它更像是 Ray 在 Kubernetes 上的控制面扩展:用户提交的是 Ray 相关的 CRD,Operator 负责把这些声明式对象协调成 Kubernetes Pod、Service 等真实资源,而 Ray 自身继续负责 Task、Actor、Object store 和 Serve 等运行时能力。
2. KubeRay 整体架构与核心对象
KubeRay 是 Kubernetes 上运行 Ray 的 Operator。每个 Ray 集群都由一个头节点 Pod 和一组工作节点 Pod 组成。可选的自动扩缩容功能允许 KubeRay Operator 根据 Ray 工作负载的需求调整 Ray 集群的大小,并根据需要添加和移除 Ray Pod。KubeRay 支持异构计算节点(包括 GPU),并且允许在同一个 Kubernetes 集群中运行多个不同 Ray 版本的 Ray 集群。
它在 Kubernetes API 中引入 RayCluster、RayJob、RayService 三类 CRD,并通过 KubeRay Operator 管理这些资源背后的 Ray 集群、任务提交和 Ray Serve 服务。三类 CRD 的关系可以概括为:
- RayCluster:表示一个 Ray 集群,由一个 Head Pod 和一组 Worker Pod 组成。
- RayJob:表示一次 Ray 任务提交,通常由 KubeRay 创建 RayCluster,并通过一个 submitter Kubernetes Job 将 Ray Job 提交到集群。
- RayService:表示一个长期运行的 Ray Serve 服务,同时管理底层 RayCluster 和上层 Ray Serve Applications。
2.1 RayCluster:Ray 集群资源
RayCluster 是 KubeRay 的基础资源。一个 RayCluster 描述一个 Ray 集群的期望状态,核心字段包括 headGroupSpec 和 workerGroupSpecs。
headGroupSpec定义唯一的 Head Pod,包括容器镜像、资源、端口和rayStartParams。workerGroupSpecs定义一组或多组 Worker Pods。每个 worker group 内的 Pod 配置相同,可以设置replicas、minReplicas、maxReplicas等字段。- KubeRay Operator 会为 RayCluster 创建 Head Pod、Worker Pods,并自动创建指向 Head Pod 的 Kubernetes Service。
Head Pod 运行 Ray 集群的全局控制进程,包括 GCS、Dashboard、Job API、Autoscaler 等。Worker Pods 运行 Raylet,执行 Ray task / actor,并提供 Object Store 内存。Head Service 为 Dashboard、Job API、GCS、Ray Client、Serve、metrics 等端口提供稳定访问入口。
2.2 RayJob:任务提交资源
RayJob 管理的是一次 Ray Job 提交。它不是简单地在 Kubernetes Pod 中直接运行用户脚本,而是将 Ray application 提交到 Ray 集群。
RayJob 通常包含两部分:
rayClusterSpec:定义任务所需的 RayCluster,KubeRay 可以自动创建这个集群。entrypoint:定义要提交到 Ray 集群中的 Ray Job 入口命令。
KubeRay Operator 会先创建或使用 RayCluster,等待集群 ready 后,再创建一个 submitter Kubernetes Job。这个 submitter Job 执行 ray job submit,把用户的 Ray Job 提交到 RayCluster。任务状态随后回写到 RayJob Status。根据配置,任务完成后 RayCluster 可以保留,也可以自动清理。
2.3 RayService:Ray Serve 服务资源
RayService 面向长期运行的 Ray Serve 应用,解决的是“如何把 Ray Serve 以在线服务的方式稳定运行在 Kubernetes 上”的问题。相比 RayCluster 只描述集群、RayJob 只描述一次任务提交,RayService 同时关注底层 Ray 集群和上层 Serve 应用的生命周期,适合在线推理、模型服务、多副本服务和需要无停机升级的场景。
RayService 管理两个核心对象:
- RayCluster:负责 Kubernetes 中的底层计算资源。
- Ray Serve Applications:负责用户的在线服务应用。
RayService 的配置通常包含 rayClusterConfig 和 serveConfig。rayClusterConfig 描述底层 RayCluster,包括 Head、Worker、镜像、资源和调度约束;serveConfig 描述要部署的 Serve 应用,包括 application、deployment、import path、runtime env、replica 数量等。
用户提交 RayService
│
▼
┌──────────────────────┐
│ KubeRay Operator │
│ 协调服务期望状态 │
└──────────┬───────────┘
│
├── 创建 / 维护 RayCluster
│ ├── Head Pod:GCS、Dashboard、Serve Controller
│ └── Worker Pods:运行 Serve Replicas
│
├── 提交 / 更新 Ray Serve Applications
│ └── application / deployment / replica
│
└── 创建 Kubernetes Services
├── Head Service:Dashboard、Job API、控制面访问
└── Serve Service:线上请求入口
线上请求
│
▼
Serve Service → Ray Serve Proxy → Serve Application → Serve Deployments → Ray Actor Replicas
它的核心原理是把“集群状态”和“服务状态”都纳入 Operator 的 reconcile 过程。Operator 会持续检查 RayService 中声明的期望状态。如果 Serve 应用配置变化,RayService 可以对 Ray Serve Applications 做原地更新;如果 RayCluster 配置变化,例如镜像、资源规格、worker group 或 Ray 启动参数变化,Operator 会创建新的 RayCluster,等待新集群和 Serve 应用健康后再切换 Service 指向,从而支持 Ray 集群层面的无停机升级。
生产环境中,RayService 的价值不只是“帮你创建一个 RayCluster 并启动 Serve”,而是把在线服务的关键运维动作标准化:健康检查、升级切流、旧集群回收、服务入口维护和状态回写。排查 RayService 问题时,除了看 RayService Status,还要同时关注 RayCluster 状态、Head / Worker Pod 日志、Serve application 状态,以及 Serve Service 的 endpoints 是否正确。
2.4 Operator Reconcile 与 Ray 运行时边界
KubeRay Operator 的职责是协调 Kubernetes 资源,而不是替代 Ray 运行时。
Watch RayCluster / RayJob / RayService
→ 读取期望状态
→ 创建或更新 Kubernetes 资源
→ 等待 Ray 集群或 Ray Serve 应用进入目标状态
→ 回写 CR Status
RayCluster 中声明 1 个 Head 和 3 个 Worker 时,Operator 会创建对应的 Head Pod、Worker Pods 和 Head Service。某个 Worker Pod 被删除后,Operator 会根据期望副本数重新创建。RayJob 中声明 entrypoint 时,Operator 会创建 submitter Job 去提交 Ray Job。RayService 中声明 Serve 应用时,Operator 会协调 RayCluster 和 Serve 应用状态。
Ray task / actor 如何调度、对象如何存储、Serve replica 如何运行,是 Ray 运行时的职责。Pod 是否能被创建和调度,则取决于 Kubernetes 的资源、调度、镜像、网络和权限配置。
2.5 Head Service 与网络入口
KubeRay 会为 RayCluster 创建指向 Head Pod 的 Head Service,命名通常遵循 {RayCluster-name}-head-svc。这个 Service 暴露 Ray Head 侧的多个端口,用于集群内部通信、任务提交、Dashboard 访问和服务入口。
常见端口如下:
| 端口 | 组件 | 用途 | 生产暴露方式 |
|---|---|---|---|
| 6379 | GCS | Ray 集群元数据服务 | 仅集群内访问 |
| 8265 | Dashboard / Job API | UI、任务提交、状态查询 | 通过 Ingress / Gateway 暴露并加鉴权 |
| 10001 | Ray Client | 客户端连接 Ray 集群 | 按需暴露,限制来源 |
| 8000 | Ray Serve | 在线服务入口 | 通过 Ingress / Gateway 或 Serve Service 暴露 |
生产环境中,Dashboard 不应无鉴权暴露到公网。Worker 无法连接 Head、RayJob 无法提交、Dashboard 无法访问时,Head Service、Endpoints、DNS、端口和 NetworkPolicy 是优先排查对象。
3. 从部署运行到对象选择:一个最小生产化路径
KubeRay 的生产化落地围绕 RayCluster、RayJob、RayService 三个对象展开。RayCluster 承载基础集群和验证链路,RayJob 面向离线任务提交,RayService 面向在线服务升级,运行排障能力则贯穿这三类对象的整个生命周期。
3.1 KubeRay Operator 安装
添加 KubeRay Helm 仓库
确保有一个可用的Kubernetes集群。KubeRay Operator 通常通过 Helm 安装。先添加 KubeRay Helm 仓库:
helm repo add kuberay https://ray-project.github.io/kuberay-helm/
helm repo update
# 搜索可用版本
helm search repo kuberay/kuberay-operator --versions
后续示例用 ${KUBERAY_VERSION} 表示要安装的 Operator 版本。
安装 KubeRay Operator
安装 Operator 到独立 Namespace(kuberay-system):
export KUBERAY_VERSION=<your-kuberay-version>
helm install kuberay-operator kuberay/kuberay-operator \
--namespace kuberay-system \
--version ${KUBERAY_VERSION}
生产环境中,Operator 的资源 requests / limits、日志级别、镜像仓库、镜像拉取策略、ServiceAccount 和 RBAC 策略都应通过 values 文件显式管理。
验证 CRD 和 Operator 状态
安装完成后,先确认 KubeRay CRD 已注册:
kubectl get crd | grep ray.io
# [Example output]
# rayclusterfleets orchestration.aibrix.ai/v1alpha1 true RayClusterFleet
# rayclusterreplicasets orchestration.aibrix.ai/v1alpha1 true RayClusterReplicaSet
# rayclusters ray.io/v1 true RayCluster
# rayjobs ray.io/v1 true RayJob
# rayservices ray.io/v1 true RayService
kubectl api-resources | grep ray
# [Example output]
# rayclusters.ray.io 2026-01-22T10:12:15Z
# rayjobs.ray.io 2026-01-22T10:12:16Z
# rayservices.ray.io 2026-01-22T10:12:17Z
正常情况下应该能看到 RayCluster、RayJob、RayService 相关资源。
再确认 Operator Pod 正常运行:
kubectl get pods -n kuberay-system
# [Example output]
# NAME READY STATUS RESTARTS AGE
# kuberay-operator-67465c8d76-2prrz 1/1 Running 0 47d
kubectl get deployment -n kuberay-system
# [Example output]
# NAME READY UP-TO-DATE AVAILABLE AGE
# kuberay-operator 1/1 1 1 47d
kubectl logs -n kuberay-system deploy/kuberay-operator
如果 Operator 没有正常启动,优先检查:
- Helm chart 版本是否存在。
- CRD 是否安装成功。
- Operator 镜像是否能拉取。
- ServiceAccount / RBAC 是否具备 watch 和 reconcile KubeRay CRD 的权限。
- 集群是否有 Admission Webhook、NetworkPolicy 或镜像仓库策略阻止启动。
3.2 RayCluster 提交链路
RayCluster 是 KubeRay 最基础的运行单元。它的关键点是:用户声明的是一个 Ray 集群的期望状态,KubeRay Operator 负责把这个期望状态协调成 Head Pod、Worker Pods、Head Service 和 RayCluster Status。参考示例:RayCluster Quickstart。
典型链路如下:
用户提交 RayCluster CR
→ KubeRay Operator 监听到 RayCluster 变化
→ 创建或更新 Head Pod
→ Head Pod 启动 GCS、Dashboard、Job API、Autoscaler
→ 创建 Head Service
→ 创建或更新 Worker Pods
→ Worker 通过 Head Service 连接 Head
→ Worker 注册到 Ray 集群
→ RayCluster Status 回写 Running / Ready 状态
这个链路对生产排障很重要。RayCluster 没有进入 Running 状态时,问题可能出在 Kubernetes 调度、镜像拉取、Head 启动、Head Service、Worker 注册或 Ray 运行时初始化中的任意一环。因此排查 RayCluster 时,不能只看 RayCluster Status,也要同时看 Head Pod、Worker Pod、Head Service Endpoints、Operator 日志和 Ray 进程日志。
3.3 RayJob 提交链路
RayJob 的关键点是:它不是直接把脚本作为 Kubernetes Pod 的主进程运行,而是由 KubeRay 创建一个独立的 Kubernetes Job 作为 submitter。submitter Job 会启动自己的 Pod,在 Pod 中执行 ray job submit,再调用 Head 侧的 Ray Jobs API,把任务提交到 Ray 集群。这个 API 由 Ray Dashboard HTTP 服务提供,默认端口是 8265。参考示例:RayJob Quickstart。
典型链路如下:
用户提交 RayJob CR
→ RayJob Controller 创建或复用 RayCluster
→ 等待 Head Pod Ready
→ 创建 Kubernetes Job(submitter Job)
→ submitter Pod 启动并执行 ray job submit
→ 调用 Head 侧 Ray Jobs API(8265)
→ Ray Head 接收任务
→ Ray Scheduler 调度 task / actor
→ Worker 执行
→ RayJob Controller 轮询状态并回写 RayJob Status
这个链路对生产排障很重要。submitter Pod 本身通常只是提交器,不承载实际分布式计算;真正的计算由 Ray 集群内部的 task / actor 在 Head 或 Worker 上执行。Ray Jobs API 和 Dashboard HTTP 服务同在 Head 侧的 8265 端口,如果 8265 不可用,新 RayJob 可能无法提交。但已经提交并运行的 Ray 任务通常不依赖 Dashboard 页面继续执行。
因此排查 RayJob 时,不应该只看 RayJob Status,也要看 Controller 日志、Dashboard API、Head Pod 日志和 Worker 日志。
3.4 RayService 升级链路
RayService 面向在线服务,核心价值是把 Serve 应用的升级过程纳入控制器管理。参考示例:RayService Zero-Downtime Incremental Upgrades。
一次典型升级可以理解为:
提交新的 RayService spec
→ Operator 创建新的 RayCluster
→ 部署新的 Serve Application
→ 健康检查通过
→ Service 指向新集群
→ 回收旧集群
生产中,RayService 的关注点不只是配置能不能生效,而是升级过程是否可控:
- 新集群冷启动需要多久?
- Serve 应用健康检查是否稳定?
- 切流时机是否明确?
- 失败后是否能回滚?
- 新旧集群并存时是否有足够容量?
如果这些问题没有提前验证,RayService 升级可能会因为资源不足、镜像拉取慢、健康检查不稳定而拖长窗口。
3.5 如何选择 RayCluster、RayJob、RayService
到了实际落地阶段,选择哪一个对象主要取决于两个问题:工作负载是一次性任务还是长期服务,以及集群生命周期是否要和工作负载绑定。
如果平台需要的是一组长期存在的分布式计算资源,例如开发调试、共享 Ray 集群、长期计算资源池,或者用于跑通基础部署、网络、镜像、日志、指标和资源配置,RayCluster 更合适。它的生命周期由用户或平台显式管理,任务结束后是否释放资源需要额外约定。
如果工作负载是离线训练、ETL、批处理或一次性计算任务,RayJob 更合适。它把任务提交、状态追踪和集群生命周期放到同一个声明式对象中,平台可以根据策略创建集群、提交任务、追踪状态,并在任务结束后保留或删除集群。
如果工作负载是在线推理服务或长期运行的 Ray Serve 应用,RayService 更合适。它关注的不是单次任务是否完成,而是服务健康检查、升级切流、失败回滚、冷启动时间和新旧集群并存时的冗余容量。
选型逻辑可以简化为:
这是长期在线服务或 Ray Serve 应用吗?
是 → RayService
否 → 任务提交和集群生命周期是否需要绑定?
是 → RayJob
否 → RayCluster
不同对象在生产选型中的差异如下:
| 维度 | RayCluster | RayJob | RayService |
|---|---|---|---|
| 生命周期 | 用户手动管理 | 可随任务创建和回收 | 长期运行 |
| 集群所有权 | 独立存在 | 自动创建或复用 RayCluster | 自动创建并管理 RayCluster |
| 典型场景 | 开发、共享集群、资源池 | 训练、ETL、批处理 | 在线推理、Serve 应用 |
| 升级方式 | 用户自行处理 | 通常不涉及服务升级 | 支持新旧集群切换 |
| 失败反馈 | RayCluster Status、Pod 状态 | RayJob Status | RayService Status、健康检查 |
| Dashboard | 集群存在期间可用 | 任务运行期间可用 | 服务运行期间可用 |
4. 生产化能力补齐:观测、弹性、安全与容灾
一个 RayCluster 能跑起来,只能说明基础链路通了。要进入生产,还需要补齐可观测、弹性伸缩、安全权限、故障恢复和容量规划。
4.1 生产可观测落地方案
Ray Dashboard 是实时调试入口,但不是完整的生产观测系统。它可以查看集群节点、Job、Actor、资源使用、日志和 Serve 应用状态;但 Head 重启后部分实时状态可能丢失,也不适合长期保留历史任务数据,单集群视图难以跨集群聚合,告警能力也不完整。Dashboard / Job API 与 Head 绑定,Head 或 8265 端口不可用时,观测入口和 RayJob 提交链路都会受影响。
因此,Ray on Kubernetes 的生产可观测不能只依赖 Dashboard。一个可落地的方案至少要覆盖四类数据:Kubernetes 资源状态、Ray 运行时指标、Pod / Ray 日志、任务和集群历史记录。
| 观测对象 | 数据来源 | 落地方案 | 主要用途 |
|---|---|---|---|
| Kubernetes 资源状态 | Pod、Service、RayCluster / RayJob / RayService Status、Event | kube-state-metrics + Prometheus,配合 kubectl describe 和 Kubernetes Event | 判断 Pod Pending、OOMKilled、Service Endpoints、CR 状态异常 |
| Ray 运行时指标 | Head / Worker 暴露的 metrics 端口 | Prometheus 抓取 Ray metrics,Grafana 展示资源、任务、Actor、Object Store、Autoscaler 指标 | 做容量趋势、资源水位、Autoscaler 和组件健康告警 |
| 运行日志 | Head / Worker 容器日志、Ray session logs | Fluent Bit / Vector / Promtail 采集到 Loki、Elasticsearch 或云日志 | 排查 Head、Worker、Job、Serve replica 的运行错误 |
| 历史记录 | Ray events、logs、Dashboard API 快照 | KubeRay History Server Collector 写入对象存储,History Server 提供查询 UI / API | RayCluster 删除后仍能查询 Job、Task、Actor、Node、日志和事件 |
这四类数据解决的问题不同:
- Kubernetes 资源状态回答“Pod 和 CR 为什么没有进入期望状态”。
- Ray metrics 回答“Ray 集群内部资源和组件是否健康”。
- Logs 回答“具体错误发生在哪里”。
- History 回答“集群销毁后如何复盘任务、Actor、节点和日志”。
Metrics:用 Prometheus 抓 Ray 和 Kubernetes 指标
Metrics 侧需要同时覆盖 Kubernetes 和 Ray 两类指标。
Kubernetes 侧:
- kube-state-metrics:采集 Pod、Deployment、Service、CRD 等资源状态。
- node-exporter / cAdvisor:采集节点、容器 CPU、内存、磁盘、网络指标。
- Kubernetes Event exporter:将调度失败、镜像拉取失败、OOMKilled 等事件转成可查询数据。
Ray 侧:
- Head / Worker 暴露 Ray metrics。
- Prometheus 通过 PodMonitor / ServiceMonitor 或 scrape config 抓取 Ray metrics 端口。
- Grafana Dashboard 展示 Ray 集群资源、任务、Actor、Object Store、Autoscaler 等指标。
Logs:同时采集容器日志和 Ray session logs
日志侧不能只看 kubectl logs。生产环境至少要采集两类日志:
- Kubernetes 容器 stdout / stderr:包括 Head、Worker、submitter Job、Serve replica、Operator 日志。
- Ray session logs:包括
raylet.out、gcs_server.out、Dashboard 日志、worker 进程日志、event 日志等。
常见落地方式:
Node / Pod logs
→ Fluent Bit / Vector / Promtail
→ Loki / Elasticsearch / Cloud Logging
→ 按 namespace、RayCluster、Pod、container、job_id 查询
日志字段需要统一保留这些标签:
namespaceray_clusterray_node_type:head / workerpodcontainerray_job_idray_serviceserve_application
这样排查 RayJob 或 RayService 时,可以从 CR 状态跳到对应 Pod,再按 job_id 或 serve application 查询日志。
History:用 KubeRay History Server 保存集群销毁后的历史
KubeRay 仓库中已经包含 History Server 实现。它的定位不是替代 Prometheus 或日志系统,而是补齐 RayCluster 销毁后的历史查询能力。
KubeRay History Server 由两个核心组件组成:
| 组件 | 部署位置 | 作用 |
|---|---|---|
| Collector | 作为 sidecar 注入 Ray Head / Worker Pod | 采集 Ray logs、events、Dashboard API 快照,并写入对象存储 |
| History Server | 独立 Deployment / Service | 从对象存储读取历史数据,提供 Web UI 和兼容 Ray Dashboard 风格的查询 API |
整体链路如下:
Ray Head / Worker Pod
├─ ray container
│ ├─ /tmp/ray/session_latest/logs
│ ├─ Ray events
│ └─ Dashboard / Job / State APIs
│
└─ collector sidecar
├─ 读取共享的 /tmp/ray
├─ 接收 Ray event export: /v1/events
├─ 轮询 Dashboard 补充 API
└─ 写入对象存储
Object Storage
├─ logs/
├─ node_events/
├─ job_events/
└─ fetched_endpoints/
History Server
├─ 读取对象存储
├─ 聚合 Task / Actor / Job / Node / Event 状态
└─ 提供 UI / API 查询历史集群
KubeRay 当前实现支持多种存储后端,代码中包括 S3 / MinIO、Azure Blob、GCS、Aliyun OSS 和 local test backend。生产环境通常会接入已有对象存储,例如 S3、GCS、Azure Blob 或云厂商 OSS;本地和测试环境可以使用 MinIO。
4.2 弹性伸缩:两层系统协同
KubeRay 场景下的伸缩不是一个开关,而是 Ray Autoscaler 和 Kubernetes Cluster Autoscaler 的协同。
先看 Ray Autoscaler 的能力边界:
- 它能根据 Ray resource demand 增减 Worker Pod。
- 它不能改变单个 Worker Pod 的资源规格。
- 它不能把已有 workerGroup 动态变成另一种资源类型。
- 对冷启动敏感的业务要谨慎允许缩到 0。
Ray Autoscaler 的工作链路可以理解为:
Ray Autoscaler 运行在 Head Pod 中
→ 观察 pending tasks / actors 的资源需求
→ 计算需要的 Worker 数量
→ 更新 RayCluster workerGroup replicas
→ KubeRay Operator 创建或删除 Worker Pod
→ Kubernetes Scheduler 调度 Pod
如果当前 Kubernetes 节点资源不足,链路会继续交给 Cluster Autoscaler:
应用负载增加
→ Ray Autoscaler 需要更多 Worker
→ KubeRay Operator 创建 Worker Pod
→ Pod Pending,因为节点资源不足
→ K8s Cluster Autoscaler 扩容节点
→ 新节点 Ready
→ Worker Pod 调度成功
→ Worker 加入 Ray 集群
核心配置通常包括:
spec:
enableInTreeAutoscaling: true
autoscalerOptions:
upscalingMode: Default
idleTimeoutSeconds: 60
workerGroupSpecs:
- groupName: cpu-workers
replicas: 1
minReplicas: 0
maxReplicas: 10
生产调优时,要重点关注:
- Node Pool 实例规格是否匹配 Worker Pod requests。
- GPU Worker 的 taints / tolerations / nodeAffinity 是否对齐。
- 冷启动延迟是否可接受,包括 Ray 决策、Pod 创建、节点扩容、镜像拉取和 Ray 初始化。
- 缩容策略是否会导致任务抖动或资源浪费。
4.3 故障恢复与 GCS Fault Tolerance
KubeRay 的故障恢复要分清两层:Kubernetes 资源层和 Ray 运行时层。Operator 能把 RayCluster 重新协调回期望的 Pod / Service 数量,但它不能自动恢复所有已经在 Ray 内部运行的 Task、Actor、Object 和 GCS 元数据。生产设计的重点不是“Pod 会不会被重建”,而是要明确每类故障发生后哪些状态会丢、哪些任务要重试、哪些入口会受影响。
常见故障的处理边界如下:
| 故障 | 资源层恢复 | 运行时影响 | 排障入口 | 生产处理 |
|---|---|---|---|---|
| Worker Pod 被驱逐或 OOM | Operator 根据 replicas / autoscaler 期望值重建 Worker | 该节点上的 task / actor 失败,未持久化 object 可能丢失 | Pod event、Worker 日志、Ray task / actor 状态、Object Store 指标 | 给 Worker 设置合理 requests / limits;重要任务在应用层做重试和幂等;避免把关键状态只放在 Ray object 中 |
| Worker 长时间 Pending | Operator 已创建 Pod,但 Kubernetes 无法调度 | Ray 资源需求得不到满足,任务排队或 autoscaler 反复扩容失败 | Pod describe、Cluster Autoscaler 日志、节点池资源、taints / tolerations、nodeAffinity | Worker requests 与节点池规格匹配;GPU 池提前预留容量;对冷启动敏感的业务不要轻易缩到 0 |
| Head Pod 重启 | Kubernetes 重建 Head Pod,Head Service 指向新 Pod | GCS、Dashboard、Job API、Autoscaler 中断;Worker 可能重连,部分运行时状态可能丢失 | Head Pod 日志、GCS 日志、Dashboard / Job API、RayCluster Status、Worker 重连日志 | Head 使用更高资源保障和优先级;Head 重启必须告警;关键生产集群评估 GCS FT |
| Dashboard / Jobs API 不可用 | Pod 可能仍然 Running | 新 RayJob 提交、Dashboard 查询和部分运维入口受影响;已运行 task 通常不依赖 Dashboard 页面继续执行 | 8265 端口、Head Service Endpoints、Dashboard 日志、submitter Job 日志 | 将 Dashboard / Jobs API 健康检查纳入告警;RayJob 失败时同时检查 submitter Pod 和 Head 侧 8265 |
| 镜像拉取失败 | Pod 无法创建成功 | 集群扩容、RayJob 提交或 RayService 升级卡住 | Pod event、镜像仓库、imagePullSecrets、节点网络 | 生产镜像提前预热;镜像版本固定;关键镜像做扫描和发布准入 |
| RayService 新集群不健康 | 新 RayCluster 无法完成接管 | 切流延迟,旧集群继续承载流量或升级失败 | RayService Status、新旧 RayCluster、Serve 应用健康检查、Service selector | 升级前预留新旧集群并存容量;验证健康检查和回滚链路 |
GCS Fault Tolerance 只解决其中一类问题:Head 故障时,Ray 的 GCS 元数据能否从外部存储恢复。它不是通用容灾方案,也不会替应用自动恢复所有任务结果、对象数据或外部副作用。
在 KubeRay 中,GCS FT 通常通过 gcsFaultToleranceOptions 配置外部 Redis,把 GCS 元数据写到 Redis。核心配置形态如下:
spec:
rayVersion: "2.52.0"
gcsFaultToleranceOptions:
redisAddress: "redis:6379"
redisPassword:
valueFrom:
secretKeyRef:
name: redis-password-secret
key: password
headGroupSpec:
rayStartParams:
num-cpus: "0"
这里有几个生产上容易踩坑的点。
第一,Redis 本身必须按生产组件管理。单 Pod Redis 只能用于验证,生产环境至少要考虑持久化、备份、监控、容量、网络隔离、密码轮转和高可用。否则 GCS FT 会把 Head 的单点问题转移成 Redis 的单点问题。
第二,externalStorageNamespace 不要随意改。KubeRay 默认会用 RayCluster UID 隔离外部存储命名空间,避免不同 RayCluster 或 RayService 升级过程中的新旧集群互相读写同一份 GCS 状态。只有完全理解 GCS FT 和 RayService 行为时,才应该显式设置这个字段。
第三,GCS FT 不能替代应用层容错。Ray task 的输入数据、训练 checkpoint、模型产物、ETL 输出和外部系统写入,都应该写到可靠存储并具备幂等或重试语义。对 RayJob 来说,任务级 retry、checkpoint 和输出提交协议比单纯开启 GCS FT 更关键;对 RayService 来说,健康检查、回滚和新旧集群并存容量通常比 GCS FT 更直接影响可用性。
第四,是否开启 GCS FT 需要按场景判断。短生命周期 RayJob 集群的重建成本低,很多时候更应该把精力放在任务重试、checkpoint 和数据幂等上;长期共享 RayCluster 或承载关键在线服务的 RayService,则更值得评估 GCS FT、Head 资源保障和外部 Redis 的可靠性。
生产验证不应只停留在 YAML 生效。至少要做三类演练:删除一个 Worker Pod,确认 Operator 能补齐且任务失败可观测;删除或重启 Head Pod,确认告警、Worker 重连、GCS 状态和 RayJob / Dashboard 影响范围;让 Worker Pod Pending,确认 Cluster Autoscaler、容量告警和任务排队指标都能暴露出来。只有这些演练结果清楚,故障恢复策略才真正可用。
4.4 RayCluster 需要成组(gang)调度
RayCluster 不是单个 Pod,而是一组 Head / Worker Pod 共同组成的分布式运行环境。普通 Kubernetes 调度器默认按 Pod 独立调度,可能出现 Head 已启动、Worker 长期 Pending 的半启动状态。多个 RayCluster 并发创建时,还可能各自占住一部分资源,导致没有任何一个集群真正可用,造成资源浪费、队列阻塞甚至调度死锁。
这类问题需要通过 batch scheduler 或 gang scheduling 解决。gang scheduling 把一组 Pod 当成一个调度单元,只有满足最小成员数和资源需求时才整体放行,避免部分 Pod 先占住资源却无法形成可用 Ray 集群。
典型链路如下:
用户提交 RayCluster / RayJob / RayService
→ KubeRay Operator 计算 Head 和 Worker 资源需求
→ 创建 PodGroup 或写入调度器所需 metadata
→ batch scheduler 判断最小成员数和资源是否满足
→ 满足条件后成组调度 Head / Worker Pods
→ RayCluster 达到可用资源规模
KubeRay 源码中把调度器适配抽象成 batch scheduler 插件。Operator 配置里的 batchScheduler 用来选择具体调度器,当前代码路径中支持 Volcano、YuniKorn、KAI Scheduler 和 scheduler-plugins;旧的 enableBatchScheduler 仍保留给 Volcano 兼容使用。Kueue 则通过 RayCluster / RayJob / RayService 的 managedBy 字段把资源交给 kueue.x-k8s.io/multikueue 管理。
Koordinator 也是常见的 Kubernetes 调度器选择,但它不属于 KubeRay 当前内置的 batch scheduler 适配。由于 Koordinator 的组调度能力可以通过 Pod 注解表达,不要求 KubeRay 额外创建 PodGroup 对象,因此也可以通过 RayCluster 的 Head / Worker Pod template 注入对应 annotations 来配合使用。这种方式更适合已经在集群中统一使用 Koordinator 的平台,由平台模板负责维护调度注解和队列策略。
| 调度器 | KubeRay 集成方式 | 适用重点 |
|---|---|---|
| Volcano | Operator 创建 / 更新 Volcano PodGroup,并写入 queue 相关 metadata | 典型 batch / AI 训练集群,关注队列、公平性和 gang scheduling |
| YuniKorn | Operator 写入 task group annotations,配合 ray.io/gang-scheduling-enabled: "true" | 多队列资源调度,按 task group 表达 Head / Worker 资源需求 |
| scheduler-plugins | Operator 创建 scheduler-plugins PodGroup,并给子资源写入 PodGroup label | 使用 Kubernetes scheduler-plugins 的集群 |
| KAI Scheduler | Operator 写入 queue metadata,依赖 KAI 的队列和 PodGrouper 能力 | 多租户队列、团队资源隔离和 GPU 资源调度 |
| Kueue | 通过 managedBy: kueue.x-k8s.io/multikueue 委托管理 | 多集群或 Kueue 统一队列体系 |
| Koordinator | KubeRay 无内置适配,可通过 Pod template annotations 接入组调度 | 已统一使用 Koordinator 的平台 |
生产上是否启用 gang scheduling,主要取决于 RayCluster 的资源形态。如果只是小规模开发集群,普通调度通常足够;如果是 GPU 训练、大规模 Worker、RayService 灰度升级或多租户共享节点池,gang scheduling 能显著减少“半个集群启动成功、任务却无法真正运行”的情况,也能避免多个 RayCluster 互相占用零散资源后全部不可用。
调度配置需要和容量规划一起设计:
- Head 和 Worker 的 requests 必须真实反映资源需求,否则 PodGroup 的最小资源判断没有意义。
minReplicas不宜随意设置过大,否则 gang scheduling 会因为最小资源长期不满足而阻塞整个 RayCluster。- GPU worker group 要和节点池 labels、taints、tolerations、nodeAffinity、device plugin 配套配置。
- RayJob 使用临时 RayCluster 时,submitter Pod 的时机也要纳入调度器行为验证,避免集群尚未满足资源需求就开始提交任务。
- RayService 升级时,新旧 RayCluster 可能同时存在,队列配额需要覆盖升级窗口内的双倍资源需求。
5. 总结:从可用到生产可用
KubeRay 的核心不是“把 Ray Pod 跑起来”,而是把 Ray 纳入 Kubernetes 的声明式运维体系。它通过 RayCluster、RayJob、RayService 把集群、任务和服务变成 Kubernetes 原生对象,再通过 Operator 协调 Head、Worker、Service 和 Status 等资源。
从落地成熟度看,KubeRay 通常会经历几个阶段:
| 阶段 | 推荐组合 | 目标 |
|---|---|---|
| 开发验证 | RayCluster + port-forward + 固定 Worker | 快速跑通功能 |
| 测试环境 | RayJob + Dashboard + 基础日志指标 | 验证任务提交和运行链路 |
| 准生产 | RayJob / RayService + Autoscaler + Prometheus + History | 验证运维能力 |
| 生产环境 | 完整观测、告警、权限、GCS FT、升级和容量策略 | 稳定承载业务 |
对于平台团队来说,KubeRay 不是单点组件,而是构建统一 AI 计算平台的底座之一。真正的生产化重点,在于是否能把场景选择、运行期链路、观测体系、弹性伸缩、权限边界和故障恢复都纳入统一设计。
如果只是想快速验证,可以从一个 RayCluster 开始;如果要支撑离线任务平台,需要重点设计 RayJob 模板、任务状态和历史追踪;如果要承载在线推理服务,则需要把 RayService 的健康检查、升级、回滚和容量冗余作为重点。只有这些能力补齐后,Ray on Kubernetes 才算从“可运行”走向“可运维”。