搞懂 Kubespray 和 Ray:一个负责搭集群,一个负责跑 AI 任务
1. 写在最前面
最近看 AI 基础设施相关资料时,笔者经常会看到 Kubespray、Kubernetes、KubeRay、Ray 和 Ray Serve 这几个名字一起出现。
单独看每个词,好像都能查到定义。但把它们放在一起以后,脑子里很快就会冒出一堆问题:
Kubespray和Kubernetes到底是什么关系?Kubernetes已经能管理集群,为什么还要再搭一个 Ray 集群?Kubernetes和Ray都在做调度,它们是不是重复了?KubeRay又是从哪里冒出来的?- 最后真正执行 AI 任务的,到底是哪一层?
这些组件都在谈「节点」「资源」和「调度」,很容易让人以为它们在做差不多的事情。但真正把链路拆开以后,会发现它们站的位置完全不一样。
先给自己留一个最小理解:
Kubespray 负责把 Kubernetes 集群搭出来。
Kubernetes 负责管理机器上的 Pod 和底层资源。
KubeRay 负责在 Kubernetes 里创建和管理 Ray 集群。
Ray 负责组织分布式计算任务。
Ray Serve 负责把模型能力变成在线服务。
如果只看最核心的区别,那就是:Kubespray 管「集群怎么搭起来」,Ray 管「AI 任务怎么跑起来」。中间的 Kubernetes 和 KubeRay,则负责把机器资源与 Ray 集群接起来。
这篇文章不展开安装命令和 YAML 配置,只想先把几层关系摆正。对刚接触 AI Infra 的人来说,先知道谁在哪一层、负责什么,后面再去看参数会轻松很多。
2. 先把完整链路摆出来
假设现在有一批服务器,最终想在上面跑一个语音识别服务。一条常见链路大概是这样:
一批 Linux 服务器
->
Kubespray 安装 Kubernetes
->
Kubernetes 管理节点、Pod 和资源
->
KubeRay 创建并维护 Ray 集群
->
Ray 调度语音识别任务
->
Ray Serve 对外提供推理接口
这条链路看起来很长,但可以先分成三段:
第一段:把机器组织起来
机器 -> Kubespray -> Kubernetes
第二段:把 Ray 运行环境准备好
Kubernetes -> KubeRay -> Ray 集群
第三段:让模型真正开始干活
Ray -> Ray Serve -> AI 服务
第一段是基础设施建设,第二段是运行环境管理,第三段才进入 AI 计算和模型服务。
不过要先强调:这是一种常见组合,不是所有 AI 系统都必须照抄的固定套餐。
如果使用云厂商提供的托管 Kubernetes,可能根本不需要 Kubespray;如果只跑一个简单模型,也可能不需要 Ray;Ray 也可以直接跑在虚拟机或物理机上,并不是只能运行在 Kubernetes 里。
把它们放在一条链路里,是为了讲清协作关系,不是说它们永远必须一起出现。
3. Kubespray:先把一批机器变成 Kubernetes 集群
3.1 它解决的是什么问题
假设手里有 10 台 Linux 服务器,其中几台准备当控制节点,另外几台准备跑业务。有些机器带 GPU,有些机器只有 CPU。
这时候它们还只是彼此独立的服务器。要把它们组成 Kubernetes 集群,需要安装 Kubernetes 组件和容器运行时,部署 etcd,配置网络与证书,并让各个节点以正确的角色加入集群。
这些事情当然可以手工完成,但机器一多,步骤就很容易漏,节点之间的配置也可能不一致。
Kubespray 做的事情,就是把这套安装过程自动化。
它基于 Ansible,读取机器清单后通过 SSH 到目标机器执行安装和配置,最后把这些机器组织成一个 Kubernetes 集群。
可以先把它理解成:
Kubespray:Kubernetes 集群的自动化安装和维护工具
Kubernetes:安装完成后长期运行的集群平台
所以 Kubespray 不是 Kubernetes 本身,更不会负责处理后面的模型请求。
3.2 Kubespray 装完以后是不是就没用了
说它是「安装工具」很容易理解,但也不能把它理解成只运行一次就永远丢掉的临时脚本。
除了初次部署,后面增加节点、升级集群或调整部分配置时,也可能继续使用 Kubespray。不过从业务请求链路看,它主要出现在基础设施建设和维护阶段:
用户发来一条语音识别请求
X
不会经过 Kubespray
Kubespray 把舞台搭好,但不会站在舞台上处理每一次请求。
4. Kubernetes:管理 Pod 和底层资源
Kubernetes 集群搭好以后,接下来长期工作的就是 Kubernetes。它会管理这些内容:
- 集群里有哪些节点;
- Pod 应该运行在哪台节点上;
- 每个 Pod 需要多少 CPU、内存或 GPU;
- Pod 挂掉以后要不要重新创建;
- 服务需要几个副本;
- Pod 之间怎么发现和访问;
- 配置、密钥和存储怎么挂载。
其中 Node 是集群里的机器,Pod 是 Kubernetes 调度和运行容器的基本单元。比如要运行一个普通后台服务,可以告诉 Kubernetes:
我要 3 个 Pod。
每个 Pod 需要 2 核 CPU 和 4 GiB 内存。
如果某个 Pod 挂了,帮我补回来。
Kubernetes 会寻找合适的节点,把 Pod 放上去,并尽量让实际状态靠近声明的目标状态。所以它关心的核心问题是:
容器应该在哪里运行?
运行环境应该维持成什么状态?
写到这里,一个很自然的问题就出现了:既然 Kubernetes 已经能调度 Pod,为什么后面还需要 Ray?
中间还有一层 KubeRay,它能帮助我们看清两套系统是怎么接起来的。
5. KubeRay:把 Ray 集群交给 Kubernetes 管起来
5.1 为什么会多出一个 KubeRay
Ray 自己也有集群概念。一个 Ray 集群通常包含一个 Head 节点和若干 Worker 节点。如果 Ray 跑在 Kubernetes 上,这些节点最终也要以 Pod 的形式出现,于是就要处理 Head、Worker 的创建、更新和扩缩容。
这些事情可以自己写 Kubernetes YAML 和控制逻辑,但维护起来并不轻松。KubeRay 就是专门处理这层连接的 Kubernetes Operator,也是 Ray 官方推荐的 Kubernetes 部署方式。
初学阶段可以把它理解成一个「翻译和管理层」:
用户描述自己想要什么样的 Ray 集群
->
KubeRay 把这个目标转换成 Kubernetes 能管理的 Pod、Service 等资源
->
Kubernetes 把这些资源真正运行起来
5.2 RayCluster、RayJob 和 RayService 是什么
KubeRay 提供了几个经常会看到的自定义资源:RayCluster 描述一个 Ray 集群,RayJob 用来提交 Ray 作业,RayService 用来管理 Ray Serve 应用及其背后的 Ray 集群。
这里不用急着记 YAML 字段。只要知道,KubeRay 给 Kubernetes 增加了一套「看得懂 Ray」的资源类型。
这几层的关系大概是:
KubeRay 看到 RayCluster / RayJob / RayService
->
创建或维护 Head Pod、Worker Pod、Service
->
Kubernetes 决定这些 Pod 最终落到哪些 Node
KubeRay 负责 Ray 集群在 Kubernetes 里的生命周期,并不替代 Ray 执行计算任务。可以先记成:
KubeRay 管「Ray 集群怎么被创建和维护」。
Ray 管「集群里的计算任务怎么执行」。
6. Ray:在已经拿到的资源里组织计算
6.1 Ray 集群里有什么
一个 Ray 集群可以先粗略看成两类节点:Head 提供集群入口,并运行协调和管理相关组件;Worker 提供执行计算任务的进程和资源。如果 Ray 运行在 Kubernetes 上,它们下面通常对应不同的 Pod。
Kubernetes 看到的是:Head Pod、Worker Pod
Ray 看到的是:Head 节点、Worker 节点和可用计算资源
同一批资源,被两套系统从不同层面观察。
6.2 Task 和 Actor 可以怎么理解
Ray Core 里经常会遇到两个概念,可以先用很简单的方式理解:
Task:一次可以被远程执行的函数调用;Actor:一个可以长期存在并保存状态的 Worker 进程。
比如处理一批独立音频文件时,可以把每个文件的识别工作拆成 Task,让多个 Worker 并行执行。如果模型加载很慢,希望模型加载一次后持续处理请求,就可以让模型实例运行在 Actor 里:
Actor 启动
->
加载模型到内存或 GPU 显存
->
连续处理多个请求
->
保留自己的状态
这已经进入 Kubernetes 不擅长直接表达的计算细节了。
Kubernetes 可以保证「运行模型的 Pod 还活着」,但它不会自动理解一个 Python 函数应该被拆成多少个 Task,也不会替业务管理 Actor 的状态和调用结果。这正是 Ray 发挥作用的位置。
7. Kubernetes 和 Ray 都在调度,到底差在哪
这个问题是整篇文章最关键的地方。
最短的答案是:
Kubernetes 调度 Pod。
Ray 调度 Task 和 Actor。
但只记这两句话还是有点飘。假设语音识别模型需要一张 GPU。
在 Kubernetes 这一层,它看到的需求更像是:
这个 Worker Pod 需要一张 GPU。
请把它放到有可用 GPU 的节点上。
Kubernetes 负责把 Worker Pod 放到合适的 GPU 节点。等 Worker Pod 启动并加入 Ray 集群以后,Ray 看到的需求更像是:
这个模型 Actor 需要一份 GPU 资源。
请把它安排到满足条件的 Ray Worker 上执行。
于是 Ray 再把 Actor 调度到合适的 Worker。完整一点看,大概是这样:
Kubernetes:Worker Pod -> 某台 GPU Node
Ray:模型 Actor -> 某个有 GPU 资源的 Worker
两次调度都和 GPU 有关,但管理对象和发生位置不一样。可以拿公司做一个不太严谨但比较好记的类比:
- Kubernetes 像园区和工位管理,决定哪个项目组在哪栋楼、占多少工位;
- Ray 像项目组内部的任务系统,决定具体任务交给哪个成员处理。
园区管理不会替项目组拆任务,项目组也不能凭空变出办公室。两层会互相影响,但不是同一件事。
8. Ray Serve:把模型能力变成在线服务
Ray Core 解决了 Task、Actor 和分布式执行的问题,但线上业务通常还需要一个稳定的调用入口。比如本地脚本原来是这样用模型的:
python recognize.py audio.wav
真正上线以后,业务系统更希望这样调用:
POST /recognize
->
提交音频
->
返回识别结果
Ray Serve 是 Ray 生态里用于构建可扩展在线推理 API 的模型服务库。它可以把模型代码组织成 Deployment 和副本,并利用 Ray 的资源调度能力运行这些副本。
可以先记成:
Ray Core:让分布式计算跑起来。
Ray Serve:让外部请求能够稳定地调用这些计算能力。
Ray Serve 比较适合模型长期驻留、不同模型独立扩缩容、一个请求经过多个模型,或者需要使用多张 GPU 和多个 Worker 的场景。
但 Ray Serve 不是为了替代所有 Web 框架。
用户登录、订单管理、数据库增删改查这类普通后台逻辑,继续使用 FastAPI、Spring Boot 或 Go Web 框架通常更自然。实际系统里,也经常是业务 API 调用后面的 Ray Serve。
9. 用一个语音识别服务把整条链路串起来
9.1 第一步:准备服务器
最开始有一批 Linux 服务器,其中包括控制节点、普通 CPU 节点和 GPU 节点。机器可以单独登录,但还没有形成统一的 Kubernetes 集群。
9.2 第二步:用 Kubespray 安装 Kubernetes
在 Kubespray 的 Inventory 里描述这些机器分别承担什么角色,然后运行对应的 Ansible Playbook。安装结束以后,得到的是一个 Kubernetes 集群:
多台独立服务器
->
一个可以统一管理 Node 和 Pod 的 Kubernetes 集群
9.3 第三步:安装 KubeRay Operator
接下来把 KubeRay Operator 部署到 Kubernetes 集群。它会监听 RayCluster、RayJob、RayService,并根据声明的目标创建或调整 Kubernetes 资源。
9.4 第四步:创建 Ray 集群
假设提交了一个 RayService,里面描述 Ray 集群规模和 Ray Serve 应用。KubeRay 会协调创建 Head Pod、Worker Pod 和相关 Service;Kubernetes 再根据 Pod 声明的 CPU、内存和 GPU,把它们调度到合适的节点。等这些 Pod 启动并互相连接后,Ray 集群才真正可用。
9.5 第五步:加载语音识别模型
Ray Serve 在 Ray 集群里启动模型副本。模型被加载到内存或 GPU 显存中,并持续等待请求。如果系统还需要做音频切片、并行识别或结果合并,也可以根据业务设计把部分工作拆成 Ray Task 或 Actor 调用。
音频是否切片、怎么合并,属于具体业务算法,不是使用 Ray 后自动发生的事情。Ray 提供执行工具,处理流程仍要由业务代码定义。
9.6 第六步:外部请求进来
一条简化后的请求链路可能是:
用户 / 业务系统
->
Ingress / 网关
->
Kubernetes Service
->
Ray Serve
->
模型副本
->
返回识别结果
这时候再回头看每一层:
- Kubespray 没有参与这次请求,它前面已经把 Kubernetes 搭好了;
- Kubernetes 保证相关 Pod 和网络入口处于可用状态;
- KubeRay 维护 Ray 集群和 Ray Serve 应用的 Kubernetes 生命周期;
- Ray 把计算安排到合适的 Worker;
- Ray Serve 接住在线请求,并调用模型副本完成推理。
10. 有了 Kubernetes,是不是一定要上 Ray
不是。
如果只有一个简单模型,加载在 FastAPI 服务里,每次请求都是独立推理,那么直接这样部署可能已经够用:
Ingress
->
Kubernetes Service
->
FastAPI Deployment
->
模型
Kubernetes 可以管理它的副本、重启、滚动更新和资源请求。这种场景强行再加 Ray,只会多出一套需要维护的系统。可以先用下面几个问题判断:
- 任务是否真的需要跨进程或跨机器并行?
- 是否有很多需要长期保存状态的模型实例?
- 是否需要把一个计算流程拆成多个 Task 或 Actor?
- 是否需要对不同模型组件独立扩缩容?
- 普通 Deployment 和任务队列是不是已经能解决问题?
如果答案大部分是否定的,就不一定需要 Ray。Ray 的价值不是「只要做 AI 就必须使用」,而是在分布式计算变复杂时,提供一套比手工协调进程和机器更自然的运行模型。
11. 这条链路不是固定套餐
为了方便理解,前面一直在使用这条线:
机器 -> Kubespray -> Kubernetes -> KubeRay -> Ray -> Ray Serve
但真实系统里可能缺少其中某几层:
- 使用 EKS、GKE、AKS 等托管 Kubernetes 时,不一定需要 Kubespray;
- Ray 可以直接部署在虚拟机或物理机上,并不依赖 Kubernetes;
- 普通 Web 服务、简单任务或单实例模型,不一定需要 Ray;
- 只做离线批处理、分布式训练或 Ray Job 时,不一定需要 Ray Serve。
所以真正应该记住的不是「必须按顺序把所有组件装一遍」,而是:
先看当前问题需要哪一层能力,再决定引入哪个组件。
12. 最后做一个职责对照
| 组件 | 主要管理对象 | 主要出现阶段 | 解决的问题 |
|---|---|---|---|
Kubespray |
Linux 机器上的 Kubernetes 组件与集群配置 | 集群部署和维护 | 怎么把一批机器安装成 Kubernetes 集群 |
Kubernetes |
Node、Pod、Service 以及 CPU、内存、GPU 等资源 | 长期运行 | 容器放在哪里,运行状态怎么维持 |
KubeRay |
RayCluster、RayJob、RayService 及其 Kubernetes 资源 | Ray 集群部署和维护 | 怎么在 Kubernetes 中创建和管理 Ray 集群 |
Ray Core |
Task、Actor 和 Ray Worker | 计算执行 | 分布式任务怎么调度和执行 |
Ray Serve |
在线推理应用、Deployment 和副本 | 对外服务 | 模型能力怎么变成可扩展的在线 API |
如果表格还是有点多,可以只记下面五句话:
Kubespray 把 Kubernetes 搭起来。
Kubernetes 把 Pod 和资源管起来。
KubeRay 把 Ray 集群管起来。
Ray 把计算任务跑起来。
Ray Serve 把模型服务提供出去。
这五句话不包含所有细节,但已经足够帮小白把几个组件放回正确的位置。
13. 碎碎念
笔者觉得真正容易把人绕晕的,可能并不是某一个组件有多难,而是很多文章一上来就同时谈集群、节点、资源和调度。
每一层都在使用相似的词,但它们眼里看到的东西并不一样:
- Kubespray 看到的是一批需要安装和配置的机器;
- Kubernetes 看到的是 Node、Pod 和底层资源;
- KubeRay 看到的是 Kubernetes 里的 Ray 自定义资源;
- Ray 看到的是 Worker、Task 和 Actor;
- Ray Serve 看到的是在线应用、模型副本和请求。
本着存在即合理的原则,不同层级存在原因有其存在的道理。
-
讲真,我要你现在快乐,毕竟等三十岁再买十八岁时喜欢的裙子就已经没什么意义了。
-
停止喂养任何人,你连想改变别人的念头都不要有,要学太阳一样,只是发出光和热。
14. 参考资料
更多推荐


所有评论(0)