この記事の情報は2025年5月時点(v0.11.4)での情報をもとに作成しています。
Kueueのベータに昇格した機能の一つであり、外部クラスタへのスケジューリング機能として注目されるMultiKueueについて解説します。この機能はKueueが導入されたKubernetessクラスタをワークロードを投入するManagerクラスタと実行環境となるWorkerクラスタに分離して、ワークロード実行をクラスタ間で分散するためのものです。

開発は現在も積極的に続いており、2025年のロードマップにも次のような記載がされています。
Improve user experience for MultiKueue – multi-cluster Job dispatching, in particular:
Kueueの新機能の実装方針などの詳細はKueue Enhancement Proposal (KEP)にまとめられています。KEPはKueueと同じリポジトリに含まれており、MultiKueueの場合はKEP-693で詳細を確認できます。MultiKueueのスコープに関してはGoals/Non-Goalsを確認して下さい。
Kueueの基本機能についてはKueueによるKubernetesネイティブなジョブ制御を試してみるをご確認ください。
MultiKueueでできること/できないこと
MultiKueueは積極的に開発が進められていますが、現時点で細かい機能まで実装されているわけではありません。以下に簡単に例を挙げてみます。詳細を注意点として最後に触れます。
できること
- ManagerクラスタのClusterQueueに入ったワークロードをWorkerクラスタで実行する
- 外部クラスタにスケジューリングしたワークロードのステータスをManagerクラスタに同期させる
- (ClusterQueueごとに)ユーザーがデプロイ先のWorkerクラスタ設定する
できないこと
- Manager KueueがWorker KueueのnominalQuotaを参照する
- Manager KueueでWorkerクラスタごとのnominalQuotaを設定する
- 単一のClusterQueueに複数のWorkerクラスタが割り当てられている場合にデプロイ先を指定する
- Workerクラスタに優先度をつけるようなスケジューリング戦略を設定する
サポートされているワークロードの種類
現在MultiKueueでは次のワークロードがサポートされています。
- batch/Job
- JobSet
- Kubeflow
- KubeRay
- MPIJob
- Plain Pod
- Deployments
- Appwrappers
環境構築

