使用 MultiKueue 特性分发作业到多集群
利用 Kueue 的 MultiKueue 特性可以将作业从管理集群分发到工作集群,基本过程如下:
用户提交作业到管理集群
管理集群的 Kueue 控制器拦截作业,并向工作集群提交相同的作业
工作集群按正常流程处理和运行作业

相同的作业在两个集群都要提交一次,因此作业所在的命名空间和队列必须在两个集群中都存在。
目前 Kueue 0.16.2 不支持向管理集群自身分发作业。
工作集群的队列设置与使用 MultiKueue 之前相同,不需要特殊设置,以下是实体关系图(没有使用 Topology):
erDiagram
LocalQueue }o--|| ClusterQueue: ""
ClusterQueue }o--|{ ResourceFlavor: ""
管理集群的 ClusterQueue 需要增加一个特殊的 AdmissionCheck 属性,以下为其实体关系图:
erDiagram
LocalQueue }o--|| ClusterQueue: ""
ClusterQueue }o--|{ ResourceFlavor: ""
ClusterQueue }o--o{ AdmissionCheck : ""
AdmissionCheck }o--o| MultikueueConfig : ""
MultikueueConfig }o--|{ MultikueueCluster : ""
MultikueueCluster }o--|| Secret : ""
可见增加的属性经过多层引用后最终指向了一个 Secret, 这个 Secret 存放着工作集群的 kubeconfig. 这是管理集群中的 Kueue 访问工作集群的依据。
配置
参考 https://kueue.sigs.k8s.io/docs/tasks/manage/setup_multikueue/.
管理集群和工作集群安装同一版本的 Kueue.
在工作集群创建队列不需要额外设置,如下:
apiVersion: kueue.x-k8s.io/v1beta2
kind: ResourceFlavor
metadata:
name: default
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: ClusterQueue
metadata:
name: test
spec:
namespaceSelector: {} # match all.
resourceGroups:
- coveredResources:
- cpu
- memory
- pods
flavors:
- name: default
resources:
- name: cpu
nominalQuota: 8
- name: memory
nominalQuota: 8Gi
- name: pods
nominalQuota: 8
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: LocalQueue
metadata:
namespace: default
name: test
spec:
clusterQueue: test
在管理集群创建队列,需要在 ClusterQueue 上设置 AdmissionCheck, 以下展示的是与工作集群队列的差异:
apiVersion: kueue.x-k8s.io/v1beta2
kind: ClusterQueue
metadata:
- name: test
+ name: to-worker1
spec:
namespaceSelector: {} # match all.
+ admissionChecksStrategy:
+ admissionChecks:
+ - name: worker1-admission-check
resourceGroups:
- coveredResources:
- cpu
namespace: default
name: test
spec:
- clusterQueue: test
+ clusterQueue: to-worker1
注意我们故意修改了 ClusterQueue 的名称,这是为了说明 MultiKueue 分发的原则是相同 namespace, 相同 LocalQueue. 两者之间 ClusterQueue 的设置可以不一致。
在管理集群中创建工作集群的准入设置:
apiVersion: kueue.x-k8s.io/v1beta2
kind: AdmissionCheck
metadata:
name: worker1-admission-check
spec:
controllerName: kueue.x-k8s.io/multikueue
parameters:
apiGroup: kueue.x-k8s.io
kind: MultiKueueConfig
name: worker1-multikueue-config
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: MultiKueueConfig
metadata:
name: worker1-multikueue-config
spec:
clusters:
- worker1
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: MultiKueueCluster
metadata:
name: worker1
spec:
clusterSource:
kubeConfig:
locationType: Secret
location: worker1-secret
这里面 MultiKueueCluster 中的 spec.clusterSource.kubeConfig 引用了一个存放工作集群 kubeconfig 的 Secret, 需要借助一个脚本来产生。脚本的下载地址:https://kueue.sigs.k8s.io/examples/multikueue/create-multikueue-kubeconfig.sh.
这个脚本的作用如下:
在工作集群中创建 ServiceAccount, ClusterRole, ClusterRoleBinding 以便管理集群对工作集群进行操作
为新的 ServiceAccount 创建证书
从当前 kubectl 上下文中提取集群信息,结合生成的证书,创建 kubeconfig 文件
因此它应该在 kubectl 上下文指向工作集群的时候运行。注意 ServiceAccount 和 证书 Secret 需要创建在 Kueue 安装的命名空间内。
运行脚本产生 kubeconfig 文件:
$ ./create-multikueue-kubeconfig.sh worker1.kubeconfig
serviceaccount/multikueue-sa created
clusterrole.rbac.authorization.k8s.io/multikueue-sa-role created
clusterrolebinding.rbac.authorization.k8s.io/multikueue-sa-crb created
secret/multikueue-sa created
Writing kubeconfig in worker1.kubeconfig
在管理集群中,创建 Secret 存放这个 kubeconfig 文件:
$ kubectl create secret generic worker1-secret -n kueue-system --from-file=kubeconfig=worker1.kubeconfig
secret/worker1-secret created
检查状态:
$ kubectl get cq to-worker1 -o jsonpath="{range .status.conditions[?(@.type == \"Active\")]}CQ - Active: {@.status} Reason: {@.reason} Message: {@.message}{'\n'}{end}"
CQ - Active: True Reason: Ready Message: Can admit new workloads
$ kubectl get admissioncheck worker1-admission-check -o jsonpath="{range .status.conditions[?(@.type == \"Active\")]}AC - Active: {@.status} Reason: {@.reason} Message: {@.message}{'\n'}{end}"
AC - Active: True Reason: Active Message: The admission check is active
$ kubectl get multikueuecluster worker1 -o jsonpath="{range .status.conditions[?(@.type == \"Active\")]}MC - Active: {@.status} Reason: {@.reason} Message: {@.message}{'\n'}{end}"
MC - Active: True Reason: Active Message: Connected
这说明工作集群连接成功,可以向队列提交工作负载了。
不成功的可能原因:
管理集群中 Kueue 支持的工作负载类型必须在工作集群中存在
提交作业
提交以下作业:
apiVersion: batch/v1
kind: Job
metadata:
name: sleep-normal
labels:
kueue.x-k8s.io/queue-name: test
spec:
completions: 3
completionMode: Indexed
parallelism: 3
template:
spec:
restartPolicy: OnFailure
containers:
- image: busybox
imagePullPolicy: IfNotPresent
name: busybox-sleep
command: ["sh", "-c", "trap exit INT TERM; sleep 30s & wait"]
resources:
requests:
cpu: "1"
limits:
cpu: "1"
在管理集群上监视作业状态:
$ kubectl get job -w
NAME STATUS COMPLETIONS DURATION AGE
sleep-normal Running 0/3 0s
sleep-normal Running 0/3 0s
sleep-normal Running 0/3 0s 0s
sleep-normal Running 0/3 3s 3s
sleep-normal Running 2/3 33s 33s
sleep-normal Complete 3/3 34s 34s
同时在工作集群上监视作业状态:
$ kubectl get job -w
NAME STATUS COMPLETIONS DURATION AGE
sleep-normal Running 0/3 0s
sleep-normal Suspended 0/3 0s
sleep-normal Suspended 0/3 0s
sleep-normal Running 0/3 0s 0s
sleep-normal Running 0/3 3s 3s
sleep-normal Running 0/3 32s 32s
sleep-normal Running 2/3 33s 33s
sleep-normal SuccessCriteriaMet 3/3 34s 34s
sleep-normal Complete 3/3 34s 34s
sleep-normal Complete 3/3 34s 34s
另外可以发现:
管理集群内没有为 Job 创建 Pod, 工作集群中的 Job 按正常流程运行
当作业完成后,工作集群内的 Job 被删除,而管理集群内的 Job 仍然保留