argus-cluster/specs/mvp/v3.0/v3.0_design.md

20 KiB
Raw Blame History

MVP v3.0 详细设计方案(基于 v2.5

0. 结论摘要v3.0 要交付什么)

v3.0 = v2.5 + WebUI + 用户数据上传/下载SFTPGo,形成第一个可对外发布的版本:

  • 用户可以通过 SFTP 上传数据/模型/代码(至少数据),落到 GPFS容器内 /private)并对 Ray worker 可见。
  • 用户可以通过 API/WebUI 提交训练任务,任务读取自己上传的数据。
  • 用户可以下载训练产物checkpoints/logs 等),最小闭环跑通。

1. 范围与原则

1.1 继承 v2.5 的前提(不回退)

  • Stateless Ray Node Poolhead 写 head.jsonworker watchdog 自动 join/自愈。
  • User Managementtoken 鉴权、任务可见性隔离(跨用户 404 不泄漏)。
  • 作业产物隔离Ray job 目录落到 /private/users/<user_id>/jobs/<ray_submission_id>/...
  • API server 短期运行方式:代码在宿主机,挂载到 head 容器,在 head 容器内启动(保持现状)。

1.2 v3.0 新增目标

  1. Data ManagementSFTPGo
    • 提供用户上传/下载入口SFTP 为主)。
    • 数据落到 GPFSdev 环境 NFS/GPFS生产环境 GPFS训练 job 在 worker 容器内可直接读取。
  2. WebUI
    • 用户可视化创建任务、查看队列/状态/日志、查看“数据路径约定”和自己的 SFTP 信息。
    • 目标是 “可用而非豪华”,支持核心工作流。
  3. 权限闭环
    • 用户只能使用自己目录下的数据(/private/users/<user_id>/...)或公共目录(/private/common/...)。
    • 防止用户提交任务读取其他用户的文件路径。

1.3 v3.0 明确不做(留给 v3.5

  • 不做 “自定义 reward function / 自定义 verl 代码 / 多版本 verl 共存”(路线图 v3.5)。
  • 不做复杂 Serving/训推一体(路线图 v3.5)。
  • 不做 IB 网络/拓扑优化(路线图 v3.5)。
  • 不做系统级可观测性平台(路线图 v4.0)。

2. 架构概览

参考 roadmap_v3.0.pngv3.0 的控制面与数据面:

2.1 控制面Control Plane

  • API ServerFastAPI
    • v2.5 的任务队列/调度/重试 + 用户管理能力继续复用
    • 新增:数据管理能力(与 SFTPGo 对接) + WebUI
  • WebUI
    • 通过 API 使用 token 登录
    • 提供任务/日志/数据入口(不直接运行训练)
  • Ray Head状态节点
    • 仍在 head 容器内(或单独节点)
    • job server/dashbaord 提供 job submit/status/logs 能力

2.2 数据面Data Plane

  • GPFS容器内挂载 /private
    • 存放 common 与 users 两大根目录
  • Ray Worker Node无状态
    • 自动连接 head执行训练
    • 读取 /private/users/<user>/... 的数据

2.3 新增组件SFTPGoData Management

  • 作为独立服务运行(容器化优先),后端存储使用 filesystemGPFS 挂载路径)。
  • 用户的 home directory 指向 /private/users/<user_id>(或其子目录)。

3. 存储与目录规范v3.0 统一约定)

3.1 目录层级

统一以容器内 /private 作为根路径dev/prod 对齐):

  • /private/common/:公共资源
    • hf/HF cache
    • datasets/:公共数据集(可选)
    • code/:公共代码(例如公共 verl repo snapshot
    • db/SQLite队列、用户、token
    • logs/API/supervisor/watchdog 日志
  • /private/users/<user_id>/用户空间v3.0 重点)
    • datasets/:用户上传的数据集(推荐)
    • models/:用户保存/上传的本地模型(允许;也用于“把 job 产物移动到长期保存目录”)
    • code/用户上传的代码v3.0 不支持执行;仅存放/下载)
    • jobs/:训练任务产物(已在 v2.5 落地)
    • tmp/:临时文件(可选)