セットアップ
MultiKueueはバージョン0.9以降デフォルトで有効になっているため、Kueueを通常の手順通りに各クラスタへデプロイします。まずはドキュメントの手順に従い、Manager Kueueが参照するWorkerクラスタのkubeconfigを生成します。
https://kueue.sigs.k8s.io/docs/tasks/manage/setup_multikueue/#multikueue-specific-kubeconfig
# kubeconfig のコンテキストを Worker クラスタに設定して実行
$ chmod +x create-multikueue-kubeconfig.sh
$ ./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
ドキュメント内で提供されているスクリプトのClusterRoleの項目にはMultikueueでサポートしているAPIのリストが含まれています。もし、jobsetやtfjob等のサードパーティーのジョブを使用しない場合には該当の箇所を一部削除して依存を解消することで、必要のないCRD不足エラーを解消することができます。
スクリプトによってサービスアカウントがWorkerクラスタへ作成され、アクセスするためのkubeconfigがファイルとして生成されました。このkubeconfigはManagerクラスタにSecretとしてデプロイし、後に作成するMultiKueueConfigによってKueueが参照して使用します。
# Managerクラスタに対して実行します
$ kubectl create secret generic worker1-secret -n kueue-system --from-file=kubeconfig=worker1.kubeconfig
💡オプションとして、先日Open Cluster Managementを使用したMultiKueue環境の設定がドキュメントに追記されました。これを利用してより良い環境のセットアップを行える可能性がありますが、環境にインストールするコンポーネントが増えることに注意が必要です。https://kueue.sigs.k8s.io/docs/tasks/manage/setup_multikueue/#optional-setup-multikueue-with-open-cluster-management
Managerクラスタの設定作成
ここからはKueueのカスタムリソースを構成してMultikueueの設定を行います。MultiKueueの構成はManagerクラスタが行うこととなり、Workerクラスタについては基本的なKueueの設定のみを行います。
MultiKueueはClusterQueueに対してAdmissionCheckの追加によって有効化されます。MultiKueueのAdmissionCheckにはMultiKueueClusterとMultiKueueConfigリソースが必要です。MultiKueueClusterでは前述の手順で作成したSecretを指定します。MultiKueueConfigはWorkerクラスタとなるMultiKueueClusterのリストとして作成します。
Setup a MultiKueue environment
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: "cluster-queue" #このClusterQueueがMultiKueueの対象になります
spec:
...
admissionChecks:
- sample-multikueue # admissionCheckをClusterQueueに紐づけてMultikeueを設定します
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: AdmissionCheck
metadata:
name: sample-multikueue
spec:
controllerName: kueue.x-k8s.io/multikueue # Multikueueのための指定
parameters:
apiGroup: kueue.x-k8s.io
kind: MultiKueueConfig
name: multikueue-test
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: MultiKueueConfig
metadata:
name: multikueue-test
spec:
clusters:
- multikueue-test-worker1 #1つ以上のWorkerクラスタ(kind: MultiKueueCluster)を指定します
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: MultiKueueCluster
metadata:
name: multikueue-test-worker1
spec:
kubeConfig:
locationType: Secret
location: worker1-secret #前手順で作成したkubeconfigを格納したsecret名を指定します
ここまでの設定で、cluster-queueという名前のClusterQueueに入ったワークロードはMultiKueueの対象になります。MultiKueueClusterリソースではWorkerクラスタとして利用できるかの情報を提供しているため、作成時点で一度確認しておくのが良いです。例えば特定のCRDが存在しない等のエラーで状態がFalseになっているケースがあります。
$ kubectl get multikueuecluster
NAME CONNECTED AGE
multikueue-test-worker1 True 28d
multikueue-test-worker2 False 22h # 何か問題が発生しているため、describeで確認します
Workerクラスタの設定作成
WorkerクラスタにはManagerクラスタでAdmitされたWorkloadリソースの情報がそのまま伝播されるため、ClusterQueueの名前などはManagerに準拠して作成を行っておく必要があります。また、WorkerクラスタのClusterQueueにいてもAdmitが行われるように基本的なKueueの環境構築は行っておく必要があります。その他、MukltiKueueに関するAdmissionCheckなどは必要なく、手順序盤のスクリプトによるサービスアカウントと権限の付与を行われていれば動作します。
利用の流れ
ワークロードを作成するユーザーはKueueを利用する通常の方法でMultiKueueを利用できます。ユーザーが指定したLocalQueueがMultiKueueを使用するClusterQueueを参照していた場合に、MultiKueueによってワークロードがWorkerクラスタへデプロイされます。
- ユーザーがManager Clusterにワークロードを作成する
- Manager Kueueがワークロードをsuspend処理し、Workloadリソースを作成する
- ManagerクラスタのClusterQueueでAdmissionCheckが行われ、Admitとなった場合にWorkerクラスタへのスケジューリングが行われる
- WorkerクラスタへWorkloadリソースが同期され、WorkerクラスタのClusterQueueでAdmitが行われる
- ManagerクラスタによってAdmitされたWorkerクラスタ以外からWorkloadリソースを削除する
- Workerクラスタでワークロードが作成され、実行される
- (MultiKueueBatchJobWithManagedByが有効の場合)ワークロードの状態が同期されるため、Workerクラスタで実行開始した場合にManagerクラスタで作成したワークロードのsuspendが解除される
- Workerクラスタでワークロードの実行が完了し、ManagerクラスタのWorkloadリソースがFINISHEDに更新される
- (MultiKueueBatchJobWithManagedByが有効の場合)ワークロードの状態が同期されるため、Workerクラスタで実行が完了した時点でManagerクラスタで作成したワークロードが完了ステータスに変更される
リソース確保のため複数リージョンへのデプロイを構築する例
最近ではクラウドでのGPUリソースの需要が高騰した影響で、オンデマンドGPUの要求時にリソースを確保できずワークロードが実行できない等事象が発生する可能性が高まっています。Google CloudはGKEでのMultiKueue利用のケースとして、KueueのProvisioning AdmissionCheckとDynamic Workload Scheduler(DWS)を利用し、複数のリージョンでのGPUリソース確保するデモをブログに掲載しました。
この例ではMultiKueueを利用して別リージョンに構築したGKEにワークロードをスケジュールし、WorkerクラスタとなったGKEでDWSを使用したGPUリソースの要求を行います。
MultiKueue の活用により GKE クラスタであらゆるロケーションの GPU が利用可能 | Google Cloud 公式ブログ
Google Cloudではオンデマンドに利用できるリージョン内GPUの在庫情報を提供していないため、そのままではGPUの在庫状況によってワークロードが実行できない可能性を排除することはできません。
ワークロードを実行するリージョンを増やすことで実質的に要求できるGPU在庫を増やしつつ、要件に合うワークロードはDWSを使用することで効率的なリソース要求を行うことで、最大限リソースを活用することを目指せます。
Google Cloudはワークロードが次の条件を満たしている場合にDWSを使用することを推奨しています。
ワークロードが次のすべての条件を満たしている場合は、Dynamic Workload Scheduler を使用することをおすすめします。
- ワークロードを実行するために GPU をリクエストする。
- 予約済みの GPU 容量が限られているかゼロであり、GPU リソースの入手可能性を改善したい。
- ワークロードに時間的な制約がなく、リクエストしたすべての容量を取得するまで待つことが可能なユースケースである。たとえば、ピーク時以外に GPU リソースを GKE が割り当てる場合などです。
- ワークロードに複数のノードが必要であり、すべての GPU ノードがプロビジョニングされて同時に準備が整うまでワークロードの実行を開始できない(分散 ML トレーニングなど)。
https://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?hl=ja
注意点
クラスタ環境をnominalQuotaに反映する
ClusterQueueではadmissionCheckStrategyRule.onFlavorsを使用することでAdmissionCheckを適用するResourceFlavorを指定することができますが、MultiKueueのAdmissionCheckについてはこの設定を適用することができません。(https://github.com/kubernetes-sigs/kueue/pull/2047)
そのためResourceFlavorに各WorkerクラスタのnominalQuotaを設定しておくような使い方はできず、ManagerクラスタのClusterQueueのnominalQuotaはWorkerクラスタのnominalQuotaの合計としておく必要があると明記されています。(https://kueue.sigs.k8s.io/docs/concepts/multikueue/#manager-cluster)
ManagerクラスタのnominalQuotaが不足していた場合にWorkerクラスタのリソースを使い切ることができなくなってしまいます。そのため、基本的には算出した合計値をClusterQueueに設定しておくことになりますが、管理上の対処としてCohortをWorkerクラスタごとに作成して、Workerクラスタ全体のnominalQuotaの合計をClusterQueueから参照できるようにする方法があります。
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: "multikueue"
spec:
cohort: "multikueue"
namespaceSelector: {} # match all.
resourceGroups:
- coveredResources: ["cpu", "memory","ephemeral-storage"]
flavors:
- name: "default-flavor"
resources:
- name: "cpu"
nominalQuota: 0
- name: "memory"
nominalQuota: 0
flavorFungibility:
whenCanBorrow: Borrow
admissionChecksStrategy:
admissionChecks:
- name: "multikueue"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: "worker1" #クラスタごとに作成し、cohort経由で参照する
spec:
cohort: "multikueue"
namespaceSelector: {} # match all.
resourceGroups:
- coveredResources: ["cpu", "memory","ephemeral-storage"]
flavors:
- name: "default-flavor"
resources:
- name: "cpu"
nominalQuota: 6
- name: "memory"
nominalQuota: 10Gi
例外として、前項目で言及したGoogle CloudのDWS利用例ではDWSがワークロード待ちを許容する特性のためManagerクラスタのnominalQuotaには10000/10000Giといった大きい値を入れておくことでWorkerクラスタ側に意図せず割り当てされない事象が発生しないようにしています。
しかし、これはDWSの特性を前提にしたものであるため、オンプレの環境やリソースクォータが明確に決まっているものについては各クラスタのリソース情報を整理した上でClusterQueueを作成する必要があります。
WorkerクラスタでAdmitされた後にワークロードを実行できないケースをカバーできない
KueueによるAdmitはClusterQueueの情報をベースにしたものであり、クラスタやクラウドのリソース状況を保証するものではありません。nominalQuotaと実際のリソース状況が乖離した場合や、ジョブの実行に必須となる要素がWorkerクラスタ内で不足していた場合に問題が発生することがあります。
Managerクラスタから発行されたワークロードがWorkerクラスタでAdmitされた後に他のWorkerクラスタではスケジューリングされないため、リソース不足など何らかの理由によって割り当てられたWorkerクラスタでワークロードを実行できない場合にはPendingのままスタックしてしまいます。
特にGKE Autopilotのようなオンデマンドにリソースを確保する環境では正確なnominalQuotaを設定することが難しく、GPUなど不足しやすいリソースを要求する場合に意図しない待ちが発生する可能性があります。
Workerクラスタごとにoverrideポリシーが設定できない
KarmadaのOverride Plicyのような機能はまだありません。異なるリージョンごとにWorkerクラスタを配置した場合、リージョンに合わせたコンテナレジストリを使用したイメージ名に書き換えることで機能的な利点を得たいことがあります。MultiKueueでは現在実施することができません。
単一のClusterQueueでリソースが足りない場合にのみMultiKueueを利用するケースに対応できない
デフォルトでは単一クラスタのKueueとして動作するようにし、そのクラスタでのリソースが不足した場合にのみMultiKueueを利用して外部クラスタでワークロードを実行したいケースがあります。(例えば、Managerクラスタがワークロードを実行したい環境でもあるとします) 特にGPU確保のために外部クラスタにスケジューリングをしたい場合にもこのケースに該当することがあります。現状ではMultiKueueのAdmissinCheckがflavorごとに設定できないことから、Multikueueを使用するClusterQueueと使用しないClusterQueueの両方を作成する必要があります。ここでワークロードが1つのLocalQueueを指定でき、LocalQueueでは1つのClusterQueueのみ指定できることから、ワークロードの発行時点でMultiKueueの利用が判断されている必要があります。
スケジュール先の選定に関するオプションがない
ClusterQueueに登録されたWorkloadはMultiKueueConfigに登録されているMultiKueueClusterを対象としてスケジュールが試みられます。このとき全てのMultiKueueClusterでスケジュールが発生するため、特に全てのWorkerクラスタがAdmitの条件を満たす場合にはスケジュール先がランダムになります。
運用の観点では、MultiKueueClusterに優先度をつけることで特定のワークロードを適したWorkerクラスタに優先的にスケジュールしたいケース考えられます。関連して次のIssueが2025年のロードマップに記載されているため、将来的に実装される可能性があります。https://github.com/kubernetes-sigs/kueue/issues/3757
ClusterQueueに対して1つのMultiKueueのAdmissionCheckが指定できるため、複数のClusterQueueにそれぞれ1つのWorkerクラスタを設定することでワークロードの投入先を制御することは可能です。
最後に
本記事ではKueueの機能の一つであるMultiKueueについてまとめました。現時点で多くの要求に対応することはできませんが、今後の機能開発によりKueueの基本機能と合わせた多くのことができるようになると期待できます。GPUを使用したワークロードの需要が高まっている昨今の課題を解決できる大きな機能でもあると思いますので、MultiKueueの今後に注目しましょう。
参考リンク
- https://kueue.sigs.k8s.io/docs/concepts/multikueue/
- https://kueue.sigs.k8s.io/docs/tasks/manage/setup_multikueue/
- https://github.com/kubernetes-sigs/kueue/tree/main/keps/693-multikueue
- https://cloud.google.com/blog/ja/products/containers-kubernetes/using-multikueue-to-provision-global-gpu-resourceshttps://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?hl=ja#kueue
- https://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?hl=ja#kueue