launch-nemo-rl について
`nrl-k8s` を使い、Kubernetes 上で NeMo-RL のレシピを起動、監視、デバッグするための手順書です。エフェメラルまたは長期稼働の Ray クラスターを扱い、共有クラスターの状態確認を重視します。
主な機能
- 01`nrl-k8s run` によるレシピの送信
- 02エフェメラルまたは長期稼働クラスターの選択
- 03レシピとインフラ設定の検証
- 04クラスター、ジョブ、Pod のログ確認
- 05Ray クラスターとデプロイの管理
活用シーン
- 01単発の NeMo-RL トレーニングの起動
- 02レシピの反復時にクラスターを再利用
- 03ジョブの進捗確認と障害の診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ promptingcompany/ nv-skills --skill launch-nemo-rlインストール後、Claude Code で/launch-nemo-rlを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
BENCHMARK.mdskill-card.mdskill.oms.sigevals/evals.json詳細
launch-nemo-rl — nrl-k8s を使用して Kubernetes 上で NeMo-RL レシピを実行する
これは、infra/nrl_k8s/ にある nrl-k8s CLI のプレイブックです。ユーザーから Kubernetes クラスター上で NeMo-RL レシピを起動、反復、デバッグするよう依頼された場合は、この手順に従ってください。操作を始める前に、現在の状態(kubectl、git log、レシピとインフラファイル)を確認してください。クラスターは共有されており、誤った操作のコストは高いためです。
1. 1 つのコマンド、2 つのモード
トップレベルの送信コマンドは nrl-k8s run の 1 つだけです。ライフサイクルモードは 2 つあります。
| モード | 呼び出し | 使用する場面 | 実行後のクラスター |
|---|---|---|---|
| エフェメラル(デフォルト) | nrl-k8s run | 1 回限りの実行です。KubeRay が RayJob を適用して実行し、クラスターを削除します。ほとんどの実行に適しています。 | なし(自動削除) |
| 長時間稼働 | nrl-k8s run --raycluster | 開発ループ向けです。一致する稼働中のクラスターを再利用し、存在しない場合は適用します。構成に差異がある場合は警告して再利用します(置き換えるには --recreate を指定します)。その後、デーモンとトレーニングを送信します。反復作業で最初に選ぶ方法です。 | あり |
次のように考えてください。実行後もこのクラスターが必要ですか? 必要な場合は --raycluster を使用してください。そうでなければ、デフォルト(エフェメラル)を使用します。
CLI の残りのコマンドは、可観測性とステージごとの制御に使います。
| コマンド | 目的 |
|---|---|
nrl-k8s check | レシピとインフラの組み合わせを検証します。必要に応じて、完全に解決されたマニフェストを書き出します(-o)。 |
nrl-k8s status | ロールごとの RayCluster の状態、ヘッド Pod のフェーズ、ワーカー Pod のフェーズ、デーモンジョブのステータスを表示します。 |
nrl-k8s cluster up/down/list/dashboard | 実行とは独立して RayCluster を管理します(例:--dry-run を指定してマニフェストをレンダリングします)。 |
nrl-k8s job list/logs/stop | ロールのクラスターにすでに送信された Ray Jobs の可観測性を提供します。 |
nrl-k8s logs | 送信 ID がなくても、ロールの Pod またはデーモンのログを追跡します。 |
2. レシピとインフラの組み合わせ
起動時には、必ず 2 つのファイルを指定します。インフラは --infra で渡し、インラインで統合しないでください。
nrl-k8s run infra/nrl_k8s/examples/<recipe>.yaml \
--infra infra/nrl_k8s/examples/<recipe>.<profile>.infra.yaml
- レシピ(例:
qwen3_30b_math_8n_4gpu.yaml)— モデル、GRPO/SFT の設定、cluster.{gpus_per_node,num_nodes}を含む NeMo-RL の構成です。defaults:を使ってexamples/configs/recipes/llm/...から継承します。 - インフラ(例:
*.<profile>.infra.yaml)— 名前空間、イメージ、サービスアカウント、kuberay:配下の RayCluster 仕様、任意のdeployments:配下の Deployment、submit.submitter、launch.{mode,codeSource,codePath,entrypoint}を含む K8s/Ray の構成です。組み合わせるファイル名は<recipe>.<profile>[.prod].infra.yamlという形式で、<profile>はハードウェアの対象を表します(例:gb300)。
infra/nrl_k8s/examples/ に組み合わせの例があります。対象のプロファイルに関する現在の規約を確認するには、近くにあるファイルを読んでください。
3. 長時間実行モードのフラグ
独立した3つの要素があります。--mode はデフォルト値を選択するマクロです。個別のフラグで上書きできます。
--mode interactive → --submitter portForward --code-source upload (tails logs)
--mode batch → --submitter exec --code-source image (returns after nohup)
- 送信方法:
portForwardはkubectl port-forwardと Ray Job SDK を使用します(ダッシュボードで追跡されるsubmission_idを取得します)。execはヘッド Pod でkubectl execとnohupを使用します(submission_idはなく、ドライバーはダッシュボードにtype=DRIVERとして表示されます)。 - コードのソース:
uploadはノート PC から working_dir をステージングします(Ray の上限は 100 MiB です)。image/lustreは Pod のファイルシステム上にコードがあることを前提とします。標準のインフラストラクチャ例では、共有ファイルシステムの PVC マウントの subPath である--code-path(通常は/opt/nemo-rl)と組み合わせて使用します。 - 待機:
--waitは終了状態になるまでログを追跡します。--no-waitはドライバーの実行開始後すぐに戻ります。
長時間実行モードでのみ使用するその他のフラグ:
--replace— 新しいジョブを送信する前に、実行中のトレーニングジョブやデーモンジョブを停止します(Ray が再送信を受け付けるよう、デーモンの submissionId にタイムスタンプを付加します)。--recreate— 現在の仕様がレンダリング済みマニフェストから乖離している RayCluster を削除して再適用します(デフォルトでは警告して再利用します)。--skip-daemons— 宣言されたすべてのクラスターを起動しますが、トレーニングのみを送信します。gym/generation がすでに正常に稼働している disagg レシピで使用します。
注意点:エントリーポイントで cd /opt/nemo-rl(またはイメージ内や Lustre 上の別のパス)を実行し、そこからレシピを読み込むインフラストラクチャでは、--code-source upload を指定しても Pod 上のレシピは上書きされません。アップロードされた working_dir は /tmp/ray/... に置かれますが、エントリーポイントが別の場所に cd するためです。ローカルでのレシピ変更を実際にテストするには、編集内容を Pod にマウントされた共有ファイルシステムに同期するか、エントリーポイントの Hydra オーバーライドを変更してください。
4. エフェメラルモードのフラグ(--rayjob)
--rayjob を指定すると、run は RayJob のコードパスに分岐します。関連するフラグは次のとおりです。
--rayjob-name NAME— RayJob のメタデータ名(デフォルトはトレーニングクラスター名です)。--shutdown / --no-shutdown— デフォルトはtrueです。Ray Job が終了状態に達すると、KubeRay は RayCluster を削除します。--ttl SECONDS— デフォルトは 3600s です。実行終了後も RayJob オブジェクトを保持し、事後調査のためにログへアクセスできるようにします。--wait / --no-wait— デフォルトはwaitです。jobDeploymentStatusが Complete/Failed になるまでポーリングします。--no-waitは RayJob の適用後すぐに戻ります。--timeout SECONDS— デフォルトは 86400s(24h)です。--waitのポーリング時間の上限を指定します。--dry-run— RayJob マニフェストをレンダリングして出力します。適用はしません。
--replace / --recreate / --skip-daemons は、--rayjob モードでは何も通知せず無視されます(ライフサイクルは KubeRay が管理します)。
5. 共有ファイルシステムに触れずに設定を反復する
Pod のファイルシステム上にあるレシピの値が実験に適さない場合は、レシピをフォークする代わりに、エントリーポイントで Hydra オーバーライドを使用します。形式:
entrypoint: |
set -eu
cd /opt/nemo-rl
RUN_ID="\${RAY_JOB_SUBMISSION_ID:-\${NRL_K8S_RUN_ID:-$(date -u +%Y%m%d-%H%M%S)}}"
python -u examples/run_grpo.py \
--config infra/nrl_k8s/examples/<recipe>.yaml \
logger.wandb_enabled=true \
logger.wandb.project=<project> \
"logger.wandb.name=<run-name>-\${RUN_ID}"
${…} はバックスラッシュでエスケープしてください。エスケープしないと、OmegaConf がこれを補間として解釈し、シェル形式の ${VAR:-default} でエラーになります。RUN_ID は RAY_JOB_SUBMISSION_ID(rayjob モードでは KubeRay が注入)→ NRL_K8S_RUN_ID(長時間実行モードでは CLI が注入)→ ローカルのタイムスタンプの順に解決されるため、どちらの経路でも名前が一意になります。
6. プロファイルごとの注意点(ハードウェア+スケジューラー+DRA)
すべてのインフラ YAML には、ハードウェア/スケジューラーのプロファイルが定義されています。infra/nrl_k8s/examples/ にある具体例は、対象とするプロファイルの正式な情報です。新しいファイルを作成する前に、近くにあるインフラファイルを確認してください。よく異なる項目は次のとおりです。
- ノードあたりの GPU 数(例:4 基か 8 基) — レシピの
cluster.gpus_per_nodeと一致させる必要があります。一致しないと、ワーカーはPendingのままになります。 - ノードセレクター — ヘッドポッドは通常、CPU のみのノードプールに配置されます。GPU ワーカーは
nvidia.com/gpu.productまたはノードグループラベルで照合されます。 - スケジューラー — トポロジーアノテーション(
kai.scheduler/topology、kai.scheduler/topology-required-placement)を伴う KAI(schedulerName: kai-scheduler+kai.scheduler/queueラベル)により、ワーカーは 1 つのクリークにギャングスケジューリングされます。これがない場合、ポッドが異なるラックに配置され、NVLink/RoCE がそれらをまたいで機能しない可能性があります。 - DRA クレーム — ComputeDomain と RoCE は、
ResourceClaimTemplateを参照するresourceClaimsを介してアタッチされます。ワーカーポッドの仕様に DRA クレームへの参照が含まれている場合、CLI がこれらを自動で作成/削除するため、手動でのセットアップは不要です。 - シークレット — 必ず
secretKeyRef(wandb-api-key、イメージプルシークレット)を介して指定します。埋め込まないでください。 - 共有ファイルシステムのマウント — 通常は Lustre PVC を 2 回マウントします。1 回目はコードのパス(例:ユーザーごとの
subPathを使う/opt/nemo-rl)に、2 回目はデータセット、HF キャッシュ、チェックポイント用のワークスペースルート(例:/mnt/rl-workspace)にマウントします。
インフラを適用する前に、対象の名前空間に前提条件が存在することを確認してください。
kubectl get pvc <workspace-pvc>
kubectl get secret <wandb-secret> <image-pull-secret>
kubectl get sa <service-account>
7. エンドツーエンドのワークフロー
7a. 新規のワンショット実行(rayjob)
# From the NeMo-RL repo root:
nrl-k8s check <recipe> --infra <infra> # validate first
nrl-k8s run <recipe> --infra <infra> --rayjob --dry-run # render RayJob manifest
nrl-k8s run <recipe> --infra <infra> --rayjob --no-wait # apply, returns fast
ステータスの監視と終了処理を行います(KubeRay がライフサイクルを管理するため、ノート PC の接続が切れた後も実行できます)。
kubectl get rayjob -n default <name> -w
kubectl get raycluster -n default # empty = teardown succeeded
7b. 開発ループ(長時間実行)
nrl-k8s run <recipe> --infra <infra> --run-id $(date +%Y%m%d-%H%M%S)
# Edits in the recipe? Just re-run — reuses the live cluster.
# Pod spec changed? Add --recreate to delete + re-apply.
# Disagg recipe with gym/gen already healthy? --skip-daemons.
7c. 初回の分離構成の起動
nrl-k8s run <recipe> --infra <disagg-infra> --mode batch --code-source image
7d. クラスターのみのライフサイクル
nrl-k8s cluster up <recipe> --infra <infra> --target kuberay.training --wait
nrl-k8s cluster up <recipe> --infra <infra> --target kuberay.training --dry-run # render manifest
nrl-k8s cluster down <recipe> --infra <infra> --target kuberay.training --wait
nrl-k8s cluster down <recipe> --infra <infra> # tear down all
nrl-k8s cluster list -n default
nrl-k8s cluster dashboard <cluster-name> # port-forward + browser
7e. デプロイメント(例:nemo-skills サンドボックス)
# Bring up just the deployment
nrl-k8s cluster up <recipe> --infra <infra> --target deployments.nemo_skills
# Tear down just the deployment
nrl-k8s cluster down <recipe> --infra <infra> --target deployments.nemo_skills
# Tear down everything (RayClusters + Deployments)
nrl-k8s cluster down <recipe> --infra <infra>
インフラ YAML の deployments: セクションでは、RayClusters と並行して管理される Kubernetes Deployment を宣言します。CLI は、最上位のインフラキーからイメージ、imagePullSecrets、serviceAccountName をパッチします(RayClusters と同じです)。Deployment はクラスターの起動と並行して開始され、順序に依存しません。
8. 実行の監視
# Status
nrl-k8s status <recipe> --infra <infra>
kubectl get rayjob,raycluster -n default
# Follow the driver
nrl-k8s job list <recipe> --infra <infra> --role training
nrl-k8s job logs <run-id> <recipe> --infra <infra> --role training -f
nrl-k8s job logs -f のサブプロセスが停止した場合(アイドル状態が約 15 分続くと kubectl port-forward が i/o タイムアウトします)、コマンドを再実行してください。トレーニングジョブはそのまま続行されます。
終了済みジョブ(SUCCEEDED/FAILED)または RayJob のドライバーログを、ダッシュボード API から取得するには、次のようにします。
RC=$(kubectl get rayjob -n default <rayjob-name> -o jsonpath='{.status.rayClusterName}')
kubectl port-forward -n default svc/${RC}-head-svc 18266:8265 &
curl -s http://localhost:18266/api/jobs/ # lists jobs, find submission_id
curl -s "http://localhost:18266/api/jobs/<submission_id>/logs" # full driver log
submission_id=null の type=DRIVER は、exec-submitter の実行を意味します(ダッシュボードのログエンドポイントはありません。代わりに nrl-k8s job logs を使用してください)。submission_id が設定された type=SUBMISSION では、/api/jobs/<id>/logs を使用できます。
Wandb の URL は、最初の wandb.init 呼び出し時にドライバーログに表示されます。grep -oE 'https://wandb\.ai/[A-Za-z0-9_./-]+' で検索してください。
9. 実行中の処理を停止する
| 停止対象 | コマンド |
|---|---|
| 1 つのトレーニング実行 | nrl-k8s job stop <run-id> <recipe> --infra <infra> --role training |
| クラスター上の実行中のすべての Ray ジョブ(+新しいジョブの送信) | nrl-k8s run <recipe> --infra <infra> --replace |
| 長時間実行中の RayCluster | nrl-k8s cluster down <recipe> --infra <infra> --target kuberay.training --wait |
| RayJob(一時的) | kubectl delete rayjob <name> -n default — shutdownAfterJobFinishes が実行されなかった場合のみ |
共有インフラを削除する前に確認してください。他の人のクラスターに対して cluster down を実行した場合のコストは大きくなります。
10. RayJob の終了処理を確認する
run --rayjob が --shutdown(デフォルト)を指定して完了すると、KubeRay は RayCluster を削除するはずです。
kubectl get rayjob -n default <rayjob-name> # jobDeploymentStatus = Complete
kubectl get raycluster -n default | grep <rayjob-name> # no output = torn down
RayJob オブジェクト自体は、ログを引き続き取得できるように、--ttl 秒間(デフォルトは 3600 秒)残ります。
11. よくある注意点
- OmegaConf のインターポレーションは、レシピ/インフラの YAML にある
${VAR}を処理してしまいます。OmegaConf がポッドのシェルにそのまま渡せるよう、シェル変数は\${VAR}としてエスケープしてください。 - Megatron のオプティマイザー設定には
foreach/fusedがありません。~policy.optimizer.kwargs.foreach ~policy.optimizer.kwargs.fusedのようなオーバーライド(DTensor 設定では有効)は、Megatron のレシピではエラーになります。Megatron では指定しないでください。 - DTensor と Megatron — MoE レシピでは通常
megatron_cfg.enabled=trueを使用します。継承したデフォルト設定でdtensor_cfg.enabled=falseになっていることを確認してください。 - 共有ファイルシステムと Git の差異 —
codeSource: image|lustreはポッドのファイルシステムから読み込みます。ローカルの変更がポッドのマウント先である共有ファイルシステムに反映されていない場合、実行時にテストされるのは手元の変更ではなく、ディスク上のバージョンです。ヘルパーポッド経由で同期する(ヘッドポッドでの exec はブロックされることがよくあります)か、Hydra フラグでオーバーライドしてください。 - ephemeral-storage と readinessProbe は、ポッドの適用時に kuberay/CDI のウェブフックによって挿入されます。インラインの RayCluster 仕様には追加しないでください。
- ノードのテイントはクラスターごとに異なります。ワーカーの
tolerations: [{operator: Exists}]は防御的な設定なので、維持する価値があります。 - ダッシュボードが空白になる場合 — Ray 2.52 では、デフォルトでダッシュボードのアセットがシンボリックリンクとしてインストールされます。
nrl-k8s cluster dashboard <name>は、これを修正するためにray[default] --link-mode=copyを自動で再インストールします。これを完全に避けるには、イメージにENV UV_LINK_MODE=copyを設定してください。 - 自動化では通常
kubectl execがブロックされます —kubectl get ... -o yaml、kubectl logs、およびkubectl port-forwardと Ray ダッシュボード API を使って回避してください。
12. 実行を「完了」とする前のチェックリスト
起動が成功したと報告する前に、次の項目を確認してください。
kubectl get rayjob/raycluster -n defaultに想定したオブジェクトが表示されること。nrl-k8s job list(またはcurl /api/jobs/)で、ジョブがRUNNING/SUCCEEDEDと表示されること。- ドライバーログに
wandb.ai/<project>/runs/<id>が含まれること(wandb が有効な場合)。ユーザーに URL を共有してください。 Processed prompts: 100%の行が少なくとも 1 つ表示されること(生成処理が接続されていることを確認します)。--rayjobモードの場合のみ:jobDeploymentStatus=Completeの後、kubectl get raycluster | grep <name>の結果が空であることを確認してください(ティアダウンが機能しています)。
13. 開発用ポッド
nrl-k8s dev は、コードの同期、デバッグ、クラスター内からの kubectl/nrl-k8s の実行に使う、軽量な CPU ポッドをクラスター上で管理します。
# One-time: set up secrets (HF token, wandb, SSH key, rclone)
nrl-k8s dev setup-secrets --ssh-key ~/.ssh/id_rsa --add-rclone
# Create pod and exec in (idempotent — reuses existing pod)
nrl-k8s dev connect
# Switch image (must stop first — image change is warned but not auto-applied)
nrl-k8s dev stop
nrl-k8s dev connect --image nvcr.io/nvidian/nemo-rl:v0.7.0
# Tear down
nrl-k8s dev stop
開発用ポッド:
- CPU 専用ノードで実行されます(GPU ノードとはアンチアフィニティを設定)
- 共有
rl-workspacePVC を/mnt/rl-workspaceにマウントします USER環境変数にnrl-k8sのユーザー名を設定します(root として実行されても、$USERとgetpass.getuser()が正しく動作します)- 初回起動時に
kubectlとrclone(設定されている場合)をインストールします - ユーザーごとの K8s Secret から、
envFromを介して SSH キーとトークンを注入します
ポッド内で kubectl を使うには、ポッドの default サービスアカウントに、その名前空間で edit RoleBinding が必要です。dev connect はこれを確認し、見つからない場合は必要な YAML を表示します。
14. リポジトリ内のファイルの場所
- CLI コード:
infra/nrl_k8s/src/nrl_k8s/(cli.py、orchestrate.py、manifest.py、rayjob.py、k8s.py、submitters/、schema.py)。 - テスト:
infra/nrl_k8s/tests/unit/—infra/nrl_k8s/からuv run --extra test pytest -x -qを実行します。 - レシピとインフラの例:
infra/nrl_k8s/examples/。 - このツールがラップするベースレシピ:
examples/configs/recipes/llm/…およびexamples/nemo_gym/…。