3.2 Jobs Retention两段式3 天移入回收站7 天后永久删除)

v3.0 引入 jobs 目录两段式保留策略

  • 第 1 阶段soft-deletejob 结束后 3 天,将该 job 目录从 jobs/ 移动到用户回收目录
  • 第 2 阶段hard-delete进入回收目录后再过 7 天,从回收目录 永久删除

目录约定(建议):

  • jobs 根目录:/private/users/<user_id>/jobs/<ray_submission_id>/...
  • 回收目录:/private/users/<user_id>/trash/jobs/<ray_submission_id>/...

计时规则:

  • 以 job 进入 terminal 状态SUCCEEDED/FAILED/CANCELED的结束时间为起点
  • “3 天”用于从 jobs/ 移入 trash/jobs/
  • “7 天”用于从 trash/jobs/ 永久删除(即总共最多 10 天窗口)。

用户保留关键产物的方式(无需 keep 标记):

  • 在 “3 天窗口”内把需要长期保存的文件从 jobs/<submission_id>/... 移动/复制models/(例如权重)或 datasets/(例如评估输出数据);
  • 即便已被移动到回收目录,用户仍可在 “7 天窗口”内从 trash/jobs/<submission_id>/... 把需要的文件移到 models/ / datasets/
  • janitor 只管理 jobs/trash/jobs/,不会触碰 models/datasets/

这里的“清理程序”我们称为 janitor

  • 定义:一个后台清理执行器,按固定周期扫描“已结束且已过期”的 job 目录并删除
  • v3.0 目标实现“3 天移入回收站 + 7 天后删除”这一条产品规则(不提供 keep/延长保留标记)

实现建议(按你的偏好):

  • janitor 作为 API server 内置后台线程运行:
    • 优点:天然可访问 SQLite任务状态、结束时间、user_id、ray_submission_id并能把清理结果写回 events 表用于审计
    • 部署更简单:不额外引入 cronjob/独立服务
  • 删除/移动动作建议 直接在 GPFS/NFS 文件系统上操作API server 运行在 head 容器,已挂载 /private
    • 第 1 阶段:os.rename(同文件系统原子移动)把 jobs/<sid> 移到 trash/jobs/<sid>
      • 若跨文件系统(理论上不应发生),则降级为 copy+delete
      • 移动前做严格路径前缀校验(必须在 .../users/<u>/jobs/ 下)。
    • 第 2 阶段:对 trash/jobs/<sid> 执行递归删除(例如 shutil.rmtree),同样做路径前缀校验(必须在 .../users/<u>/trash/jobs/ 下)。
    • 为什么不依赖 SFTPGo APISFTPGo 只是用户访问协议层SFTP/Web目录物理就在同一份文件系统文件系统直连更简单、也不依赖 SFTPGo 在线。
  • 如果你强烈希望“通过 SFTPGo API 删除”:
    • 可以作为可选实现/补充(例如用于统一审计或未来接入配额/策略但不建议作为唯一手段SFTPGo 停机不应阻塞清理)。

3.3 用户在 SFTPGo 内移动/整理文件(确认点)

支持用户在 SFTPGo 中进行“移动/重命名/整理”(例如把权重从 jobs/ 移动到 models/

  • 前提SFTPGo 用户权限允许对其 home 目录进行 rename/mkdir/remove 等操作v3.0 默认可写)。
  • 行为:用户可以把 jobs/ 下某些文件移动到 models/datasets/,用于长期保存权重/评估产物等。
  • 与 retention 的关系:只要文件被移动出 jobs/,就不会被 jobs 清理逻辑删除。

3.4 路径权限规则API 侧校验)

