KubeRay 与 Volcano:从 RayJob 到 PodGroup

KubeRay 与 Volcano:从 RayJob 到 PodGroup

💡 原文中文,约9500字,阅读约需23分钟。
📝

内容提要

KubeRay Operator 通过 Volcano 适配器将 RayJob 转换为 PodGroup 等调度资源。适配器创建 PodGroup,设置 owner 引用、分组注解和 schedulerName;最低成员数不含 submitter 以避免启动死锁,但其资源仍提前计入。资源计算基于模板 requests,未涵盖 init 容器等。收尾时按存活集群重算需求,而非直接清零。

🔎

延伸解读

适配器在 Operator 进程内,与 Volcano Scheduler 解耦

KubeRay 的 Volcano 适配器运行在 Operator 进程内,负责创建和更新 PodGroup 等 Kubernetes 资源;独立的 Volcano Scheduler 则观察这些对象并绑定 Pod。两者之间没有直接的作业提交 RPC,仅通过 Kubernetes 资源协作。这意味着适配器不实现节点选择,而是把 RayJob 的生命周期转换成调度器能观察的声明。

minMember 排除 submitter 以避免启动死锁

RayJob Controller 需先观察 RayCluster 就绪,再创建 submitter Job。若将 submitter 计入 minMember,Gang 调度要求凑够四个成员,但第四个 Pod 此时尚未创建,导致集群无法启动,submitter 也等不到创建条件。因此适配器将 submitter 排除在 minMember 外,但将其资源提前计入 minResources,以便参与后续准入约束。

资源计算基于模板 requests,需与实际 Pod 核对

CalculatePodResource 遍历 podSpec.Containers,读取 requests,缺失时从 limits 补入,然后求和。它不涵盖 init container、Pod overhead 或 Admission 阶段注入的 sidecar。若模板包含这些因素,最终 Pod 的请求可能大于适配器计算的 minResources。因此应同时核对最终 Pod 请求与适配器生成的 minResources,避免调度需求偏差。

收尾时按存活集群重算,而非直接清零

CleanupOnCompletion 根据 status.rayClusterName 查询实际集群,按存活集群 spec 重算最低成员和资源量。若集群存在且未删除,则保留需求;若 worker 组暂停,则跳过暂停组;若集群已不存在或进入删除流程,才将需求置空。更新为零也不等于节点资源已释放,实际占用仍随 Pod 生命周期变化。

Q&A

KubeRay 的 Volcano 适配器是如何把 RayJob 转换成 PodGroup 的?

适配器在 Operator 进程内运行,通过 DoBatchSchedulingOnSubmission 为 RayJob 创建或更新 PodGroup,设置 owner reference 指向 RayJob,并填写分组 annotation、label 和 Pod 的 schedulerName。PodGroup 名称由 RayJob 名生成,如 ray-demo-job-pg。

为什么 PodGroup 的最低成员数不包含 submitter?

因为 RayJob Controller 需要先观察 RayCluster 就绪,再创建 submitter Job。如果把 submitter 计入最低成员数,组需要凑够四个成员,但第四个 Pod 此时还未创建,Gang 不放行会导致集群无法启动,形成死锁。因此 minMember 只包含 head 和 worker,但 submitter 的资源仍提前计入 minResources。

适配器计算资源需求时,是否考虑了 init 容器和 Pod overhead?

没有。CalculatePodResource 只遍历 podSpec.Containers,读取每个容器的 requests(缺失时从 limits 补入)并求和,没有完整复刻 Kubernetes 对 init container 和 Pod overhead 的资源计算规则。因此若模板包含资源较大的 init container 或自动注入的 sidecar,最终 Pod 请求可能与适配器生成的 minResources 不一致。

RayJob 完成或暂停后,PodGroup 的资源是如何清理的?

CleanupOnCompletion 会根据 status.rayClusterName 查找实际集群并重算需求:集群存在且未删除时按存活集群 spec 重算;worker 组暂停时跳过暂停组;集群已不存在或进入删除流程时,将最低成员和资源需求更新为空。K8sJobMode 正常完成的独立 submitter 不再追加其资源。直接创建的 RayCluster 不经过此方法。

Pod 是如何关联到同一个 PodGroup 的?

通过 AddMetadataToChildResource 在构造 Pod 时写入关联信息:设置 Pod 的 schedulerName 为 volcano,添加 annotation scheduling.k8s.io/group-name 指向 PodGroup 名称,添加 annotation volcano.sh/task-spec 区分角色(head 为 headgroup,worker 为 compute,submitter 为 submittergroup),并可能添加 queue-name 和 priority-class-name 等 label。

启用自动扩缩容后,PodGroup 的资源需求如何计算?

启用自动扩缩容时,calculatePodGroupParams 使用 CalculateMinReplicas 和 CalculateMinResources 计算最低副本数和资源,加上 head 的资源,不会把最大扩容规模作为启动门槛。后续扩出的 worker 仍需竞争资源。计算时还会将 worker 组的副本数乘以 numOfHosts 得到实际 Pod 数,暂停的组会被跳过。

🏷️

标签

➡️

继续阅读