mcpField
T
tao-run-on-kubernetes

tao-run-on-kubernetes

github.com/nvidiaクラウド・DevOps3.8k1.6k 回インストール今日更新
リポジトリ

tao-run-on-kubernetes について

kubeconfigまたはPod内サービスアカウントで接続できるクラスターに、TAOコンテナジョブをKubernetes Jobとして投入するプラットフォームスキルです。投入、状態確認、ログ取得、キャンセルに対応し、Indexed Jobによるマルチノード学習も実行できます。

主な機能

  1. 01kubectlによるTAOジョブ投入
  2. 02クラスターとGPU容量の確認
  3. 03状態追跡とログ取得
  4. 04ジョブのキャンセルと結果記録
  5. 05マルチノード分散学習

活用シーン

  1. 01KubernetesクラスターでTAOジョブを起動
  2. 02投入済みジョブの進捗とログを確認
  3. 03複数Podにまたがる分散学習

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nvidia/skills --skill tao-run-on-kubernetes

インストール後、Claude Code で/tao-run-on-kubernetesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

BENCHMARK.md
config.json
eval.config
skill-card.md
skill.oms.sig
config/
skillspector-baseline.yaml
evals/
evals.json
references/
action-request.md
local-cluster.md
skill_info.yaml
scripts/
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
  1. 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; }
    
  2. ストレージ層(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 が検証済みの読み取り専用コンフィグマウントを受け取ります。レガシーの単一ルートテンプレートでは、その契約を表現できません。

  3. レコードを開く — 起動前に 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 オブジェクトから何も復元できません。

  4. レンダリング、ゲート、適用、そして 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 ≥ 1RUNNING
condition CompleteCOMPLETE
condition FailedERROR (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 つの動詞に加えて:

  1. バージョンゲート: k8s ≥ 1.28 を要求(kubectl version -o json) — MASTER_ADDR=<job>-0.<svc> が解決する Pod ホスト名 <job>-<index>(PodIndexLabel)にはこれが必要です。古いクラスターではランク 0 がランデブーでハングします。
  2. 容量ゲート ×nodes: 割り当て可能な GPU が gpus_per_node × nodes 以上でない限りハードフェイル(ギャングスケジューリングなし → 部分的な起動ではランク 0 が永遠に待機したままになります)。
  3. templates/k8s/indexed-job.yaml.tmpl をレンダリング — ヘッドレス Service + Indexed Job + ランデブー環境変数(WORLD_SIZE = ノード数、JOB_COMPLETION_INDEX からの NODE_RANK、MASTER_ADDR=<job>-0.<svc>、NCCL がサイレントにハングしないよう /dev/shm 16Gi)。kubectl apply -f は Service と Job を同時に作成します;cancel は Job(Foreground)と Service を削除します。
  4. 最初に 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 をレンダリングすると、次のものがプロビジョニングされます。

  1. Job と同じ名前の ヘッドレス Service(セレクター:job-name=<job-name>、clusterIP: None、すべての Pod が Ready になる前に相互検出できるよう publishNotReadyAddresses: true)。

  2. parallelism = completions = num_nodes、completionMode: Indexed の Indexed Job。各 Pod には、k8s によって JOB_COMPLETION_INDEX が自動的に設定されます(=ノードランク)。

  3. ユーザーコマンドを呼び出す前にランデブー用の環境変数をエクスポートする コマンドラッパー。次の 2 つの命名規則が同時にエクスポートされます。

    環境変数値読み取り元
    WORLD_SIZEnum_nodesTAO PyTorch コンテナーの nvidia_tao_pytorch/core/entrypoint.py(PyTorch 独自の規則では 全プロセス数 を意味しますが、こちらでは ノード数 として使用されます)
    NUM_GPU_PER_NODEgpu_countTAO PyTorch コンテナーのエントリーポイント
    NNODESnum_nodestorchrun と PyTorch 標準のランデブー
    NPROC_PER_NODEgpu_counttorchrun
    NODE_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 オペレーターの代替案

より高度なトポロジー(ギャングスケジューリング、PyTorch Elastic / フォールトトレラント学習、MPI / Horovod、RDMA セットアップ)が必要な場合は、素の Indexed Job ではなくオペレーターを利用してください。

このスキルの 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 の名前空間の運用方法はさまざまなため、シークレットの作成は明示的に行う方式にしています。

コメント