v2.5 约束是 “只允许 /private/common/...”。
v3.0 需要升级为:

  • 允许:
    • /private/common/...
    • /private/users/<current_user_id>/...
  • 禁止:
    • 任何其他绝对路径(例如 /private/users/other/.../etc/...

并把该规则应用到 TaskSpec 的相关字段(至少):

  • train_file / val_file
  • code_path:仍仅允许 /private/common/...v3.0 不支持执行用户 code
  • 本地模型路径字段:允许 /private/users/<me>/models/...确认v3.0 允许)

4. SFTPGo 方案设计Data Management

4.1 运行形态

推荐用容器运行 SFTPGo与 Ray/API 解耦),挂载同一份 /private

  • sftpgo 容器挂载 ../../shared:/private
  • 对外暴露:
    • SFTP 端口(建议 2022
    • WebAdmin/API 端口(建议 8081仅内网或管理员访问

4.1.1 镜像来源(现成 Docker 镜像)

SFTPGo 有现成可用的 Docker 镜像(无需自建):

  • v3.0 推荐优先使用官方/上游发布的 sftpgo 镜像作为运行基座
  • 我们在 v3.0 里不需要定制 SFTPGo 代码,只需要:
    • 正确挂载 GPFS/NFS容器内 /private
    • 配置管理员账号(用于 API server 联动创建/禁用用户、重置密码)
    • 配置每用户 home/chroot

注意:具体镜像名/tag 在不同环境可能有差异(官方/镜像仓库策略会变动)。落地时建议在 argus@h1docker search sftpgo 或由你们内部镜像仓库提供固定版本v3.0 设计只要求“使用现成镜像”,不强依赖某个 tag。

4.1.2 docker-compose 服务草案(示意)

下面给出一个示意(最终以实际镜像名/tag 与你们端口规划为准):

services:
  sftpgo:
    image: sftpgo/sftpgo:latest   # 示例:使用现成镜像
    container_name: argus-sftpgo
    ports:
      - "2022:2022"   # SFTP
      - "8081:8080"   # WebAdmin/API建议仅内网/管理员)
    volumes:
      - ../../shared:/private
      - ../../shared/common/sftpgo:/var/lib/sftpgo   # 持久化 SFTPGo 元数据(可选/建议)
    environment:
      # 管理员账号/密码(示意,具体变量名以镜像文档为准)
      SFTPGO_ADMIN_USERNAME: "admin"
      SFTPGO_ADMIN_PASSWORD: "${SFTPGO_ADMIN_PASSWORD}"

与 v3.0 的配合点:

  • API server 使用 data.sftpgo.admin_api_base + admin 凭据联动创建用户
  • 用户 home/chroot 统一指向 /private/users/<user_id>

4.2 用户隔离

每个用户在 SFTPGo 中的 home dir 绑定到:

  • /private/users/<user_id>chroot用户只能读写自己的目录。

4.3 用户创建与凭据管理(两种实现,建议先做 A

方案 Av3.0 推荐API Server 负责“联动创建 SFTPGo 用户”

  • 在 v2.5 的 POST /api/v2/users 成功后:
    • API server 调用 SFTPGo 管理 API 创建同名用户
    • 设置 home dir = /private/users/<user_id>
    • 设置权限(默认可写;是否只读可配置)
  • 认证方式:
    • v3.0 最小可用:用户名+密码确认v3.0 先 passwordAPI 生成一次性密码,用户首次登录后要求改密)
    • SSH public keyWebUI 允许上传 public keyAPI 写入 SFTPGo

方案 B更强但复杂SFTPGo 外部认证

  • SFTPGo 把认证委托给 API servertoken/SSOSFTP 也走内部 token。
  • 复杂度高,建议 v3.0 不做,放到 v3.5 或更后。

4.4 用户上传/下载体验

用户通过 SFTP 上传:

  • datasets/...(训练数据)
  • models/...(本地模型,可选) 下载:
  • jobs/<ray_submission_id>/...checkpoints/logs

WebUI/文档提供 “路径如何写进 TaskSpec” 的指引。

5. WebUI 方案设计(最小可用)

5.1 目标页面

v3.0 WebUI 采用“多子页面 + 侧边导航栏”而不是把所有功能挤到单页:

  • 原因信息密度更可控后续可扩展v3.5+)且不会把一个页面做成“巨型表单/巨型列表”。
  • 实现仍保持轻量:服务端渲染(或静态 HTML + 少量 JS不引入复杂前端工程。

信息架构IA建议如下

  1. 登录页/ui/login
    • 用户粘贴 token管理员发放浏览器保存localStorage/sessionStorage
    • 提供“退出登录/清空 token”
  2. 任务列表页/ui/tasks
    • 默认列表:最近 N 条任务(按 created_at 倒序)
    • 支持过滤workload、stateQUEUED/RUNNING/SUCCEEDED/FAILED/CANCELED、时间范围
    • 支持快捷操作:进入详情、取消任务
  3. 新建任务页/ui/tasks/new
    • 两种模式(二选一,均可实现):
      • YAML 直接提交:上传/粘贴 TaskSpec YAML最省开发
      • 表单生成 YAML:选择 workload填写核心字段train/val/model/nnodes/gpus生成 YAML 预览后提交
    • 提交后跳转到任务详情页
  4. 任务详情页/ui/tasks/{task_id}
    • 顶部task_id、workload、state、created_at、updated_at、error_summary
    • Attempt 卡片latest attempt_no、ray_submission_id、ray_status、start/end
    • 操作区:取消任务(若非 terminal、刷新状态、复制路径/ID
    • 链接到日志页与产物提示SFTP 路径)
  5. 任务日志页/ui/tasks/{task_id}/logs
    • 默认 tail=2000可选 200/1000/5000
    • 提供“自动刷新(每 3~5 秒)”开关(简单轮询即可)
  6. 数据页/ui/data
    • 显示 SFTP 连接信息host/port/username
    • 显示用户目录约定:
      • home/private/users/<user_id>
      • datasets/private/users/<user_id>/datasets
      • models/private/users/<user_id>/models
      • jobs/private/users/<user_id>/jobs
      • trash/jobs/private/users/<user_id>/trash/jobs
    • 明确 retentionjobs 结束后 3 天移入回收站,回收站 7 天后删除;重要文件请移到 models/datasets/
  7. (仅管理员可见)用户管理页/ui/admin/users,可选但很有价值)
    • 创建用户、禁用用户、签发 token、重置 SFTP 密码(方案 A

5.2 页面组织与导航(建议)

侧边栏导航(普通用户):

  • Tasks列表
  • New Task新建
  • DataSFTP/目录说明)

管理员侧边栏额外增加:

  • Admin / Users

5.3 大致示意图wireframe

下面是一个粗略示意(非最终 UI仅表达信息结构与布局

┌──────────────────────────────────────────────────────────────────────┐
│ Argus MVP v3.0                                      [user: alice]    │
├───────────────┬──────────────────────────────────────────────────────┤
│  Side Nav     │  /ui/tasks                                            │
│               │                                                      │
│  • Tasks      │  [Filter] workload=all  state=all  [Search task_id]  │
│  • New Task   │                                                      │
│  • Data       │  Task List                                           │
│  • Admin(*)   │  ┌────────────────────────────────────────────────┐  │
│               │  │ task_id                 workload  state   ...   │  │
│               │  │ mvp2-alice-ppo-...      ppo       RUNNING ...   │  │
│               │  │ mvp2-alice-sft-...      sft       SUCCEEDED...  │  │
│               │  └────────────────────────────────────────────────┘  │
│               │  [View] [Cancel]                                     │
└───────────────┴──────────────────────────────────────────────────────┘

任务详情页(示意):

┌──────────────────────────────────────────────────────────────────────┐
│ /ui/tasks/{task_id}                                                   │
├──────────────────────────────────────────────────────────────────────┤
│ task_id: mvp2-alice-ppo-...   state: RUNNING   workload: ppo          │
│ created_at: ...               updated_at: ...                         │
│ error_summary: (empty)                                                │
│                                                                        │
│ latest_attempt: a01  ray_submission_id: ...--a01  ray_status: RUNNING  │
│ [Open Logs] [Cancel Task] [Refresh]                                   │
│                                                                        │
│ Artifacts (SFTP paths):                                                │
│   jobs/:   /private/users/alice/jobs/<ray_submission_id>/              │
│   trash/:  /private/users/alice/trash/jobs/<ray_submission_id>/        │
│   tip: move important files to /private/users/alice/models/            │
└──────────────────────────────────────────────────────────────────────┘

5.2 技术取舍(建议:不引入 Node 构建)

为了降低部署复杂度,建议 v3.0 WebUI 以 “服务端渲染 + 少量 JS/HTMX” 或 “纯静态 HTML+fetch” 实现:

  • 由 API server 提供静态资源FastAPI StaticFiles
  • 页面调用同源 API避免跨域与复杂前端构建链

6. API 扩展设计(概览)

v3.0 可以保持 /api/v2/... 不变,增量加:

  • SFTPGo 集成管理端点(管理员):
    • 创建/禁用用户时联动 SFTPGo
    • 重置 SFTP 密码 / 更新 SSH key
  • 用户数据端点(可选,最小化):
    • /api/v2/me:返回 user_id、SFTP 信息host/port/home
    • /api/v2/files:仅用于浏览/下载(上传仍走 SFTP

详细见 specs/mvp/v3.0/v3.0_api.md

7. 配置与部署v3.0 新增项)

configs/dev.yaml 基础上扩展一组 data 配置(示意):

data:
  shared_root: "/private"              # 通常与 ray.shared_root 一致
  user_root: "/private/users"          # 用户空间根目录
  allow_common_prefix: "/private/common/"
  allow_user_prefix_template: "/private/users/{user_id}/"

  sftpgo:
    enabled: true
    host: "127.0.0.1"
    sftp_port: 2022
    admin_api_base: "http://127.0.0.1:8081/api/v2"
    admin_user: "admin"
    admin_password_env: "SFTPGO_ADMIN_PASSWORD"   # 仅 head 容器内可读

  retention:
    jobs_trash_after_days: 3
    jobs_purge_after_days: 7
    trash_root_template: "/private/users/{user_id}/trash/jobs"
    janitor_interval_s: 3600     # 每小时扫一次(可配置)

8. 风险点与对策

  1. 路径逃逸/越权读取
    • 必须在 API 提交任务时校验路径前缀
    • SFTPGo 必须 chroot 到用户 home
  2. 大文件上传稳定性
    • 优先用 SFTP断点续传/可靠性更好)
  3. 用户 token 与 SFTP 凭据的生命周期
    • token 走 v2.5 SQLite
    • SFTP 凭据建议独立(密码/SSH key并提供 reset 流程
  4. GPFS/NFS 权限
    • 确保 /private/users/<user> 目录权限可被 SFTPGo 写入且 worker 可读

9. 已确认结论(来自你的反馈)

  1. 允许用户上传并在训练时使用自定义数据集:允许(/private/users/<u>/datasets/...)。
  2. 允许用户上传并在训练时使用本地模型路径:允许(/private/users/<u>/models/...)。
  3. v3.0 不允许执行用户自定义代码(不注入 PYTHONPATH 作为可执行 code path
  4. SFTPGo 认证方式v3.0 先 password。
  5. WebUI按“简单最小必要功能”做token 粘贴登录优先)。

10. 待确认问题(需要你给结论)

已确认jobs 清理执行主体v3.0 采用 API server 内置 janitor 后台线程