349 lines
15 KiB
Markdown
349 lines
15 KiB
Markdown
# MVP Roadmap(V1 → V2 → … → 训练平台)
|
||
|
||
本文档在 `specs/mvp/milestones.md` 的草稿基础上做**扩展与细化**:把目标拆成可迭代的版本(MVP v1/v2/…),保证每个版本都能**独立运行、可验证验收**,并且在上一版本基础上演进。
|
||
|
||
> 总目标(North Star):产出一套**基于 Native Ray 集群(无 K8s 底座)**的训练平台,面向多用户,支持 `verl` 各类训练/评测/Serving 工作负载,提升集群利用率,并通过可观测系统实现资源统计、监控告警,最终形成运维 SOP 并可接入运维智能体做自动化运维。
|
||
|
||
---
|
||
|
||
## 0. 关键原则(贯穿所有版本)
|
||
|
||
1) **版本可独立运行**:每个版本都能从“空环境”按文档跑起来(不依赖未来能力)。
|
||
2) **验收可客观验证**:每个里程碑必须有明确的 DoD(Definition of Done)与可复现步骤。
|
||
3) **强制产物落盘**:模型/数据/日志/ckpt 必须可追踪、可复用、可审计(基于共享存储/NFS)。
|
||
4) **Head 不参与计算**:Head 只承担控制面(GCS/Dashboard/Job server),避免训练抢占控制面资源。
|
||
5) **按 submission id 组织作业**:作业输出目录与 Ray submission id 绑定,方便检索、回收、归档。
|
||
6) **“先把 RL 跑稳”,再扩 workload**:先 PPO(已验证),再 GRPO/SFT/Serving。
|
||
|
||
---
|
||
|
||
## 0.1 里程碑总览(建议交付顺序)
|
||
|
||
| 版本 | 定位 | 关键交付 | 核心验收点 |
|
||
|---|---|---|---|
|
||
| v1 | 可复现实验闭环 | Ray 集群 + PPO 跑通 + 持久化 | driver 不在 head;产物落盘 |
|
||
| v1.1 | 实验工程化 | JobSpec 模板 + 新增 1 个 workload | 可回归、可定位、可扩展 |
|
||
| v2.0 | 服务化入口 | API + Ray Jobs SDK | API 提交/查询/停止可用 |
|
||
| v2.1 | 节点纳管 | SSH 注入 + 资源池/标签 | 节点上线/下线、gang 约束 |
|
||
| v3.0 | 平台雏形 | 队列 + 超时 + 最小多用户 | pending→running 自动调度 |
|
||
| v3.1 | 可扩展平台 | 自定义代码/reward + 多版本 | 多版本并存、插件可用 |
|
||
| v4.0 | 可运营平台 | Prom/Grafana + W&B | 资源核算/告警/归档 |
|
||
| v4.1 | 可交接平台 | SOP + 自动化运维接口 | 非开发可按 SOP 运维 |
|
||
| v5.0 | 长期形态 | Serving + Pipeline | 训练→发布推理闭环 |
|
||
|
||
## 1. 当前基线:MVP v1(已完成/已验证)
|
||
|
||
### 1.1 目标
|
||
|
||
在单机(或同一宿主机)用 3 个容器跑通:
|
||
|
||
- Ray head(无 GPU,CPU=0/GPU=0)
|
||
- 2 个 Ray worker(每个 4 GPU)
|
||
- 通过 **head 上的 `ray job submit`** 提交 `verl` PPO(`total_epochs=1`)
|
||
- 通过 **entrypoint 自定义资源**强制 driver 在 worker 上
|
||
- 数据/模型/日志/ckpt 全部持久化
|
||
|
||
### 1.2 交付物(repo 中已存在)
|
||
|
||
- 脚本与 compose:`src/mvp/v1/`
|
||
- 行动与验收文档:`specs/mvp/v1/v1_action.md`
|
||
- 共享目录约定:`shared/datasets`、`shared/hf`、`shared/jobs` 等(与 NFS 对齐)
|
||
|
||
### 1.3 验收口径(摘要)
|
||
|
||
- `ray job list` 的 `driver_info.node_ip_address` ∈ worker IP,且 ≠ head IP
|
||
- 训练输出落在 `/mnt/shared/jobs/<submission_id>/...`
|
||
- checkpoint 按 `save_freq` 产生(避免爆磁盘)
|
||
|
||
---
|
||
|
||
## 2. MVP v1.1(Hardening + 多 workload 可行性验证)
|
||
|
||
> 目标:把 v1 从“实验脚本”升级成“可长期回归的最小系统”,并验证更多 workload 的可行性边界。
|
||
|
||
### 2.1 主要能力
|
||
|
||
- Workload 扩展(可选顺序):
|
||
- PPO(回归金标)
|
||
- GRPO on Ray(可运行验证)
|
||
- SFT on Ray(可运行验证:`llamafactory` 或 `verl` 相关 SFT 路径)
|
||
- 作业模板化(最小实现):
|
||
- 统一 JobSpec(YAML/JSON)描述:workload 类型、资源(nnodes/n_gpus_per_node)、数据、模型、输出目录、超时
|
||
- 仍然用 `ray job submit`,但把 entrypoint 组装逻辑标准化
|
||
- checkpoint 策略与磁盘保护:
|
||
- 默认 `save_freq` ≥ 10(或按训练总 steps 的比例)
|
||
- 明确保留策略(至少提供“保留最后 N 个 ckpt”的配置建议/脚本)
|
||
- “失败可定位”:
|
||
- 统一收敛日志入口(Ray job logs + hydra 日志目录 + 关键参数快照)
|
||
- 失败时能定位:是资源不足 / NCCL / 数据 / 模型 / 配置错误
|
||
|
||
### 2.2 验收(DoD)
|
||
|
||
- 同一套脚本在同一台机器能连续跑 3 次 PPO 回归,产物目录不互相覆盖
|
||
- 至少新增 1 个 workload(GRPO 或 SFT)可以跑通 “启动→训练→落盘” 闭环
|
||
- 作业目录内包含:
|
||
- `config/submit_cmd.txt`(或 job spec 快照)
|
||
- `logs/`(可追踪)
|
||
- `checkpoints/`(按策略生成)
|
||
|
||
---
|
||
|
||
## 3. MVP v2.0(Control Plane 服务化:API + Ray Jobs SDK)
|
||
|
||
> 目标:从“人跑脚本”升级为“服务提交任务”。依然是 Native Ray 集群,但引入一个最小控制平面服务。
|
||
|
||
### 3.1 系统形态
|
||
|
||
- Control Plane(建议部署在 head/CPU 机器):
|
||
- FastAPI 服务(REST)
|
||
- Job 管理:用 Ray Jobs **Python SDK** 提交/查询/停止(不再依赖 CLI 文本解析)
|
||
- 节点视图:读取 Ray state(nodes, actors, placement groups)
|
||
- Data Plane:
|
||
- 仍然是预先启动的 worker 节点加入集群(先不做 SSH 动态纳管也可)
|
||
|
||
### 3.2 API(MVP 级别)
|
||
|
||
- `POST /v1/jobs`:提交 JobSpec(ppo/grpo/sft)
|
||
- `GET /v1/jobs`:列表(含状态、资源、开始/结束时间)
|
||
- `GET /v1/jobs/{id}`:详情(含输出目录、driver node)
|
||
- `POST /v1/jobs/{id}:stop`:停止作业
|
||
|
||
### 3.3 验收(DoD)
|
||
|
||
- API 提交 PPO,返回 submission id;输出目录为 `/mnt/shared/jobs/<submission_id>/...`
|
||
- API 查询 job 状态与 driver node(必须是 worker)
|
||
- 停止 job 后,资源释放、状态可见
|
||
|
||
---
|
||
|
||
## 4. MVP v2.1(SSH 纳管 + 资源池 + Gang 约束)
|
||
|
||
> 目标:对齐你草稿里“SSH 纳管”的约束与需求:控制面能纳管 GPU 节点,形成可运营的资源池。
|
||
|
||
### 4.1 节点纳管(SSH Provisioner)
|
||
|
||
- 控制面保存 NodeSpec(ip/user/port/labels/gpu_count)
|
||
- 通过 SSH 执行:
|
||
- `ray start --address=<head>:6379 --resources=...`
|
||
- `ray stop`(drain/下线)
|
||
- 维护节点状态机:`pending → online → draining → offline`
|
||
|
||
### 4.2 资源池与 gang(All-or-nothing)
|
||
|
||
- 资源池最小模型:
|
||
- pool 标签(如 `pool_a`、`h20`、`ib_domain_1`)
|
||
- 提交 job 时指定 pool 约束
|
||
- Gang 约束(MVP 实现方式):
|
||
- job spec 明确 `trainer.nnodes` + `trainer.n_gpus_per_node`
|
||
- 提交前检查 Ray 可用资源是否满足,不满足则进入 pending 队列(见 v3.0)
|
||
|
||
### 4.3 验收(DoD)
|
||
|
||
- 通过 API 注册 2 个 worker(SSH 注入 ray start)后,`ray status` 可见节点上线
|
||
- 通过 API 下线节点,节点被标记不可调度且不再分配新 job
|
||
- gang 不满足时 job 不提交(或提交后一直 pending),满足后可运行
|
||
|
||
---
|
||
|
||
## 5. MVP v3.0(调度与多用户:队列 + 超时 + 最小权限)
|
||
|
||
> 目标:平台开始“像个平台”:多用户、队列、超时、审计。仍然不做复杂配额/公平调度。
|
||
|
||
### 5.1 作业队列(简单但可用)
|
||
|
||
- FIFO 队列:无优先级
|
||
- “资源满足就调度”:谁先满足谁先跑(可接受非严格 FIFO)
|
||
- job 超时:Ray 原生不支持统一 timeout(草稿已指出),因此控制面需:
|
||
- 记录 start_time
|
||
- 定期扫描超时 job → `stop`
|
||
|
||
### 5.2 多用户最小闭环
|
||
|
||
- 认证(MVP):token 或 basic auth(先不做复杂 RBAC)
|
||
- 归属与隔离(文件层):
|
||
- `/mnt/shared/users/<user>/datasets/`
|
||
- `/mnt/shared/users/<user>/models/`
|
||
- `/mnt/shared/jobs/<submission_id>/` 记录 user/metadata
|
||
|
||
### 5.3 验收(DoD)
|
||
|
||
- 2 个用户可各自提交 job,能看到自己的 job 列表与输出目录
|
||
- 超时策略可触发(模拟短 timeout),job 被停止且状态标记为 timeout
|
||
- 队列在资源不足时保持 pending,资源释放后自动运行
|
||
|
||
---
|
||
|
||
## 6. MVP v3.1(可扩展性:自定义代码/Reward、多版本 VERL)
|
||
|
||
> 目标:把“平台内置 workload”升级成“用户可提交自定义代码与 reward”,并支持多版本并存。
|
||
|
||
### 6.1 自定义代码提交(最小实现)
|
||
|
||
两种方式二选一(建议先做 A):
|
||
|
||
- A:`working_dir` 指向 NFS 上的代码快照目录(用户自己准备/上传)
|
||
- B:上传 zip(控制面落到 NFS 并解压为 code snapshot)
|
||
|
||
### 6.2 多版本 VERL 并存
|
||
|
||
约束前提:**基础镜像保持同一个**(生产环境容器由算力平台创建时已固定镜像标签)。
|
||
|
||
目标:在同一 Ray 集群内,不同 job 可以使用不同版本的 `verl`(例如不同分支/commit 或用户魔改版)。
|
||
|
||
已确认优先方案(A):**必须通过 Ray Job 的 `runtime_env.env_vars` 透传 `PYTHONPATH`**,让 job 粒度优先 import 指定代码快照。
|
||
|
||
建议方案(以 NFS 为中心,最小可行实现):
|
||
|
||
- 在共享存储上以“不可变快照”的方式存放代码版本(推荐 commit hash 命名):
|
||
- `${SHARED_ROOT}/common/code/verl/<commit>/...`
|
||
- `${SHARED_ROOT}/users/<user>/code/verl/<commit>/...`(用户魔改版)
|
||
- JobSpec 增加 `code_path`(指向上述目录),控制面在提交 job 时注入(必须走 runtime_env):
|
||
- `runtime_env.env_vars.PYTHONPATH = "<code_path>:$PYTHONPATH"`(把 code_path 放最前面,确保 import 优先级)
|
||
|
||
示例(概念性,实际以 `${SHARED_ROOT}` 为准):
|
||
|
||
```bash
|
||
CODE_PATH="${SHARED_ROOT}/common/code/verl/<commit>"
|
||
|
||
ray job submit \
|
||
--address="http://127.0.0.1:8265" \
|
||
--submission-id="<submission_id>" \
|
||
--runtime-env-json='{"env_vars": {"PYTHONPATH": "'"${CODE_PATH}"':$PYTHONPATH"}}' \
|
||
-- \
|
||
python3 -m verl.trainer.main_ppo ...
|
||
```
|
||
|
||
需要验证的关键点(作为 v3.1 的 DoD 之一):
|
||
|
||
- 同时运行两个 job:
|
||
- jobA 使用 `<commitA>`,jobB 使用 `<commitB>`
|
||
- 互不影响,且各自训练/日志/ckpt 正常
|
||
- job 粒度是否能做到“依赖隔离”(至少做到 `verl` 版本隔离;第三方依赖冲突可先假设镜像内一致)
|
||
|
||
> 备注:当前 v1 的做法是容器内全局 `pip install -e /workspace/verl`,这会让所有 job 默认使用同一份 `verl`。要实现多版本并存,必须让 job 的 import 优先使用 `code_path`(或为每个 job 单独创建 venv/安装 wheel;后者更重,建议后置)。
|
||
|
||
### 6.3 自定义 reward function
|
||
|
||
- JobSpec 支持 `reward_fn_path`(Python 模块路径)
|
||
- `reward_fn_path` 可指向共享存储中用户自定义代码目录(例如 `${SHARED_ROOT}/users/<user>/code/...`)
|
||
- 约束:代码必须在 job runtime 中可 import(由 `working_dir`/`PYTHONPATH` 或 runtime_env 保障)
|
||
- 控制面校验模块可导入(basic lint/安全白名单可后置)
|
||
|
||
### 6.4 验收(DoD)
|
||
|
||
- 同时运行两个 job:使用不同的 `verl` 代码版本(或用户魔改版本),互不影响
|
||
- 用户可在 JobSpec 中替换 reward function 并跑通一个最小训练闭环
|
||
|
||
---
|
||
|
||
## 7. MVP v4.0(可观测性:Prometheus/Grafana + W&B 集成)
|
||
|
||
> 目标:平台可运营:能回答“谁在用多少资源、跑了多久、利用率如何、是否空占 GPU”。
|
||
|
||
### 7.1 指标与监控
|
||
|
||
- Ray 指标接入 Prometheus(节点/任务/actor)
|
||
- GPU 指标:nvidia exporter 或 DCGM exporter
|
||
- Dashboard:Grafana(至少 3 张核心面板)
|
||
- 集群总 GPU/CPU 使用率、空闲率
|
||
- 每 job 的 GPU 时间、峰值显存、运行时长
|
||
- 节点健康(心跳/掉线)与告警
|
||
|
||
### 7.2 W&B(或等价)集成验证
|
||
|
||
- 最小可行:单机 self-host W&B server 可用性验证
|
||
- JobSpec 支持启用/关闭 W&B,并传入 project/run name
|
||
|
||
### 7.3 验收(DoD)
|
||
|
||
- Grafana 上能看到集群与 job 资源视图
|
||
- 某个 job GPU 利用率异常(模拟)能触发告警规则(邮件/IM/日志即可)
|
||
- W&B 指标能按 job 维度归档(至少 PPO 能上报)
|
||
|
||
---
|
||
|
||
## 8. MVP v4.1(运维化:SOP + 自动化运维接口)
|
||
|
||
> 目标:把平台变成“可交接”的系统:运维动作标准化,并为智能体留出接口。
|
||
|
||
### 8.1 SOP 与自动化入口
|
||
|
||
- SOP 文档:
|
||
- 节点上线/下线
|
||
- 故障定位(Ray session、Ray job、NCCL、OOM)
|
||
- 资源回收(停止 job、清理 ckpt)
|
||
- 自动化接口(最小):
|
||
- `/v1/ops/drain_node`
|
||
- `/v1/ops/restart_ray_head`(谨慎:需要保护与权限)
|
||
- `/v1/ops/cleanup_job_artifacts`
|
||
|
||
### 8.2 验收(DoD)
|
||
|
||
- 按 SOP,非开发人员可完成一次“节点上线→跑任务→下线→清理”
|
||
- 自动化接口至少能完成 1 个高频动作(如清理/停止/下线)
|
||
|
||
---
|
||
|
||
## 9. MVP v5.0(Serving 与 Pipeline,偏长期)
|
||
|
||
> 目标:训练-部署一体化:支持 model serving,并在平台内串联训练→评测→发布。
|
||
|
||
### 9.1 Serving
|
||
|
||
- Ray Serve(或等价)部署模型推理服务
|
||
- Serving 与训练共用模型库与权限(按 user/project)
|
||
|
||
### 9.2 Pipeline(草稿里标为高级)
|
||
|
||
- Pipeline 是对多个 job 的封装(训练→merge→eval→publish)
|
||
- 可先实现最小 DAG(两步串联)作为验证
|
||
|
||
### 9.3 验收(DoD)
|
||
|
||
- 训练产物一键发布为一个可访问的推理 endpoint
|
||
- Pipeline 能自动串联并产出最终 artifact(可回滚/可追踪)
|
||
|
||
---
|
||
|
||
## 10. 并行技术验证(建议尽早做)
|
||
|
||
这些属于“跨版本”风险项,建议在 v1.1 ~ v2.0 期间尽早做:
|
||
|
||
### 10.1 网络(IB / RoCEv2)
|
||
|
||
- 确认环境是否支持 IB(H100)或 RoCEv2(H20)
|
||
- 跑最小 NCCL 通信验证(all-reduce / bandwidth)
|
||
- 将必要的 NCCL 环境变量注入到 job runtime_env
|
||
|
||
### 10.2 Ray + 多节点容器约束
|
||
|
||
- 多容器同宿主机时的 Ray node_ip/临时目录冲突规律(已踩坑,需固化规范)
|
||
- 端口范围与防火墙策略(Ray worker 端口、dashboard、metrics)
|
||
|
||
---
|
||
|
||
## 11. 已确认的约束与假设(来自讨论结论)
|
||
|
||
这些会直接影响 v2.1(SSH 纳管)与后续多用户/存储设计:
|
||
|
||
1) **最终形态仍以“每节点容器”运行**(不是裸机 systemd)。
|
||
- H20 开发环境:我们可在宿主机用 `docker compose` 自建容器,并通过 SSH 进入容器调试/纳管。
|
||
- H100 生产环境:容器由算力平台创建/回收;平台侧控制面只能 **SSH 进入这些容器** 做纳管(执行 `ray start/stop`、注入 env 等)。
|
||
2) **认证**:内部 token 即可(MVP 阶段不对接 SSO)。
|
||
3) **存储**:只考虑 NFS。
|
||
- 开发环境:NFS/共享目录可通过宿主机 bind mount 提供给容器。
|
||
- 生产环境:所有容器挂载相同 NFS,容器内共享根路径为 `/private/`(需要在实现时把“共享根路径”做成可配置项,而不是写死 `/mnt/shared`)。
|
||
4) **网络拓扑约束**:暂不做按 IB 域/机架/拓扑的强约束调度(第 10.1 仍需验证 IB/RoCE 是否可用与配置方式,但调度不引入拓扑维度)。
|
||
5) **共享目录分层**:在 `users/<user>/...` 之外增加一个可读写的 `common/` 目录用于共享数据/模型/代码:
|
||
- `${SHARED_ROOT}/common/datasets/`
|
||
- `${SHARED_ROOT}/common/models/`
|
||
- `${SHARED_ROOT}/common/code/`
|
||
- 权限(MVP):先默认“所有内部 token 用户可读写”,后续再细化只读/受控写。
|
||
|
||
---
|
||
|
||
## 12. 仍需你确认/讨论的问题(剩余不确定项)
|
||
|
||
1) `runtime_env.env_vars` 注入对“子进程/训练框架内部启动进程”的覆盖范围是否足够?
|
||
- 需要确认 `verl`/`sglang` 等子进程是否继承 driver 的环境变量(通常会继承,但建议在 v3.1 验收时明确验证)。
|