分散バッチジョブを作成する
このページでは PFCP クラスタ上で分散バッチ処理を実行するための ParallelJob の作成方法を説明します。
概要
ParallelJob は、複数のノード間で協調して動作する分散バッチジョブを簡単にデプロイ・管理するための Kubernetes カスタムリソースです。ParallelJob には以下の特徴があります。
- 複数のフレームワークに対応: MPI などの分散処理フレームワークをサポート。
- Gang Scheduling: 分散バッチジョブ内の全 Pod が同時にスケジューリングされることを保証。
- ジョブ失敗時の再実行: 1 つのジョブが失敗した場合の ParallelJob 全体の自動再実行。
ParallelJob がサポートしているランタイム
Open MPI
Message Passing Interface(MPI)実装の 1 つである Open MPI を使用した並列計算をサポートします。Open MPI ジョブでは、1 つの launcher Pod が複数の worker Pod に SSH 経由で接続し、MPI を用いた並列計算を実行します。launcher Pod は rank=0 の worker としても使用されます。
以下は、MPI ランタイムを使用する ParallelJob の設定例です。
apiVersion: preferred.jp/v1alpha1
kind: ParallelJob
metadata:
name: mpi-sample-job
spec:
# 利用するMPIランタイムを指定
runtimeRef:
name: mpi-openmpi
# LauncherとWorkerを含むPodの数です。
# MPIランタイムではLauncherは1つで、残りがWorkerとなります。
numPods: 3
# PodあたりのMPIプロセス数で、MPIのhostfileのslotsに設定されます。
# アクセラレータを用いた計算の場合は Pod あたりの アクセラレータ数、flat MPI の場合は CPU コア 数、ハイブリッド並列の場合は 1 を指定するケースが多いです。
numProcPerPod: 2
# Launcher用PodのTemplateの設定です。PodTemplateSpec形式で記述します。
# `main` コンテナが含まれない場合、ParallelJobの作成に失敗します。
launcher:
spec:
containers:
- name: main # MPIを実行するコンテナは `main` としてください。
image: ghcr.io/pfnet/parallel-controller/openmpi:v0.1.0
command:
- sh
- -c
- |
cat > hello_mpi.c << 'EOF'
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int rank, world_size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
printf("Hello from MPI process %d rank in %d processes\n", rank, world_size);
MPI_Finalize();
return 0;
}
EOF
mpicc -o hello_mpi hello_mpi.c
mpirun --allow-run-as-root ./hello_mpi
# (Optional) Worker用PodのTemplateの設定です。PodTemplateSpec形式で記述します。
# Workerの設定はLauncherから継承され、Launcherと通信する用のコンテナは `main` という名前で自動生成されます。
# worker: nil
Open MPI ランタイムで独自のコンテナイメージを使用する場合は下記のソフトウェアが含まれている必要があります。
- Open MPI
- ssh (SSH クライアント)
- sshd (SSH サーバー)
シーン別設定例
以下に、実際の利用シーンでよく使用される設定例を示します。
失敗時のリトライ設定
デフォルトでは、ParallelJob 内のいずれかのジョブが失敗した場合、ParallelJob 全体が最大 3 回まで再実行されます。リトライ回数を変更するには、.spec.failurePolicy.maxRestarts フィールドを設定します。以下は、リトライ回数を 1 回に設定する例です。
apiVersion: preferred.jp/v1alpha1
kind: ParallelJob
metadata:
name: mpi-sample-job
spec:
failurePolicy:
# ジョブ失敗時にParallelJob全体を再実行する最大回数です。(デフォルト: 3)
maxRestarts: 1
...
GPU/RDMAリソースの指定
分散ジョブで GPU や RDMA リソースを使用する場合、Pod テンプレートで該当リソース要求を指定します。 NCCL や UCX の設定ファイルは自動生成されますが、読み込みは明示的に行う必要があります。以下は、launcher Pod に GPU と RDMA デバイスを要求し、NCCL と UCX の設定ファイルを読み込む例です(今後のアップデートで自動化予定です)。
apiVersion: preferred.jp/v1alpha1
kind: ParallelJob
metadata:
name: sample-job
spec:
launcher:
spec:
containers:
- name: main
command: ["/bin/sh", "-c"]
args:
# Note: NCCLやUCX用の設定ファイルは自動生成されますが、読み込みは明示的に行う必要があります。
- |
[ -f "$RDMA_NCCL_CONF" ] && . "$RDMA_NCCL_CONF"
[ -f "$RDMA_UCX_CONF" ] && . "$RDMA_UCX_CONF"
mpirun --allow-run-as-root something-using-gpu-rdma
resources:
limits:
nvidia.com/gpu: "2"
preferred.jp/rdma: "1"
...
トラブルシューティング
分散ジョブの実行中に問題が発生した場合、以下の手順でトラブルシューティングを行います。
ジョブの状態確認
ParallelJob の状態を確認するには、以下のコマンドを実行します。
# ParallelJob の状態を確認
kubectl get paralleljobs sample-job
# イベントを含めた詳細情報を確認
kubectl describe paralleljobs sample-job
関連する Job / Pod の状態を確認するには、以下のコマンドを実行します。
# ParallelJob に紐づく JobSet 名を変数に設定
jobset_name=$(kubectl get paralleljobs sample-job -o jsonpath={".status.jobGroupName"})
# 関連する Job / Pod の状態を確認
kubectl get jobs,pods -l jobset.sigs.k8s.io/jobset-name=${jobset_name}
Podのログ確認
rank=0 の Pod のログを取得するには、以下のコマンドを実行します。
# ParallelJob に紐づく JobSet 名を変数に設定
jobset_name=$(kubectl get paralleljobs sample-job -o jsonpath={".status.jobGroupName"})
# ログの表示
kubectl logs -f $(kubectl get pod -l jobset.sigs.k8s.io/jobset-name=${jobset_name},jobset.sigs.k8s.io/job-global-index=0 -o name)