このチュートリアルでは、Kueue を使用して、ジョブ キューイング システムの実装、Google Kubernetes Engine(GKE)上の異なる Namespace 間のワークロード リソースと割り当て共有の構成、クラスタの使用率の最大化について説明します。
背景
インフラストラクチャ エンジニアやクラスタ管理者としては、Namespace の間で使用率を最大化することが非常に重要です。ある Namespace 内のジョブのバッチが、その Namespace に割り当てられた割り当てをすべて使用できない場合があります。一方、別の Namespace には保留中のジョブが複数存在する場合があります。異なる Namespace のジョブ間でクラスタ リソースを効率的に利用し、割り当て管理の柔軟性を高めるために、Kueue でコホートを構成できます。コホートとは、未使用の割り当てを互いに借用できる ClusterQueues のグループです。ClusterQueue は、CPU、メモリ、ハードウェア アクセラレータなどのリソースのプールを管理します。
このようなコンセプト全体の定義については、Kueue のドキュメントをご覧ください。
ResourceFlavors を作成する
ResourceFlavor は、各種 VM(Spot とオンデマンドなど)、アーキテクチャ(x86 CPU と ARM CPU など)、ブランドとモデル(Nvidia A100 GPU と T4 GPU など)などのクラスタノードのリソース バリエーションを表します。
ResourceFlavor は、ノードラベルと taint を使用して、クラスタ内のノードのセットを照合します。
このマニフェストの内容:
- ResourceFlavor
on-demand
のラベルがcloud.google.com/gke-provisioning: standard
に設定されています。 - ResourceFlavor
spot
のラベルがcloud.google.com/gke-provisioning: spot
に設定されています。
ワークロードに ResourceFlavor が割り当てられると、Kueue は ResourceFlavor に定義されたノードラベルに一致するノードにワークロードの Pod を割り当てます。
ResourceFlavor をデプロイします。
kubectl apply -f flavors.yaml
ClusterQueue と LocalQueue を作成する
2 つの ClusterQueue(cq-team-a
と cq-team-b
)とそれに対応する LocalQueues(lq-team-a
と lq-team-b
)には、それぞれ team-a
と team-b
という Namespace が設定されます。
ClusterQueues は、CPU、メモリ、ハードウェア アクセラレータなどのリソースのプールを管理するクラスタ スコープ オブジェクトです。Batch 管理者は、これらのオブジェクトをバッチユーザーにのみ表示するように制限できます。
LocalQueue は、バッチユーザーが一覧表示できる Namespace 付きのオブジェクトです。LocalQueues は CluterQueues を指し、CluterQueues で LocalQueue のワークロードを実行するためのリソースが割り当てられます。
ClusterQueue を使用すると、リソースに複数のフレーバーを持つことができます。この場合、どちらの ClusterQueue にも on-demand
と spot
の 2 つのフレーバーがあり、それぞれが cpu
リソースを提供しています。ResourceFlavor spot
の割り当ては 0
に設定されており、ここでは使用されません。
どちらの ClusterQueue も、.spec.cohort
で定義された all-teams
という同じコホートを共有します。複数の ClusterQueue が同じコホートを共有する場合、互いに未使用の割り当てを借用できます。
コホートの仕組みと借用の意味については、Kueue のドキュメントをご覧ください。
ClusterQueues と LocalQueues をデプロイします。
kubectl apply -f cq-team-a.yaml
kubectl apply -f cq-team-b.yaml
(省略可)kube-prometheus を使用してワークロードをモニタリングする
Prometheus を使用して、アクティブな Kueue ワークロードと保留中の Kueue ワークロードをモニタリングできます。起動中のワークロードをモニタリングして ClusterQueue の負荷を監視するには、Namespace monitoring
の下にあるクラスタに kube-prometheus をデプロイします。
Prometheus オペレーターのソースコードをダウンロードします。
cd git clone https://github.com/prometheus-operator/kube-prometheus.git
CustomResourceDefinitions(CRD)を作成します。
kubectl create -f kube-prometheus/manifests/setup
モニタリング コンポーネントを作成します。
kubectl create -f kube-prometheus/manifests
prometheus-operator
が Kueue コンポーネントから指標をスクレイピングできるようにします。kubectl apply -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/prometheus.yaml
作業ディレクトリを変更します。
cd kubernetes-engine-samples/batch/kueue-cohort
GKE クラスタで実行されている Prometheus サービスへのポート転送を設定します。
kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
ブラウザから、localhost:9090 で Prometheus ウェブ UI を開きます。
Cloud Shell で次の操作を行います。
[ウェブでプレビュー] をクリックします。
[ポートを変更] をクリックし、ポート番号を
9090
に設定します。[変更してプレビュー] をクリックします。
次の Prometheus ウェブ UI が表示されます。
[式] クエリボックスに次のクエリを入力して、
cq-team-a
ClusterQueue のアクティブなワークロードをモニタリングする最初のパネルを作成します。kueue_pending_workloads{cluster_queue="cq-team-a", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-a"}
[Add Panel] をクリックします。
[式] クエリボックスに次のクエリを入力して、
cq-team-b
ClusterQueue のアクティブなワークロードをモニタリングする別のパネルを作成します。kueue_pending_workloads{cluster_queue="cq-team-b", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-b"}
[Add Panel] をクリックします。
[式] クエリボックスに次のクエリを入力して、クラスタ内のノード数をモニタリングするパネルを作成します。
count(kube_node_info)
(省略可)Google Cloud Managed Service for Prometheus を使用してワークロードをモニタリングする
Google Cloud Managed Service for Prometheus を使用して、アクティブな Kueue ワークロードと保留中の Kueue ワークロードをモニタリングできます。指標の完全なリストについては、Kueue のドキュメントをご覧ください。
指標へのアクセス用に ID と RBAC を設定します。
次の構成では、Google Cloud Managed Service for Prometheus コレクタに指標アクセスを提供する 4 つの Kubernetes リソースが作成されます。
kueue-system
Namespace 内のkueue-metrics-reader
という名前の ServiceAccount が、キューの指標にアクセスする際の認証に使用されます。kueue-metrics-reader
サービス アカウントに関連付けられた Secret には、コレクタで使用される認証トークンが保存されます。このトークンは、Kueue デプロイによって公開される指標エンドポイントで認証に使用されます。kueue-system
Namespace 内のkueue-secret-reader
という名前のロール。サービス アカウント トークンを含む Secret の読み取りを許可します。kueue-metrics-reader
サービス アカウントにkueue-metrics-reader
ClusterRole を付与する ClusterRoleBinding。
apiVersion: v1 kind: ServiceAccount metadata: name: kueue-metrics-reader namespace: kueue-system --- apiVersion: v1 kind: Secret metadata: name: kueue-metrics-reader-token namespace: kueue-system annotations: kubernetes.io/service-account.name: kueue-metrics-reader type: kubernetes.io/service-account-token --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: kueue-secret-reader namespace: kueue-system rules: - resources: - secrets apiGroups: [""] verbs: ["get", "list", "watch"] resourceNames: ["kueue-metrics-reader-token"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kueue-metrics-reader subjects: - kind: ServiceAccount name: kueue-metrics-reader namespace: kueue-system roleRef: kind: ClusterRole name: kueue-metrics-reader apiGroup: rbac.authorization.k8s.io
Google Cloud Managed Service for Prometheus の RoleBinding を構成します。
Autopilot クラスタと Standard クラスタのどちらを使用するかによって、RoleBinding を
gke-gmp-system
Namespace またはgmp-system
Namespace のいずれかに作成する必要があります。このリソースにより、コレクタ サービス アカウントはkueue-metrics-reader-token
Secret へのアクセス権を取得し、Kueue 指標の認証とスクレイピングを行うことができます。Autopilot
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: gmp-system:collector:kueue-secret-reader namespace: kueue-system roleRef: name: kueue-secret-reader kind: Role apiGroup: rbac.authorization.k8s.io subjects: - name: collector namespace: gke-gmp-system kind: ServiceAccount
Standard
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: gmp-system:collector:kueue-secret-reader namespace: kueue-system roleRef: name: kueue-secret-reader kind: Role apiGroup: rbac.authorization.k8s.io subjects: - name: collector namespace: gmp-system kind: ServiceAccount
Pod Monitoring リソースを構成します。
次のリソースは、Kueue のデプロイのモニタリングを構成し、指標が HTTPS 経由で /metrics パスに公開されることを指定します。指標のスクレイピング時に認証に
kueue-metrics-reader-token
Secret を使用します。apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: kueue namespace: kueue-system spec: selector: matchLabels: control-plane: controller-manager endpoints: - port: 8443 interval: 30s path: /metrics scheme: https tls: insecureSkipVerify: true authorization: type: Bearer credentials: secret: name: kueue-metrics-reader-token key: token
エクスポートした指標をクエリする
Kueue ベースのシステムをモニタリングするための PromQL クエリの例
これらの PromQL クエリを使用すると、ジョブのスループット、キューごとのリソース使用率、ワークロードの待ち時間などの主要なキュー指標をモニタリングして、システムのパフォーマンスを把握し、潜在的なボトルネックを特定できます。
ジョブのスループット
これにより、各 cluster_queue について、5 分間のワークロードの許可レートが 1 秒あたりで計算されます。この指標は、キューごとに分類することでボトルネックを特定できます。また、合計することでシステム全体のスループットを把握できます。
クエリ:
sum(rate(kueue_admitted_workloads_total[5m])) by (cluster_queue)
リソース使用率
これは、metrics.enableClusterQueueResources
が有効になっていることを前提としています。各キューの現在の CPU 使用量と名目上の CPU 割り当ての比率を計算します。値が 1 に近いほど、使用率が高いことを示します。リソースラベルを変更することで、メモリやその他のリソースに適応させることができます。
カスタム構成のリリース バージョンの Kueue をクラスタにインストールするには、Kueue のドキュメントをご覧ください。
クエリ:
sum(kueue_cluster_queue_resource_usage{resource="cpu"}) by (cluster_queue) / sum(kueue_cluster_queue_nominal_quota{resource="cpu"}) by (cluster_queue)
キューの待ち時間
これにより、特定のキュー内のワークロードの 90 パーセンタイルの待ち時間が返されます。分位値を変更して(中央値の場合は 0.5、99 パーセンタイルの場合は 0.99 など)、待ち時間の分布を把握できます。
クエリ:
histogram_quantile(0.9, kueue_admission_wait_time_seconds_bucket{cluster_queue="QUEUE_NAME"})
Job を作成し、許可されたワークロードを監視する
このセクションでは、Namespace team-a
と team-b
に Kubernetes Job を作成します。Kubernetes の Job コントローラは、1 つ以上の Pod を作成し、特定のタスクが正常に実行されるようにします。
10 秒間スリープする両方の ClusterQueue に 3 つの並列 Job を生成し、3 つ Job が完了すると終了します。60 秒後にクリーンアップされます。
job-team-a.yaml
は team-a
Namespace に Job を作成し、LocalQueue lq-team-a
と ClusterQueue cq-team-a
を指します。
同様に、job-team-b.yaml
は team-b
Namespace に Job を作成し、LocalQueue lq-team-b
と ClusterQueue cq-team-b
を指します。
新しいターミナルを開始し、このスクリプトを実行すると 1 秒ごとに Job が生成されます。
./create_jobs.sh job-team-a.yaml 1
別のターミナルを開始して、
team-b
Namespace の Job を作成します。./create_jobs.sh job-team-b.yaml 1
Job が Prometheus のキューに格納されていることを確認します。次のコマンドを使用します。
watch -n 2 kubectl get clusterqueues -o wide
出力例を以下に示します。
NAME COHORT STRATEGY PENDING WORKLOADS ADMITTED WORKLOADS
cq-team-a all-teams BestEffortFIFO 0 5
cq-team-b all-teams BestEffortFIFO 0 4
未使用の割り当てをコホートで借用する
ClusterQueue が最大容量に達するとは限りません。ワークロードが ClusterQueue 間で均等に分散されていなければ、割り当ての使用量は最大化されません。ClusterQueue が相互に同じコホートを共有していれば、ClusterQueue は割り当ての使用率を最大化するために、他の ClusterQueue から割り当てを借用できます。
Job が、ClusterQueue の
cq-team-a
とcq-team-b
の両方のキューに入れられたら、対応するターミナルでCTRL+c
を押してteam-b
Namespace のスクリプトを停止します。Namespace
team-b
の保留中の Job がすべて処理されると、Namespaceteam-a
の Job がcq-team-b
内の使用可能なリソースを借用できます。kubectl describe clusterqueue cq-team-a
cq-team-a
とcq-team-b
はall-teams
という同じコホートを共有しているため、これらの ClusterQueues は使用されていないリソースを共有できます。Flavors Usage: Name: on-demand Resources: Borrowed: 5 Name: cpu Total: 15 Borrowed: 5Gi Name: memory Total: 15Gi
team-b
Namespace のスクリプトを再開します。./create_jobs.sh job-team-b.yaml 3
cq-team-a
から借用したリソースが0
に戻り、cq-team-b
のリソースが独自のワークロードに使用されます。kubectl describe clusterqueue cq-team-a
Flavors Usage: Name: on-demand Resources: Borrowed: 0 Name: cpu Total: 9 Borrowed: 0 Name: memory Total: 9Gi
Spot VM で割り当てを増やす
保留中のワークロードの高い需要を満たす場合など、割り当てを一時的に増やす必要がある場合は、コホートに ClusterQueue を追加して需要に対応するように Kueue を構成できます。未使用のリソースを含む ClusterQueue は、それらのリソースを同じコホートに属する別の ClusterQueue と共有できます。
チュートリアルの最初で、Spot VM と spot
という名前の ResourceFlavor を使用して spot
という名前のノードプールを作成し、ラベルを cloud.google.com/gke-provisioning: spot
に設定しました。このノードプールとそれを表す ResourceFlavor を使用するために、ClusterQueue を作成します。
コホートを
all-teams
に設定して、cq-spot
という新しい ClusterQueue を作成します。この ClusterQueue は
cq-team-a
とcq-team-b
で同じコホートを共有するため、ClusterQueue のcq-team-a
とcq-team-b
はどちらも最大 15 個の CPU リクエストと 15 Gi のメモリのリソースを借用できます。kubectl apply -f cq-spot.yaml
Prometheus で、同じコホートを共有する
cq-spot
が割り当てが追加されたので、cq-team-a
とcq-team-b
の両方で許可されたワークロードの急増状況を確認します。次のコマンドを使用します。watch -n 2 kubectl get clusterqueues -o wide
Prometheus で、クラスタ内のノードの数を確認します。次のコマンドを使用します。
watch -n 2 kubectl get nodes -o wide
両方のスクリプトを停止するには、
team-a
とteam-b
の各 Namespace でCTRL+c
を押します。