关于 launch-nemo-rl
这是使用 `nrl-k8s` 在 Kubernetes 上启动、监控和排查 NeMo-RL 配方的操作指南,涵盖临时与长期运行的 Ray 集群流程,并强调操作共享集群前先核实状态。
主要功能
- 01使用 `nrl-k8s run` 提交配方
- 02选择临时或长期集群
- 03验证配方与基础设施配置
- 04查看集群、作业和 Pod 日志
- 05管理 Ray 集群与部署
适用场景
- 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. 一条命令,两种模式
只有一个顶层提交命令:nrl-k8s run。它有两种生命周期模式。
| 模式 | 调用 | 使用时机 | 运行后集群? |
|---|---|---|---|
| 临时(默认) | nrl-k8s run | 一次性运行。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 Job。 |
nrl-k8s logs | 查看某个角色的 Pod / 守护进程日志,无需提交 ID。 |
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)——NeMo-RL 配置:模型、GRPO/SFT 参数、cluster.{gpus_per_node,num_nodes}。使用defaults:继承自examples/configs/recipes/llm/...。 - 基础设施文件(例如
*.<profile>.infra.yaml)——K8s/Ray 配置:命名空间、镜像、服务账号、kuberay:下的 RayCluster 规范、可选的deployments:、submit.submitter、launch.{mode,codeSource,codePath,entrypoint}。成对文件的名称遵循<recipe>.<profile>[.prod].infra.yaml格式,其中<profile>表示硬件目标(例如gb300)。
infra/nrl_k8s/examples/ 中提供了示例文件对——请阅读同一目录下的文件,了解目标配置的当前约定。
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(会获取一个由 dashboard 跟踪的submission_id)。exec使用kubectl exec+ head pod 上的nohup(没有 submission_id;driver 在 dashboard 中显示为type=DRIVER)。 - 代码来源:
upload会从笔记本电脑暂存一个 working_dir(Ray 上限为 100 MiB)。image/lustre需要代码位于 pod 的文件系统上,并与--code-path配合使用(通常为/opt/nemo-rl);在标准基础设施示例中,该路径是共享文件系统 PVC 挂载的 subPath。 - 等待方式:
--wait会持续跟踪日志,直到任务进入终止状态;--no-wait会在 driver 运行后立即返回。
其他仅适用于长期运行模式的标志:
--replace— 提交新任务前,停止所有正在运行的训练任务 / 守护任务(为守护任务的 submissionIds 添加时间戳后缀,以便 Ray 接受重新提交)。--recreate— 删除并重新应用实时 spec 与渲染后的清单不一致的 RayCluster(默认会发出警告并复用)。--skip-daemons— 启动所有声明的集群,但只提交训练任务。适用于 gym / generation 已运行正常的分离式配置。
注意:在入口点会执行 cd /opt/nemo-rl(或其他镜像内 / Lustre 路径)并从该路径加载配置的基础设施中,--code-source upload 不会覆盖 pod 上的配置——上传的 working_dir 位于 /tmp/ray/...,但入口点会切换到其他路径。要实际测试本地配置更改,请将修改同步到挂载到 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 清单并打印;不应用该清单。
在 --rayjob 模式下,--replace / --recreate / --skip-daemons 会被静默忽略(生命周期由 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 会将其解释为插值,并因 shell 风格的 ${VAR:-default} 而报错。RUN_ID 会依次解析为 RAY_JOB_SUBMISSION_ID(rayjob 模式下由 KubeRay 注入)→ NRL_K8S_RUN_ID(长期运行模式下由 CLI 注入)→ 本地时间戳,因此在两种路径下名称都具有唯一性。
6. 各配置的注意事项(硬件 + 调度器 + DRA)
每个 infra YAML 都定义了一种硬件/调度器配置。infra/nrl_k8s/examples/ 中的具体示例是其目标配置的权威参考——编写新文件前,请先查看相邻的 infra 文件。以下方面通常会有所不同:
- 每个节点的 GPU 数量(例如 4 个或 8 个)——必须与配方中的
cluster.gpus_per_node一致,否则工作器会一直处于Pending状态。 - 节点选择器——头部 Pod 通常会调度到仅含 CPU 的节点池;GPU 工作器则通过
nvidia.com/gpu.product或节点组标签进行匹配。 - 调度器——KAI(
schedulerName: kai-scheduler+kai.scheduler/queue标签)结合拓扑注解(kai.scheduler/topology、kai.scheduler/topology-required-placement),可将工作器成组调度到同一集群中。若没有这些设置,Pod 可能会落到不同机架上,NVLink/RoCE 将无法跨机架连接。 - DRA 声明——通过引用
ResourceClaimTemplate的resourceClaims挂载 ComputeDomain + RoCE。当工作器 Pod 规格中包含 DRA 声明引用时,CLI 会自动创建/删除这些资源,无需手动设置。 - 密钥——始终使用
secretKeyRef(wandb-api-key、镜像拉取密钥)。切勿直接嵌入。 - 共享文件系统挂载——通常使用 Lustre PVC 挂载两次:一次挂载到代码路径(例如
/opt/nemo-rl,使用限定用户范围的subPath),另一次挂载到工作区根目录(例如/mnt/rl-workspace),用于存放数据集、HF 缓存和检查点。
应用 infra 前,请确认目标命名空间中已存在所需的前置资源:
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 管理):
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 sandbox)
# 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>
infra YAML 中的 deployments: 部分声明了与 RayClusters 一同管理的 Kubernetes 部署。CLI 会从顶层 infra 键中修补镜像、imagePullSecrets 和 serviceAccountName(与 RayClusters 相同)。部署会与集群并行启动,不存在顺序依赖。
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 子进程退出(kubectl port-forward 在空闲约 15 分钟后发生 i/o 超时),只需重新运行该命令。训练作业会继续运行。
若要通过 dashboard API 获取终止作业(SUCCEEDED/FAILED)或 RayJob 的驱动程序日志:
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
type=DRIVER 且 submission_id=null 表示 exec-submitter 运行(dashboard 没有日志端点——请改用 nrl-k8s job logs)。type=SUBMISSION 表示已设置 submission_id,此时 /api/jobs/<id>/logs 可用。
Wandb URL 会在首次调用 wandb.init 时出现在驱动程序日志中;使用 grep -oE 'https://wandb\.ai/[A-Za-z0-9_./-]+' 搜索。
9. 停止任务
| 要停止的内容 | 命令 |
|---|---|
| 一个训练运行 | 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 未生效时 |
删除共享 infra 前请先确认。对他人的集群执行 cluster down 代价很高。
10. 验证 RayJob 清理
使用 --shutdown(默认值)运行的 run --rayjob 完成后,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}。使用\${VAR}转义 shell 变量,让 OmegaConf 将其原样传递给 pod shell。 - 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从 pod 文件系统读取代码。如果本地修改不在 pod 挂载的共享文件系统上,那么运行测试的是磁盘上的版本,而不是你的版本。可以通过辅助 pod 同步(通常会阻止执行 head pod 命令),或使用 Hydra 标志覆盖。 - Ephemeral-storage 和 readinessProbe由 kuberay/CDI webhook 在应用 pod 时注入。请勿将它们添加到内联 RayCluster 规范中。
- 节点污点因集群而异。在 worker 上设置
tolerations: [{operator: Exists}]是一种稳妥的做法,建议保留。 - Dashboard 空白页——Ray 2.52 默认将 dashboard 资源安装为符号链接;
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 dashboard 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%(确认生成流程已正确接通)。 - 仅适用于
--rayjob模式:在jobDeploymentStatus=Complete后,确认kubectl get raycluster | grep <name>无输出(表示已成功清理)。
13. 开发 pod
nrl-k8s dev 会在集群上管理一个轻量级 CPU pod,用于同步代码、调试,以及在集群内运行 kubectl / nrl-k8s。
# 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
开发 pod:
- 在仅有 CPU 的节点上运行(与 GPU 节点设置反亲和性)
- 将共享的
rl-workspacePVC 挂载到/mnt/rl-workspace - 将
USER环境变量设为nrl-k8s用户名(这样即使以 root 身份运行,$USER和getpass.getuser()也能正常工作) - 首次启动时安装
kubectl、rclone(如果已配置) - 通过
envFrom从按用户配置的 K8s Secret 注入 SSH 密钥和令牌
pod 的 default 服务账号需要在命名空间中绑定 edit RoleBinding,才能在其中使用 kubectl。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/…。