ack-kube-queueは、KubernetesでAI、機械学習、バッチワークロードを管理するように設計されています。 これにより、システム管理者はジョブキュー管理をカスタマイズし、キューの柔軟性を向上できます。 クォータシステムと統合されたack-kube-queueは、ワークロードとリソースクォータの管理を自動化および最適化して、Kubernetesクラスターでのリソース使用率を最大化します。 このトピックでは、ack-kube-queueをインストールして使用する方法について説明します。
前提条件
クラウドネイティブAIスイートが有効化されました。制限事項
Kubernetesバージョンが1.18.aliyun.1以降のContainer Service for Kubernetes (ACK) Proクラスターのみがサポートされています。
ack-kube-queueのインストール
このセクションでは、2つのシナリオでack-kube-queueをインストールする方法について説明します。
シナリオ1: クラウドネイティブAIスイートがインストールされていない
ACK コンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、
を選択します。クラウドネイティブAI Suiteページの下部で、[デプロイ] をクリックします。
[スケジューリング] セクションで、[キューキュー] を選択します。 [インタラクティブモード] セクションで、[アリーナ] を選択します。 ページの下部で、[クラウドネイティブAIスイートのデプロイ] をクリックします。
シナリオ2: クラウドネイティブAIスイートがインストールされている
ACK コンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、
を選択します。ack-arenaとack-kube-queueをインストールします。
[クラウドネイティブAI Suite] ページで、[ack-arena] を見つけ、[操作] 列の [デプロイ] をクリックします。 [パラメーター] パネルで、[OK] をクリックします。
Cloud-native AI Suiteページで、ack-kube-queueを見つけ、[操作] 列の [デプロイ] をクリックします。 表示されるメッセージで、[確認] をクリックします。
ack-arenaとack-kube-queueをインストールすると、[コンポーネント] セクションの [ステータス] 列にデプロイ済みが表示されます。
サポートされるジョブタイプ
ack-kube-queueは、TensorFlowジョブ、PyTorchジョブ、MPIジョブ、Argoワークフロー、Rayジョブ、Sparkアプリケーション、およびKubernetesネイティブジョブをサポートします。
制限事項
TensorFlowジョブ、PyTorchジョブ、およびMPIジョブをキューに送信するには、ack-arenaが提供するオペレーターを使用する必要があります。
Kubernetesネイティブジョブをキューに送信するには、Kubernetesバージョンのクラスターが1.22以降であることを確認します。
MPIジョブをキューに送信するには、アリーナを使用します。
Argoワークフローのみをキューに送信できます。 Argoワークフローのステップをキューに送信することはできません。 次のアノテーションを追加して、Argoワークフローによって要求されたリソースを宣言できます。
``` annotations: kube-queue/min-resources: | cpu: 5 memory: 5G ```
さまざまな種類のジョブをキューに送信する
デフォルトでは、ack-kube-queueはTensorFlowジョブとPyTorchジョブをサポートしています。 ack-kube-queueでサポートされているジョブタイプは、必要に応じて変更できます。
v0.4.0より前のバージョン
各ジョブタイプのkubeキュー機能は、個々の配置によって制御されます。 拡張セクションのレプリケートされたポッドの数を0に設定して、kube-queue機能を無効にすることができます。
バージョンv0.4.0以降
Argoワークフローを除き、他のジョブタイプのkube-queue機能はjob-Extensionsによって制御されます。 コマンドの -- enabled-extensions
の値を変更することで、ジョブの種類の機能を有効または無効にできます。 異なるジョブタイプはコンマ (,) で区切ります。 コマンドで使用するジョブの種類と名前を次の表に示します。
TfJob | tfjob |
Pytorchjob | pytorchjob |
ジョブ | job |
SparkApplication | sparkapp |
RayJob | rayjob |
RayJob(v1alpha 1) | rayjobv1alpha1 |
MpiJob | mpiv1 |
TensorFlowジョブ、PyTorchジョブ、およびMPIジョブをキューに送信する
ジョブにscheduling.x-k8s.io/suspend="true"
の注釈を追加する必要があります。 次のサンプルコードは、TensorFlowジョブをキューに送信します。
apiVersion: "kubeflow.org/v1"
kind: "TFJob"
metadata:
name: "job1"
annotations:
scheduling.x-k8s.io/suspend: "true"
spec:
...
Kubernetesネイティブジョブをキューに送信する
ジョブの中断フィールドをtrueに設定する必要があります。 次のサンプルコードは、Kubernetesネイティブジョブをキューに送信します。
apiVersion: batch/v1
kind: Job
metadata:
generateName: pi-
spec:
suspend: true
completions: 1
parallelism: 1
template:
spec:
schedulerName: default-scheduler
containers:
- name: pi
image: perl:5.34.0
command: ["sleep", "3s"]
resources:
requests:
cpu: 100m
limits:
cpu: 100m
restartPolicy: Never
上の例では、CPUリソースの100m
を要求するジョブがキューに入れられます。 ジョブがデキューされると、ジョブの中断フィールドの値はfalseに変更され、ジョブはクラスタコンポーネントによって実行されます。
Argoワークフローをキューに送信する
コンソールのマーケットプレイスからack-workflowをインストールします。
ワークフローを送信するときに、kube-queue-suspendというカスタム中断テンプレートをArgoワークフローに追加し、中断フィールドをtrueに設定する必要があります。 例:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: $example-name
spec:
suspend: true # Set this field to true.
entrypoint: $example-entrypoint
templates:
# Add a suspend template named kube-queue-suspend.
- name: kube-queue-suspend
suspend: {}
- name: $example-entrypoint
...
Sparkアプリケーションをキューに送信する
コンソールのマーケットプレイスからack-spark-operatorをインストールします。
Sparkアプリケーションにscheduling.x-k8s.io/suspend="true"
アノテーションを追加する必要があります。
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
generateName: spark-pi-suspend-
namespace: spark-operator
annotations:
scheduling.x-k8s.io/suspend: "true"
spec:
type: Scala
mode: cluster
image: registry-cn-beijing.ack.aliyuncs.com/acs/spark:v3.1.1
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.1.1.jar
sparkVersion: "3.1.1"
driver:
cores: 1
coreLimit: "1200m"
memory: "512m"
serviceAccount: ack-spark-operator3.0-spark
executor:
cores: 1
instances: 1
memory: "512m"
キューにRayジョブを送信する
コンソールのマーケットプレイスからack-kuberay-operatorをインストールします。
Rayジョブをキューに送信するときは、Rayジョブのspec.suspend
フィールドをtrueに設定する必要があります。
apiVersion: ray.io/v1
kind: RayJob
metadata:
name: rayjob-sample
spec:
entrypoint: python /home/ray/samples/sample_code.py
runtimeEnvYAML: |
pip:
- requests==2.26.0
- pendulum==2.1.2
env_vars:
counter_name: "test_counter"
# Suspend specifies whether the RayJob controller should create a RayCluster instance.
# If a job is applied with the suspend field set to true, the RayCluster will not be created and we will wait for the transition to false.
# If the RayCluster is already created, it will be deleted. In the case of transition to false, a new RayCluste rwill be created.
suspend: true
rayClusterSpec:
rayVersion: '2.9.0' # should match the Ray version in the image of the containers
headGroupSpec:
rayStartParams:
dashboard-host: '0.0.0.0'
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.9.0
ports:
- containerPort: 6379
name: gcs-server
- containerPort: 8265 # Ray dashboard
name: dashboard
- containerPort: 10001
name: client
resources:
limits:
cpu: "1"
requests:
cpu: "200m"
volumeMounts:
- mountPath: /home/ray/samples
name: code-sample
volumes:
# You set volumes at the Pod level, then mount them into containers inside that Pod
- name: code-sample
configMap:
# Provide the name of the ConfigMap you want to mount.
name: ray-job-code-sample
# An array of keys from the ConfigMap to create as files
items:
- key: sample_code.py
path: sample_code.py
workerGroupSpecs:
- replicas: 1
minReplicas: 1
maxReplicas: 5
groupName: small-group
rayStartParams: {}
template:
spec:
containers:
- name: ray-worker # must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc'
image: rayproject/ray:2.9.0
lifecycle:
preStop:
exec:
command: [ "/bin/sh","-c","ray stop" ]
resources:
limits:
cpu: "1"
requests:
cpu: "200m"
クォータシステムのタイプを変更する
クラスターが複数のユーザーによって使用されている場合、ユーザーがリソースを求めて競合する場合に備えて、各ユーザーに一定量のリソースを割り当てる必要があります。 従来の方法では、Kubernetesリソースクォータを使用して、各ユーザーに固定量のリソースを割り当てます。 しかしながら、リソース要件は、ユーザ間で異なり得る。 デフォルトでは、ack-kube-queueはエラスティッククォータを使用して、全体的なリソース使用率を改善します。 Kubernetesリソースのクォータを使用する場合は、次の手順を実行します。elasticクォータの詳細については、「ElasticQuota」をご参照ください。
次のコマンドを実行して、エラスティッククォータからKubernetesリソースクォータに切り替えます。
kubectl edit deploy kube-queue-controller -nkube-queue
から環境変数を変更します。
elasticquota
へresourcequota
.env: - name: QueueGroupPlugin value: resourcequota
設定を変更した後、ファイルを保存します。 kube-queue-controllerが起動するのを待ちます。 次に、Kubernetesリソースクォータを使用してリソースを割り当てます。
ブロックキューの有効化
ack-kube-queueは、kube-schedulerと同じように、デフォルトでラウンドロビン方式でジョブを処理します。 キュー内のジョブは、リソースを1つずつ要求します。 リソースの取得に失敗したジョブは、スケジュール不可キューに送信され、次のジョブスケジューリングを待機します。 リソース需要が低い多数のジョブがクラスタに含まれている場合、これらのジョブをラウンドロビン方式で処理するには時間がかかります。 このシナリオでは、リソース需要が高いジョブは、リソース需要が低いジョブがリソースを求めて競合するため、保留になる可能性が高くなります。 この問題を回避するために、ack-kube-queueはブロッキングキューを提供します。 この機能を有効にすると、キュー内の最初のジョブのみがスケジュールされます。 このようにして、より多くのリソースをリソース需要の高いジョブにスケジュールできます。
手順
ACKコンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
Namespaceパラメーターをkube-queueに設定します。 次に、kube-queue-controllerの [操作] 列で [編集] をクリックします。
[環境変数] の右側にある [追加] をクリックし、次の環境変数を追加します。
パラメーター
値
Type
Custom
変数キー
厳密な優先順位
値 /ValueFrom
true
ページの右側にある [更新] をクリックします。 [OK] メッセージで、[確認] をクリックします。
厳格な優先スケジューリングの有効化
既定では、リソースの取得に失敗したジョブはスケジュール不可キューに送信され、次のジョブスケジューリングを待機します。 ジョブが完了すると、ジョブによって占有されたリソースが解放されます。 これらのジョブはまだスケジュール不可キューにあるため、これらのリソースは優先度の高いジョブにスケジュールされません。 その結果、アイドルリソースは優先度の低いジョブにスケジューリングされる。 アイドルリソースを優先度の高いジョブに好ましくスケジュールするために、ack-kube-queueは厳格な優先度スケジューリング機能を提供します。 ジョブがリソースを解放した後、システムは、キュー内の最初のジョブである最も優先度の高いジョブにリソースをスケジュールしようとします。 これにより、アイドルリソースが優先度の高いジョブにスケジューリングされることが好ましい。
低優先度のジョブは、アイドルリソースが高優先度のジョブを満たすには不十分である場合、アイドルリソースを求めて競合することができる。
手順
ACKコンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
Namespaceパラメーターをkube-queueに設定します。 次に、kube-queue-controllerの [操作] 列で [編集] をクリックします。
[環境変数] の右側にある [追加] をクリックし、次の環境変数を追加します。
パラメーター
値
Type
Custom
変数キー
厳密な一貫性
値 /ValueFrom
true
ページの右側にある [更新] をクリックします。 [OK] メッセージで、[確認] をクリックします。
リソースクォータのユースケース
ElasticQuota
次のYAMLテンプレートを使用してElasticQuotaTreeを作成します。
次のコマンドを実行して、ElasticQuotaTreeが作成されているかどうかを確認します。
kubectl get elasticquotatree -A
期待される出力:
NAMESPACE NAME AGE kube-system elasticquotatree 7s
ElasticQuotaTreeが作成されます。
ジョブを作成します。
説明ack-kube-queueのジョブキュー管理機能をテストするには、作成するジョブのリソースクォータを、ジョブが要求するリソースの合計量よりも少なくする必要があります。
テストを簡単にするために、TensorFlowジョブで使用されるTensorFlowイメージはBusyBoxイメージに置き換えられます。 各コンテナは30秒間スリープし、トレーニングプロセスをシミュレートします。
次のYAMLテンプレートを使用して、2つのTensorFlowジョブを作成します。
ジョブを送信した後、ジョブのステータスを照会します。
次のコマンドを実行して、ジョブのステータスを照会します。
kubectl get tfjob
期待される出力:
NAME STATE AGE job1 Running 3s job2 Queuing 2s
出力は、
job1
がRunning状態で、job2
がQueuing状態であることを示します。 これは、各TensorFlowジョブが3つのvCoresを要求するが、作成したElasticQuotaTreeが4つのvCoresをデフォルトの名前空間に割り当てるためです。 したがって、2つのTensorFlowジョブを同時に実行することはできません。しばらく待ってから、次のコマンドを再度実行します。
kubectl get tfjob
期待される出力:
NAME STATE AGE job1 Succeeded 77s job2 Running 77s
出力は、
job1
が完了したことを示します。job1
が完了すると、job2
の実行が開始されます。 出力は、ack-kube-queueが期待どおりにジョブキューを管理することを示します。
ResourceQuota
次のYAMLテンプレートを使用してResourceQuotaを作成します。
apiVersion: v1 kind: ResourceQuota metadata: name: default spec: hard: cpu: "4" memory: 4Gi
次のコマンドを実行して、ResourceQuotaが作成されているかどうかを確認します。
kubectl get resourcequota default -o wide
期待される出力:
NAME AGE REQUEST LIMIT default 76s cpu: 0/4, memory: 0/4Gi
ResourceQuotaが作成されます。
次のYAMLテンプレートを使用して、2つのTensorFlowジョブを作成します。
2つのジョブが送信されたら、次のコマンドを実行してジョブのステータスを照会します。
kubectl get tfjob NAME STATE AGE job1 Running 5s job2 Queuing 5s kubectl get pods NAME READY STATUS RESTARTS AGE job1-ps-0 1/1 Running 0 8s job1-worker-0 1/1 Running 0 8s job1-worker-1 1/1 Running 0 8s
job1はRunning状態で、job2はQueuing状態です。 結果は、ack-kube-queueが期待どおりにジョブキューを管理することを示しています。 これは、各TensorFlowジョブが3つのvCoreを要求するためです。パラメーターサーバーポッドに1つのvCore、2つのワーカーポッドに1つのvCoreです。 ただし、作成したElasticQuotaTreeは、4つのvCoresをデフォルトの名前空間に割り当てます。 したがって、2つのTensorFlowジョブを同時に実行することはできません。
しばらく待ってから、次のコマンドを実行します。
kubectl get tfjob NAME STATE AGE job1 Succeeded 77s job2 Running 77s kubectl get pods NAME READY STATUS RESTARTS AGE job1-worker-0 0/1 Completed 0 54s job1-worker-1 0/1 Completed 0 54s job2-ps-0 1/1 Running 0 22s job2-worker-0 1/1 Running 0 22s job2-worker-1 1/1 Running 0 21s
job1が完了しました。 job2は、job1の完了後に実行を開始します。 結果は、ack-kube-queueが期待どおりにジョブキューを管理することを示しています。
同時にデキューできるジョブ数の制限
アプリケーションが自動的にスケーリングされ得るシナリオでは、アプリケーションによって必要とされるリソースの量は、予測不可能であり得る。 この場合、デキューされるジョブの数を制限できます。 キュー内のジョブ数を制限するには、ElasticQuotaTreeで
kube-queue/max-jobs
リソースを定義する必要があります。 制限が設定された後、クォータ以下でデキューできるキューユニットの数は、キュー内のジョブの最大数にオーバーコミット率を掛けたものを超えることはできません。 例: