RayJob 的 Gang 调度和优先级调度与 Kueue#
本指南演示了在本地 Kind 集群上使用 RayJob 进行 KubeRay 和 Kueue 的 gang 和优先级调度。请参考 使用 RayJob 和 Kueue 进行优先级调度 和 使用 RayJob 和 Kueue 进行 Gang 调度 以了解实际用例。
Kueue#
Kueue 是一个 Kubernetes 原生的作业排队系统,用于管理配额以及作业如何消耗这些配额。Kueue 决定何时:
使任务等待。
要允许一个作业启动,这将触发 Kubernetes 创建 Pod。
要抢占一个作业,这将触发 Kubernetes 删除活动 Pod。
Kueue 对一些 KubeRay API 提供了原生支持。具体来说,您可以使用 Kueue 来管理 RayJob 和 RayCluster 消耗的资源。请参阅 Kueue 文档 以了解更多信息。
步骤 0:创建一个 Kind 集群#
kind create cluster
步骤 1:安装 KubeRay 操作员#
按照 部署 KubeRay 操作员 来从 Helm 仓库安装最新稳定的 KubeRay 操作员。
步骤 2: 安装 Kueue#
VERSION=v0.6.0
kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
有关安装 Kueue 的更多详细信息,请参阅 Kueue 安装。Kueue 和 RayJob 之间存在一些限制。有关更多详细信息,请参阅 Kueue 的限制。
步骤 3:创建 Kueue 资源#
# kueue-resources.yaml
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: "default-flavor"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: "cluster-queue"
spec:
preemption:
withinClusterQueue: LowerPriority
namespaceSelector: {} # Match all namespaces.
resourceGroups:
- coveredResources: ["cpu", "memory"]
flavors:
- name: "default-flavor"
resources:
- name: "cpu"
nominalQuota: 3
- name: "memory"
nominalQuota: 6G
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
namespace: "default"
name: "user-queue"
spec:
clusterQueue: "cluster-queue"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: WorkloadPriorityClass
metadata:
name: prod-priority
value: 1000
description: "Priority class for prod jobs"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: WorkloadPriorityClass
metadata:
name: dev-priority
value: 100
description: "Priority class for development jobs"
YAML 清单配置:
ResourceFlavor
ResourceFlavor
default-flavor
是一个空的 ResourceFlavor,因为 Kubernetes 集群中的计算资源是同质的。换句话说,用户可以请求 1 个 CPU 而不必考虑它是 ARM 芯片还是 x86 芯片。
ClusterQueue
ClusterQueue
cluster-queue
只有一个 ResourceFlavordefault-flavor
,配额为 3 个 CPU 和 6G 内存。ClusterQueue
cluster-queue
有一个抢占策略withinClusterQueue: LowerPriority
。此策略允许待处理的 RayJob,如果其在 ClusterQueue 的名义配额内无法容纳,则可以抢占 ClusterQueue 中优先级较低的活跃 RayJob 自定义资源。
LocalQueue
LocalQueue
user-queue
是default
命名空间中的一个命名空间对象,属于一个 ClusterQueue。典型的做法是将命名空间分配给组织的租户、团队或用户。用户将作业提交到 LocalQueue,而不是直接提交到 ClusterQueue。
工作负载优先级类
工作负载优先级类
prod-priority
的值高于工作负载优先级类dev-priority
。具有prod-priority
优先级类的 RayJob 自定义资源优先于具有dev-priority
优先级类的 RayJob 自定义资源。
创建 Kueue 资源:
kubectl apply -f kueue-resources.yaml
步骤 4:使用 Kueue 进行 Gang 调度#
Kueue 始终以“gang”模式接纳工作负载。Kueue 以“全有或全无”的方式接纳工作负载,确保 Kubernetes 永远不会部分配置 RayJob 或 RayCluster。使用 gang 调度策略来避免因工作负载调度效率低下而导致的计算资源浪费。
从 KubeRay 仓库下载 RayJob YAML 清单。
curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/ray-job.kueue-toy-sample.yaml
在创建 RayJob 之前,请使用以下内容修改 RayJob 元数据:
metadata:
generateName: rayjob-sample-
labels:
kueue.x-k8s.io/queue-name: user-queue
kueue.x-k8s.io/priority-class: dev-priority
创建两个具有相同优先级 dev-priority
的 RayJob 自定义资源。请注意 RayJob 自定义资源的这些重要点:
RayJob 自定义资源包括 1 个头节点 Pod 和 1 个工作节点 Pod,每个 Pod 请求 1 个 CPU 和 2G 内存。
RayJob 运行一个简单的 Python 脚本,该脚本演示了一个运行 600 次迭代的循环,每次迭代打印迭代次数并在每次迭代中休眠 1 秒。因此,在提交的 Kubernetes Job 启动后,RayJob 大约运行 600 秒。
将
shutdownAfterJobFinishes
设置为 true 以启用 RayJob 的自动清理。此设置会触发 KubeRay 在 RayJob 完成后删除 RayCluster。Kueue 不会处理
shutdownAfterJobFinishes
设置为 false 的 RayJob 自定义资源。更多详情请参见 Kueue 的限制。
kubectl create -f ray-job.kueue-toy-sample.yaml
kubectl create -f ray-job.kueue-toy-sample.yaml
每个 RayJob 自定义资源总共请求 2 个 CPU 和 4G 内存。然而,ClusterQueue 总共只有 3 个 CPU 和 6G 内存。因此,第二个 RayJob 自定义资源保持挂起状态,即使剩余资源足以创建一个 Pod,KubeRay 也不会从挂起的 RayJob 创建 Pod。你还可以检查 ClusterQueue
以查看可用和已使用的配额:
$ kubectl get clusterqueues.kueue.x-k8s.io
NAME COHORT PENDING WORKLOADS
cluster-queue 1
$ kubectl get clusterqueues.kueue.x-k8s.io cluster-queue -o yaml
Status:
Admitted Workloads: 1 # Workloads admitted by queue.
Conditions:
Last Transition Time: 2024-02-28T22:41:28Z
Message: Can admit new workloads
Reason: Ready
Status: True
Type: Active
Flavors Reservation:
Name: default-flavor
Resources:
Borrowed: 0
Name: cpu
Total: 2
Borrowed: 0
Name: memory
Total: 4Gi
Flavors Usage:
Name: default-flavor
Resources:
Borrowed: 0
Name: cpu
Total: 2
Borrowed: 0
Name: memory
Total: 4Gi
Pending Workloads: 1
Reserving Workloads: 1
Kueue 在第一个 RayJob 自定义资源完成后,允许挂起的 RayJob 自定义资源。检查 RayJob 自定义资源的状态,并在它们完成后删除它们:
$ kubectl get rayjobs.ray.io
NAME JOB STATUS DEPLOYMENT STATUS START TIME END TIME AGE
rayjob-sample-ckvq4 SUCCEEDED Complete xxxxx xxxxx xxx
rayjob-sample-p5msp SUCCEEDED Complete xxxxx xxxxx xxx
$ kubectl delete rayjob rayjob-sample-ckvq4
$ kubectl delete rayjob rayjob-sample-p5msp
步骤 5:使用 Kueue 进行优先级调度#
此步骤首先创建一个优先级较低的 RayJob dev-priority
,然后创建一个优先级较高的 RayJob prod-priority
。优先级较高的 RayJob prod-priority
优先于优先级较低的 RayJob dev-priority
。Kueue 会抢占优先级较低的 RayJob,以接纳优先级较高的 RayJob。
如果你按照上一步操作,RayJob YAML 清单 ray-job.kueue-toy-sample.yaml
应该已经设置为 dev-priority
优先级类。使用较低优先级类 dev-priority
创建一个 RayJob:
kubectl create -f ray-job.kueue-toy-sample.yaml
在创建高优先级类 prod-priority
的 RayJob 之前,请使用以下内容修改 RayJob 元数据:
metadata:
generateName: rayjob-sample-
labels:
kueue.x-k8s.io/queue-name: user-queue
kueue.x-k8s.io/priority-class: prod-priority
使用更高优先级类 prod-priority
创建一个 RayJob:
kubectl create -f ray-job.kueue-toy-sample.yaml
你可以看到 KubeRay 操作符删除了属于优先级较低的 dev-priority
的 RayJob 的 Pod,并创建了属于优先级较高的 prod-priority
的 RayJob 的 Pod。