tao-run-on-kubernetes について
kubeconfigまたはPod内サービスアカウントで接続できるクラスターに、TAOコンテナジョブをKubernetes Jobとして投入するプラットフォームスキルです。投入、状態確認、ログ取得、キャンセルに対応し、Indexed Jobによるマルチノード学習も実行できます。
主な機能
- 01kubectlによるTAOジョブ投入
- 02クラスターとGPU容量の確認
- 03状態追跡とログ取得
- 04ジョブのキャンセルと結果記録
- 05マルチノード分散学習
活用シーン
- 01KubernetesクラスターでTAOジョブを起動
- 02投入済みジョブの進捗とログを確認
- 03複数Podにまたがる分散学習
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nvidia/ skills --skill tao-run-on-kubernetesインストール後、Claude Code で/tao-run-on-kubernetesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
BENCHMARK.mdconfig.jsoneval.configskill-card.mdskill.oms.sigconfig/skillspector-baseline.yamlevals/evals.jsonreferences/action-request.mdlocal-cluster.mdskill_info.yamlscripts/render_action_job.py詳細
Kubernetes
単独でインストールしますか? このセッションが TAO skill bank プラグインによって初期化されていない場合は、まず
tao-setupスキルを実行してください(ホストの事前確認、認証情報、スキル横断の検出)。
TAO コンテナージョブを Kubernetes Jobs として送信します。kubeconfig からアクセスできる任意のクラスター(EKS/GKE/AKS/オンプレミス)、またはクラスター内のサービスアカウント(ポッド内で実行する場合)で動作します。
デフォルトでは単一ポッドです。num_nodes > 1 を指定すると、複数ノードの分散トレーニングを利用できます(Indexed Job とヘッドレス Service を使用します。詳しくは以下のマルチノードトレーニング(分散)を参照してください)。
事前確認
確認項目は 3 つです。GPU ホストのランタイムが使用可能であること、kubectl からクラスターにアクセスできること、GPU Operator/デバイスプラグインが存在することです。
# 0. GPU node host runtime.
# Run this on each self-managed GPU worker node or in the node image build.
# Set TAO_K8S_SKIP_NODE_RUNTIME_CHECK=1 only when using managed GPU nodes whose
# driver/toolkit lifecycle is owned by the cloud provider or GPU Operator policy.
if [ "${TAO_K8S_SKIP_NODE_RUNTIME_CHECK:-0}" != "1" ]; then
TAO_SKILL_BANK_ROOT="${TAO_SKILL_BANK_ROOT:-$PWD}"
SETUP_SCRIPT="${TAO_SKILL_BANK_ROOT}/skills/platform/tao-setup-nvidia-gpu-host/scripts/setup-nvidia-gpu-host.sh"
bash "$SETUP_SCRIPT" --backend kubernetes --check-only || {
echo "MISSING: TAO Kubernetes GPU node runtime is not ready."
echo "For self-managed GPU nodes, run after user approval:"
echo " bash \"$SETUP_SCRIPT\" --backend kubernetes --install --yes"
echo "For managed clusters, verify the node image/GPU Operator policy installs driver 580 and toolkit 1.19.0, then set TAO_K8S_SKIP_NODE_RUNTIME_CHECK=1."
exit 1
}
fi
# 1. Cluster reachable (kubeconfig OR in-cluster service account)
command -v kubectl >/dev/null 2>&1 || {
echo "MISSING: kubectl not found on PATH. Install kubectl to submit Jobs."
exit 1
}
kubectl cluster-info >/dev/null 2>&1 || {
echo "MISSING: no reachable cluster (kubeconfig at ~/.kube/config, \$KUBECONFIG, or in-pod service account)."
echo "Configure kubectl for your cluster, or set \$KUBECONFIG:"
echo " EKS: aws eks update-kubeconfig --name <cluster> --region <region>"
echo " GKE: gcloud container clusters get-credentials <cluster> --region <region>"
echo " AKS: az aks get-credentials --resource-group <rg> --name <cluster>"
echo " local: minikube start (see 'Local cluster' below)"
exit 1
}
# 2. NVIDIA GPU Operator present (soft check — warn, don't fail)
gpu=$(kubectl get nodes -o jsonpath='{range .items[*]}{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}' 2>/dev/null | grep -v '^$' | head -1)
if [ -z "$gpu" ] || [ "$gpu" = "0" ]; then
echo "WARN: no nvidia.com/gpu allocatable on this cluster."
echo "Install the NVIDIA GPU Operator before submitting GPU jobs:"
echo " https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html"
fi
GPU ノードのランタイム確認は、自己管理ノードでは必須です。クライアントが GPU ワーカー上で実行されていないマネージドクラスターでは、プロバイダーのノードイメージまたは GPU Operator のポリシーを確認し、クライアント上でインストーラーを実行する代わりに TAO_K8S_SKIP_NODE_RUNTIME_CHECK=1 を設定してください。ここでの GPU 容量に関する警告はソフトチェックです。submit 動詞では nvidia.com/gpu の割り当て可能数を再確認し、マニフェストを適用する前にハードエラーとします(ギャングスケジューリングはないため、容量を超えるジョブは永久に Pending のままになります)。
認証情報と設定
- Kubeconfig(次のいずれか):
~/.kube/config— デフォルトの検出パス$KUBECONFIG— 代替パス- クラスター内のサービスアカウント — ポッド内で実行する場合に使用(kubeconfig は不要)
- TAO_K8S_NAMESPACE(任意):ジョブ送信のデフォルトの名前空間です。デフォルトは
defaultです。 - TAO_K8S_CONTEXT(任意):クラスターを切り替えるための kubeconfig コンテキスト名です。
- NGC_KEY(任意):nvcr.io からイメージをプルする場合に使用します。対象の名前空間にイメージプルシークレットを事前に作成している場合は、レンダリングされたマニフェストの
imagePullSecretsでその名前を指定してください。 - AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / S3_BUCKET_NAME / S3_ENDPOINT_URL(任意):S3 データセット I/O(ストレージティア C)に使用します。ジョブごとの Secret(
envFrom.secretRef)経由でポッドに渡し、インラインでは指定しません。従来のACCESS_KEY/SECRET_KEYはtao-data-ioによってマッピングされます。
Kubernetes で実行する場合、Brev または SLURM の認証情報を求めないでください。選択したワークフローで s3:// 入力または出力を使用する場合に限り S3 認証情報を求め、HF_TOKEN などのモデル固有の認証情報は、選択したモデルで必要な場合に限り求めてください。起動前に、選択した名前空間で Jobs を作成できること、データセット/結果のパスをポッドから参照できること、PVC/マウントされたファイルシステムのパスがジョブコンテナーにマウントされていることを確認してください。エージェントホスト上のローカルパスは、マウントされていることの証明にはなりません。
実行 — 4 つの動詞
tao-run-on-kubernetes はプラットフォームのコンシューマーです。kubectl を介して spec-bundle を実行し、変更するのは job-record のみです。nvidia-tao-sdk も tao_sdk のインポートも不要で、ジョブは通常の kubectl apply で送信します。
$BANK = ${TAO_SKILL_BANK_PATH}。
submit
-
GPU 容量ゲート — 最初にハードフェイル(ギャングスケジューリングなし → 大きすぎる Job は永遠に
Pendingのまま):ALLOC=$(kubectl get nodes -o jsonpath='{range .items[*]}{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}' | awk '{s+=$1} END{print s+0}') [ "${ALLOC:-0}" -ge "$NUM_GPUS" ] || { echo "insufficient GPUs: need $NUM_GPUS, allocatable $ALLOC"; exit 1; } -
ストレージ層(
tao-data-io経由):A = データを保持するバインド済み PVC/NFS をマウントする(マウントパスを記述し、フェッチは行わない — エアギャップの答えであり、パッケージ済みテンプレートが行うこと);C = エフェメラル: initContainer が S3 から共有emptyDirへフェッチし、最終ステップが TTL 前に結果を S3 へアップロードします。ティア C はダウンロード中も GPU を占有します。 Pod は initContainer を含めたライフタイム全体にわたって
nvidia.com/gpuを予約するため、大規模なティア C のフェッチ — あるいは初回のマルチ GB イメージプル — は、SLURM アロケーション内でプルするのとまったく同様に、課金され reaper の対象となるアイドル GPU 時間となります。データがすでに PVC 上にある場合はティア A を優先してください。ティア C は小規模な入力向けに、十分理解した上で選択してください。プロデューサーのアクションリクエストは、論理パスおよび埋め込み絶対パスに対する重複ソースエイリアスを含め、複数のマウントを宣言できます。
references/action-request.mdを読み、そのステージングマップとパッケージ済みレンダラーを使用してください。mode=configの場合は、まずプロデューサーのネストされたスペックを実体化し、その正確に生成されたファイルをステージングしてレンダラーに渡し戻すことで、Pod が検証済みの読み取り専用コンフィグマウントを受け取ります。レガシーの単一ルートテンプレートでは、その契約を表現できません。 -
レコードを開く — 起動前に id を発行し、
results_dirをバインドする:JOB_ID=$("$BANK/scripts/tao_job_record.py" open --platform kubernetes --image "$IMAGE" \ --network-arch "$ARCH" --action "$ACTION" --storage-tier "$TIER" --results-dir "$RESULTS_DIR")results_dirはマウントされた(存続する)ボリュームパスまたは S3 プレフィックスでなければなりません —ttlSecondsAfterFinishedは終了後に Job とそのログを削除するため、後から Job オブジェクトから何も復元できません。 -
レンダリング、ゲート、適用、そして RUNNING を記録する。 プロデューサーのアクションリクエストの場合は、
references/action-request.mdに従ってください。これがバックエンド名の正規化、条件付き Secret 参照、ネイティブ argv レンダリング、サーバードライラン、および適用されたオブジェクト名の job-record へのバインドを担います。単純な単一ルートの spec-bundle の場合は、templates/k8s/single-pod-job.yaml.tmplをレンダリングし、redact_secrets.py lintおよびkubectl apply --dry-run=serverを実行して適用し、レコードをbackend-ref=<namespace>/<actual-object-name>でマークします。
ゲートまたは open をスキップした submit には id がありません — そのため起動できません。
status
submit で取得した K8S_JOB_NAME を保持してください。再アタッチ時には、job-record の backend_ref=<namespace>/<name> を読み、そのフィールドから両方の値を復元してください。Kubernetes 名がレコード id と等しいと仮定しないでください。
kubectl get job "$K8S_JOB_NAME" -n "$NAMESPACE" \
-o jsonpath='{.status.conditions[0].type} {.status.active} {.status.succeeded} {.status.failed}'
| kubectl シグナル | 語彙 |
|---|---|
| スケジュールされた Pod なし | PENDING (kubectl get pods -n "$NAMESPACE" -l job-name="$K8S_JOB_NAME" → message 内の ImagePullBackOff / Insufficient nvidia.com/gpu) |
active ≥ 1 | RUNNING |
condition Complete | COMPLETE |
condition Failed | ERROR (Pod の terminated reason から分類 — OOMKilled → ERR_INFRA) |
| Job/Pod が見つからない | UNKNOWN (TTL により削除された可能性 — job-record が信頼できるソース) |
logs
kubectl logs -n "$NAMESPACE" -l "job-name=$K8S_JOB_NAME" --tail "${N:-200}"
cancel
kubectl delete job "$K8S_JOB_NAME" -n "$NAMESPACE" --cascade=foreground
if [ -n "${CRED_SECRET:-}" ]; then
kubectl delete secret "$CRED_SECRET" -n "$NAMESPACE" --ignore-not-found
fi
"$BANK/scripts/tao_job_record.py" mark "$JOB_ID" --state CANCELED --source agent
マルチノード(nodes > 1)
同じ 4 つの動詞に加えて:
- バージョンゲート: k8s ≥ 1.28 を要求(
kubectl version -o json) —MASTER_ADDR=<job>-0.<svc>が解決する Pod ホスト名<job>-<index>(PodIndexLabel)にはこれが必要です。古いクラスターではランク 0 がランデブーでハングします。 - 容量ゲート ×nodes: 割り当て可能な GPU が
gpus_per_node × nodes以上でない限りハードフェイル(ギャングスケジューリングなし → 部分的な起動ではランク 0 が永遠に待機したままになります)。 templates/k8s/indexed-job.yaml.tmplをレンダリング — ヘッドレス Service + Indexed Job + ランデブー環境変数(WORLD_SIZE= ノード数、JOB_COMPLETION_INDEXからのNODE_RANK、MASTER_ADDR=<job>-0.<svc>、NCCL がサイレントにハングしないよう/dev/shm16Gi)。kubectl apply -fは Service と Job を同時に作成します;cancelは Job(Foreground)と Service を削除します。- 最初に NCCL プローブ(SLURM と同様) — タイムアウト付きの 2 ノード all-reduce;ハングした場合は、クラスターの NCCL 環境変数を設定して再プローブし、クラスターごとにキャッシュします。
ローカルクラスター(開発、CI、評価)
使い捨ての minikube/kind クラスターで、クラスターのクォータを消費せずにアドミッション、4 つの動詞、ジョブレコードの配線、ログの配線をテストできます。また、エージェント駆動の評価でエージェント自身がプロビジョニングするクラスターとしても使用できます。kubectl と minikube は root 権限を必要としない単一の静的バイナリなので、非 root の CI コンテナーで自分でインストールできます。
レンダリングされた Job が Pending のままになる原因は 2 つあり、1 つ目の問題が 2 つ目を隠します。テンプレートがマウントする PVC が存在しなければなりません(persistentvolumeclaim "<name>" not found が GPU に関するエラーより先に発生します)。次に、GPU のないクラスターで nvidia.com/gpu を要求する Job は Insufficient nvidia.com/gpu を報告し、永遠に待機します。ライフサイクルのみを実行する場合は NUM_GPUS=0 でレンダリングし、GPU のスケジューリングは検証されていないことを明記してください。Linux GPU ホストでは、minikube start --driver=docker --gpus all によって実際の GPU を利用できるため、GPU を搭載したマシンが 1 台あれば、実 GPU を使ったスモークテストができます。
インストールコマンド、ドライバーの選択、コンテナーとホストネットワークに関する注意点、および偽のデバイスプラグインを使う中間案については、references/local-cluster.md を参照してください。
コンテナーシェル
シンプルな単一 Pod テンプレートは、/bin/sh -c を介してコマンドを実行します(POSIX sh は busybox/distroless と TAO イメージの両方に含まれています)。プロデューサーのアクションリクエストでは、args モードのコマンドとその引数はコンテナーのネイティブな argv です。シェルが必要なプロデューサーは、シェルとスクリプトを明示的に指定します。シンプルな config モードのコマンドも、{config_path} の置換後はネイティブな argv になります。プロデューサーが所有する設定コマンドが複数行のシェルスクリプトそのものである場合は、/bin/sh -c の下でそのまま保持されます。レンダラーが設定値からシェルテキストを組み立てることはありません。
GPU Operator の依存関係
submit 動詞は、nvidia.com/gpu の割り当て可能数がないクラスターでの GPU ジョブの起動を拒否します。セルフマネージドクラスターでは、まずすべての GPU ワーカーノードで tao-setup-nvidia-gpu-host インストールアクションを実行するか、同じパッケージ一式をノードイメージに組み込んでください。
bash skills/platform/tao-setup-nvidia-gpu-host/scripts/setup-nvidia-gpu-host.sh --backend kubernetes --install --yes
次に、NVIDIA GPU Operator またはデバイスプラグインをインストールしてください。
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install --wait gpu-operator -n gpu-operator --create-namespace nvidia/gpu-operator
完全なガイド:https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html
マルチノードトレーニング(分散)
num_nodes > 1(上記のマルチノード(nodes > 1)動詞の手順を参照)を設定すると、N 個の Pod で分散トレーニングを実行できます。templates/k8s/indexed-job.yaml.tmpl をレンダリングすると、次のものがプロビジョニングされます。
-
Job と同じ名前の ヘッドレス Service(セレクター:
job-name=<job-name>、clusterIP: None、すべての Pod が Ready になる前に相互検出できるようpublishNotReadyAddresses: true)。 -
parallelism = completions = num_nodes、completionMode: Indexedの Indexed Job。各 Pod には、k8s によってJOB_COMPLETION_INDEXが自動的に設定されます(=ノードランク)。 -
ユーザーコマンドを呼び出す前にランデブー用の環境変数をエクスポートする コマンドラッパー。次の 2 つの命名規則が同時にエクスポートされます。
環境変数 値 読み取り元 WORLD_SIZEnum_nodesTAO PyTorch コンテナーの nvidia_tao_pytorch/core/entrypoint.py(PyTorch 独自の規則では 全プロセス数 を意味しますが、こちらでは ノード数 として使用されます)NUM_GPU_PER_NODEgpu_countTAO PyTorch コンテナーのエントリーポイント NNODESnum_nodestorchrunと PyTorch 標準のランデブーNPROC_PER_NODEgpu_counttorchrunNODE_RANK$JOB_COMPLETION_INDEX両方 MASTER_ADDR<job-name>-0.<job-name>(pod-0 の DNS)両方 MASTER_PORT29500両方(TAO のデフォルト) TAO のエントリーポイント(
dino trainなど)と未加工のtorchrunコマンドを変更なしで動作させるため、両方の命名規則を設定します。
TAO のエントリーポイントでは、コンテナーは spec.train.num_nodes と設定された環境変数を読み取ります。例:gpu_count=8、num_nodes=4(合計 32 GPU)で dino train -e /tmp/spec.yaml を実行します。
未加工の torchrun ベースのコマンド(TAO 以外のコンテナー)の場合、ラッパーは次を呼び出します。
torchrun --nnodes=$NNODES --nproc-per-node=$NPROC_PER_NODE --node-rank=$NODE_RANK \
--master-addr=$MASTER_ADDR --master-port=$MASTER_PORT train.py
容量チェックではノード間の合計を計算します。gpu_count × num_nodes ≤ クラスターの割り当て可能な nvidia.com/gpu 数。
マルチノード向けのクラスター要件
- Indexed Job で安定したポッドのホスト名(
PodIndexLabel機能)を利用するには k8s 1.28+ が必要です。古いクラスターではMASTER_ADDR=<job>-0.<svc>の DNS 参照が失敗します。kubectl versionで確認してください。 - ポッド間ネットワークはポート 29500(PyTorch のデフォルト。
MASTER_PORT環境変数で設定可能)で開放されている必要があります。ほとんどの CNI(Calico、Cilium、AWS VPC CNI)はデフォルトでこれを許可していますが、制限の厳しい NetworkPolicy は緩和する必要があります。 - コンテナ内の NCCL は GPU 間で通信します。クラスターにマルチ NIC ノードや RDMA がある場合は、レンダリングされたマニフェストのコンテナ
envでNCCL_SOCKET_IFNAME/NCCL_IB_HCAを設定してください。
参考資料
- Kubernetes Indexed Job: https://kubernetes.io/docs/concepts/workloads/controllers/job/#completion-mode
- バッチ ML 向け Indexed Job: https://kubernetes.io/blog/2022/06/01/indexed-jobs-mpi/
- PyTorch 分散(環境変数によるランデブー): https://pytorch.org/docs/stable/elastic/run.html
- NCCL ネットワークチューニング(NCCL_SOCKET_IFNAME、NCCL_IB_HCA): https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html
Kubernetes オペレーターの代替案
より高度なトポロジー(ギャングスケジューリング、PyTorch Elastic / フォールトトレラント学習、MPI / Horovod、RDMA セットアップ)が必要な場合は、素の Indexed Job ではなくオペレーターを利用してください。
- MPI Operator — https://github.com/kubeflow/mpi-operator — MPI / Horovod ワークロード向け。
- Kubeflow Training Operator(
PyTorchJob、TFJob) — https://www.kubeflow.org/docs/components/training/ — 再起動ロジックを内蔵した Elastic な PyTorch 学習向け。 - Volcano — https://volcano.sh/ — ギャングスケジューリング、キュー、フェアシェア。共有マルチテナントクラスターで有用です。
- Kueue — https://kueue.sigs.k8s.io/ — 上記のいずれかの上に乗せるクォータ / キューレイヤー。
このスキルの Indexed Job パスは意図的にシンプルで依存関係がありません。Elastic な再起動やギャングスケジューリングが必要な場合は、これらのいずれかを上に重ね、オペレーターの CRD を通じてジョブを投入してください。
よくあるエラーパターン
No nvidia.com/gpu resources allocatable on the cluster — GPU Operator(または NVIDIA Device Plugin)がインストールされていません。上記のリンクに従ってインストールし、kubectl get nodes -o jsonpath='{.items[*].status.allocatable}' で確認してください。
ImagePullBackOff / ErrImagePull — クラスターがイメージをプルできません。nvcr.io の場合: 名前空間に image-pull シークレットを事前に作成し、レンダリングされたマニフェストでポッドの imagePullSecrets として参照します:
キーは stdin 経由で渡してください — --docker-password=$NGC_KEY を使うとシークレットが
argv に入り、ホストのプロセステーブルとシェル履歴から見えるようになります:
set -a; source /path/to/.env; set +a # omit if already exported
kubectl create secret generic ngc-pull-secret -n tao-jobs \
--type=kubernetes.io/dockerconfigjson \
--from-file=.dockerconfigjson=/dev/stdin <<EOF
{"auths": {"nvcr.io": {"username": "\$oauthtoken", "password": "${NGC_KEY}"}}}
EOF
# Verify without reading the secret back:
kubectl get secret ngc-pull-secret -n tao-jobs >/dev/null && echo SECRET_OK
ポッドが永遠に Pending のまま — kubectl describe pod -l job-name=$JOB_ID の Events にスケジューリング理由が表示されます。よくある原因: GPU 容量の不足(Insufficient nvidia.com/gpu)、ポッドの nodeSelector に一致するノードがない、image-pull シークレットの欠落、PVC マウントの失敗。
OOMKilled(exit 137) — コンテナがメモリを超過しました。バッチサイズを小さくする、max_length を下げる、またはメモリの request / limit を追加してより大きなノードをターゲットにしてください。
CredentialError: Could not authenticate to a Kubernetes cluster — kubeconfig もクラスター内認証も機能しませんでした。kubectl get nodes を実行して設定を確認するか、$KUBECONFIG を正しいパスに設定してください。
このスキルで現在サポートされていないこと
- Elastic/フォールトトレラントなトレーニング。 Indexed Job では
backoff_limit=0に設定されているため、失敗するとトレーニング全体が失敗します。ノード障害後にチェックポイントから再開するなど、Elastic な再起動には、代わりに Kubeflow のPyTorchJobオペレーターを使用してください。 - ギャングスケジューリング。 Indexed Job の Pod は個別にスケジュールされるため、すべてを一括で実行する仕組みはありません。一部の Pod しかスケジュールできない場合、マルチノードトレーニングは一部だけ起動し(rank-0 は他の Pod を待ち続けます)。共有クラスターで一括スケジューリングするには、Volcano または Kueue を使用してください。
- MPI/Horovod。 MPI Operator を使用してください。ここでの Indexed Job の方式は、PyTorch の分散トレーニング形式です(
MASTER_ADDR:MASTER_PORTを使用した環境変数によるランデブー)。 $NGC_KEYからのイメージプルシークレットの自動作成。 対象の名前空間にシークレットを事前に作成し、その名前を渡してください。K8s の名前空間の運用方法はさまざまなため、シークレットの作成は明示的に行う方式にしています。