cleaning code

This commit is contained in:
2026-01-13 10:46:43 +08:00
parent ac9c80ed8c
commit 4a5afb7ed7
91 changed files with 1 additions and 13294 deletions

File diff suppressed because it is too large Load Diff

BIN
doc/assets/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

BIN
doc/assets/layout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

BIN
doc/assets/networking.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

BIN
doc/assets/scheduling.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

BIN
doc/assets/task_submit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

View File

@@ -1,279 +0,0 @@
# AI Infra 训练平台建设方案
## 1. 愿景与目标
### 1.1 愿景
构建一套**端到端的智能化AI训练平台**,将分散的训练框架、资源调度、监控运维、数据管理能力整合为统一的标准化流水线,让大模型训练算法团队**专注于模型创新而非基础设施运维**,同时与现有运维智能体深度协同,实现训练任务的智能化运维闭环。
### 1.2 核心目标
| 目标维度 | 描述 |
|---------|------|
| **效率提升** | 训练任务从准备到启动时间缩短 70%,故障恢复时间缩短 50% |
| **标准化** | 建立统一的训练流程规范,消除"人人一套环境"的混乱局面 |
| **可观测性** | 全链路监控覆盖,训练状态、资源利用、异常事件一目了然 |
| **智能运维** | 与运维智能体对接,实现断训自动分析、故障智能诊断 |
---
## 2. 整体架构概览
```
┌─────────────────────────────────────────────────────────────────────┐
│ 用户交互层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Web 前端 │ │ CLI 工具 │ │ API 接口 │ │
│ │ (任务提交) │ │ (高级用户) │ │ (自动化集成) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────────┐
│ 平台服务层 │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ 任务调度 │ │ 数据管理 │ │ 模型管理 │ │
│ │ (SkyPilot) │ │(schema/dataset)│ │ (版本/产物) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ 镜像管理 │ │ 指标追踪 │ │ 日志中心 │ │
│ │(Local Registry)│ │ (W&B) │ │ (集中采集) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────────┐
│ 智能运维层 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 运维智能体对接 │ │
│ │ • 断训自动分析 • 故障根因定位 • 资源利用率优化建议 │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────────┐
│ 基础设施层 │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Kubernetes │ │ GPU 集群 │ │ 分布式存储 │ │
│ │ (容器编排) │ │ H20/A6000/H100│ │ (JuiceFS) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. 用户故事
### 3.1 算法工程师视角
> **作为**一名算法工程师,
> **我希望**通过简单的界面配置就能提交一个多节点 RLHF 训练任务,
> **以便于**我可以专注于模型和数据本身,而不是花大量时间在环境配置和资源协调上。
**验收标准:**
- [ ] 在 Web 界面上选择数据集、模型、训练配置
- [ ] 一键提交后,系统自动完成资源分配、镜像拉取、任务启动
- [ ] 实时查看训练进度曲线和关键指标
---
> **作为**一名算法工程师,
> **我希望**训练中断时能快速定位问题原因,
> **以便于**减少排查时间,尽快恢复训练。
**验收标准:**
- [ ] 系统自动检测训练中断事件
- [ ] 智能体自动分析中断原因(OOM、网络故障、硬件异常等)
- [ ] 提供可操作的恢复建议
---
> **作为**一名算法工程师,
> **我希望**启动一个 Notebook 环境调试代码.
> **以便于**小规模试跑训练,测试训练数据集、调整模型参数
**验收标准:**
- [ ] Notebook容器启动速度
- [ ] 开发容器内置依赖包完善度,按照新包
---
### 3.2 团队负责人视角
> **作为**团队负责人,
> **我希望**能够看到所有训练任务的整体资源利用情况,
> **以便于**合理规划算力资源,识别资源浪费。
**验收标准:**
- [ ] 仪表盘展示各集群 GPU 利用率趋势
- [ ] 任务队列可视化,等待/运行/完成状态一目了然
- [ ] 资源使用报表按项目/用户统计
---
### 3.3 运维工程师视角
> **作为**运维工程师,
> **我希望**训练任务的监控数据能自动接入现有运维系统,
> **以便于**统一管理,减少割裂的监控工具。
**验收标准:**
- [ ] 训练任务指标自动推送到运维智能体
- [ ] 异常告警自动触发智能体分析流程
- [ ] 与现有运维系统数据互通
---
## 4. 里程碑规划
### 里程碑总览
```
M1 M2 M3 M4
│ │ │ │
────●──────────────────●──────────────────●──────────────────●────────▶
│ │ │ │
基础设施就绪 训练流水线上线 监控运维闭环 智能化运维
```
---
### M1: 基础设施就绪
**目标:** 完成底层平台搭建,具备运行训练任务的基础能力
| 交付物 | 说明 |
|-------|------|
| K8S 集群 | H20 集群上部署 Kubernetes,支持 GPU 调度 |
| 本地 Registry | 内网镜像仓库,解决镜像拉取问题 |
| JuiceFS/MinIO | 分布式存储,数据集和模型 checkpoint 持久化 |
| 基础镜像 | veRL 训练镜像,预置常用依赖 |
**关键验证点:**
- 能够手动在 K8S 上启动单节点训练任务
- 数据从 JuiceFS 正常读写
- 镜像从本地 Registry 正常拉取
- 引入 Volcano 或 Kueue,并配置 Gang Scheduling 策略,实现All-or-Nothing 的资源分配
- 确认JuiceFS 的本地 SSD 缓存策略,在其中一台机器部署MiniIO单节点,另外两台机器上部署JuiceFS client
- 网络通信支持 RoCE/InfiniBand
- Notebook 交互式开发环境
---
### M2: 训练流水线上线
**目标:** 用户可通过前端提交和管理训练任务
| 交付物 | 说明 |
|-------|------|
| SkyPilot 集成 | 任务调度与资源编排 |
| W&B 本地服务 | 训练指标追踪与可视化 |
| 任务管理前端 | 数据上传、任务提交、进度查看、日志查看 |
| 数据管理模块 | 支持从 HuggingFace 链接或 FTP 导入数据集 |
**关键验证点:**
- 端到端完成一次多节点 SFT 训练
- 通过前端提交任务,查看 W&B 训练曲线
- 训练日志完整保存并可查询
- 多租户、项目制配额管理功能
---
### M3: 监控运维闭环
**目标:** 实现任务全生命周期监控,与运维智能体初步对接
| 交付物 | 说明 |
|-------|------|
| 资源监控 | GPU 利用率、显存、网络带宽实时采集 |
| 日志采集 | 训练日志集中存储,支持检索 |
| 智能体对接 | 断训事件自动推送,触发智能体分析 |
| 告警机制 | 异常状态(OOM、任务卡死等)自动告警 |
**关键验证点:**
- 训练任务异常时,5 分钟内收到告警
- 断训事件自动生成分析报告
- Grafana 仪表盘展示集群整体健康状态
- sidecar方式部署 DCGM Exporter 来获取细粒度指标,自动采集到Prometheus
- 断训时“保留现场”机制,供人工/智能体排查介入
---
### M4: 智能化运维
**目标:** 深度整合运维智能体,实现智能调度与自愈
| 交付物 | 说明 |
|-------|------|
| 故障自愈 | 常见故障自动处理(如重新调度到健康节点) |
| 智能调度 | 基于历史数据优化任务资源分配 |
| 根因分析 | 复杂故障场景的深度分析能力 |
| 容量预测 | 基于任务趋势预测算力需求 |
---
## 5. 约束与风险
### 5.1 已知约束
| 约束项 | 影响 | 应对策略 |
|-------|------|---------|
| **内网环境** | 无法直接访问HF/Dockerhub/Github资源(模型、数据集) | 本地 Registry + 数据导入工具 |
| **算力平台限制** | 现有平台调度能力有限 | 引入 SkyPilot 作为上层调度 |
| **数据持久化** | 需要可靠的分布式存储 | JuiceFS + MinIO 方案 |
### 5.2 潜在风险
| 风险 | 可能性 | 影响 | 缓解措施 |
|-----|-------|------|---------|
| K8S 与现有系统集成复杂 | 中 | 高 | 先在 H20 集群小范围验证 |
| 智能体接口适配工作量大 | 中 | 中 | 早期明确接口规范,持续对齐 |
| 用户习惯迁移阻力 | 低 | 中 | 渐进式推广,保留手动模式 |
---
## 6. 资源与依赖
### 6.1 硬件资源
| 集群 | 配置 | 用途 |
|-----|------|------|
| H20 集群 | 2 节点 × 8 卡 = 16 卡 | 主力训练集群,首期部署目标 |
| A6000 集群 | 2 节点 × 4 卡 = 8 卡 | 开发测试、小规模实验 |
| H100 集群 | 多节点 | 目前仅提供容器方式,不确定能否提供KubeConfig接入,大规模训练 |
### 6.2 外部依赖
| 依赖项 | 状态 | 负责方 |
|-------|------|-------|
| yd运维智能体接口 | 已有基础 | |
| argus运维系统 | 已有 | 运维团队 |
---
## 7. 成功标准
### 阶段一完成标准(M1 + M2)
- [ ] 算法工程师可通过 Web 界面完成 SFT/RLHF 训练全流程
- [ ] 任务提交到开始训练时间 < 10 分钟
- [ ] 训练指标实时可视化,延迟 < 1 分钟
- [ ] 至少完成 3 个实际项目的验证使用
### 阶段二完成标准(M3 + M4)
- [ ] 断训事件 100% 自动检测并推送智能体
- [ ] 常见故障(OOM、节点失联)自动生成分析报告
- [ ] GPU 整体利用率提升 20%(通过更好的调度)
- [ ] 平均故障恢复时间(MTTR)缩短 50%
---
## 附录:关键技术选型
| 领域 | 选型 | 选型理由 |
|-----|------|---------|
| 容器编排 | Kubernetes | 业界标准,生态成熟 |
| 任务调度 | SkyPilot | 专为 ML 场景设计,支持多集群 |
| 分布式存储 | JuiceFS + MinIO | 兼容 POSIX,适合训练场景 |
| 实验追踪 | W&B (自部署) | 功能完善,团队已有使用经验 |
| 镜像仓库 | Harbor / Registry | 内网环境必需 |
| 训练框架 | veRL / Megatron | 支持 RLHF,与现有工作对齐 |

115
doc/hl_design_v2.md Normal file
View File

@@ -0,0 +1,115 @@
# 基于Ray Cluster的overlay计算集群方案
**“中心化控制平面 + 分布式计算平面”** 的架构设计。系统基于 **Ray Cluster** 构建应用层调度器,利用 **SSH** 作为带外(Out-of-Band)节点发现机制,并在底层通过 **NFS** 实现数据一致性。
### 0\. 算力平台资源
![](./assets/layout.png)
算力平台上可以申请单节点容器(有无GPU均可)以及分布式任务下多节点容器。
初步设想,在同一个用户账户下预先申请一批分布式任务节点以及一批不同规格(GPU数量)的计算容器,
并将这些计算容器全部纳管在一个CPU容器中的服务程序下,提供统一的访问入口,供云桌面多用户使用。
以下是该方案的**技术架构规范说明**:
### 1\. 架构拓扑 (Architectural Topology)
![arch.png](./assets/arch.png)
系统采用 **Hub-and-Spoke (星型)** 拓扑结构,逻辑上划分为控制平面(Control Plane)和计算平面(Data Plane)。
* **控制平面 (Control Plane / Head Node)**
* 部署于 **CPU 容器**。
* 承载 **Ray GCS (Global Control Store)**:负责集群元数据管理、任务调度表维护、Actor 寻址。
* 承载 **API Gateway (FastAPI)**:对外暴露 RESTful 接口,封装 Job Submission API。
* 承载 **Node Provisioner (Bootstrap Daemon)**:负责节点生命周期管理的守护进程。
* **计算平面 (Data Plane / Worker Nodes)**
* 部署于 **GPU 容器池**。
* 运行 **Raylet**:负责本地资源(GPU/CPU/RAM)管理和 Task 执行。
* 集成 **Object Store (Plasma)**:负责节点间共享内存对象传输。
* **IB Interconnect**:配置 NCCL 环境变量,绕过 TCP 协议栈,直接利用 InfiniBand 进行 GPU 显存直连通信(RDMA)。
* **存储平面 (Storage Plane)**
* **NFS Protocol**:全节点挂载 `/mnt/shared`。
* **Artifacts Repository**:统一存储 Codebase、Datasets、Checkpoints、Logs。
### 2\. 核心机制设计 (Core Mechanisms)
#### 2.1 节点发现与纳管 (Node Discovery & Bootstrapping)
![](./assets/node_bootstrap.png)
采用 **SSH-based Side-channel Injection (SSH 侧信道注入)** 机制绕过 K8s 控制面限制。
* **触发机制**:Provisioner 接收目标节点 IP 及凭证。
* **握手流程**:
1. Provisioner 建立 SSH 连接 (TCP/22)。
2. 注入 **Ray Runtime Config**,执行 `ray start --address=<HEAD_VIP>:6379`。
3. 注入 **Custom Resources** (如 `{"node_id_xyz": 1}`) 用于后续的亲和性调度。
* **状态同步**:Raylet 启动后通过 TCP 回连 GCS,建立长连接心跳。
#### 2.2 任务调度策略 (Scheduling Strategy)
![](./assets/scheduling.png)
系统针对不同负载类型,采用差异化的调度原语:
* **Type A: SFT Workloads (Job-Level Scheduling)**
* **调度模式**:**Driver-on-Worker**。
* **资源原语**:使用 Ray Job Entrypoint 资源约束 (`entrypoint_num_gpus=8`)。
* **调度逻辑**:
1. API Server 接收请求,提交 Job 到 GCS。
2. GCS 调度器执行 **Resource Matching**,寻找满足 GPU 数量及 Custom Resource (节点亲和性) 的 Worker。
3. 将 Shell Command (`torchrun`) 下发至目标 Worker 的 Raylet 执行。
* **进程模型**:`torchrun` 作为子进程运行,独占节点 GPU。
* **Type B: RL Workloads (Actor-Level Scheduling)**
* **调度模式**:**Driver-on-Head** (或 Driver-on-CPU-Worker)。
* **资源原语**:使用 Ray **Placement Groups**。
* **调度逻辑**:
1. Driver 进程在 Head 节点启动。
2. Driver 申请 Placement Group (例如:`{"CPU": 1}` for Controller, `{"GPU": 1} * N` for Rollout Workers)。
3. GCS 将不同的 Actors 实例化到集群内的各个 Worker 节点。
* **通信模型**:Controller 与 Workers 通过 gRPC (Ray Protocol) 交换控制指令;Workers 之间通过 NCCL (IB) 交换 Tensor 数据。
#### 2.3 网络通信规范 (Networking Specification)
![](./assets/networking.png)
* **Control Plane Traffic (TCP/IP)**
* 范围:Head \<-\> Worker,Worker \<-\> Worker (非 Tensor 数据)。
* 端口:6379 (Redis/GCS), 8265 (Dashboard), 10000-65535 (Ephemeral Ports)。
* 要求:容器间 Overlay 网络互通。
* **Data Plane Traffic (RDMA/IB)**
* 范围:Worker \<-\> Worker (DDP/FSDP 通信)。
* 协议:NCCL over IB Verbs。
* 配置:通过 `runtime_env` 注入 `NCCL_IB_HCA` 等环境变量,确保训练流量卸载至 IB 网卡,不占用 Overlay 网络带宽。
### 3\. 工作流序列 (Workflow Sequence)
#### 3.1 节点上线流程
![](./assets/node_onboarding.png)
#### 3.2 任务提交流程 (以 SFT 为例)
![](./assets/task_submit.png)
### 4\. 数据持久化与隔离 (Persistence & Isolation)
* **Runtime Environment Isolation**:
* 利用 Ray 的 `runtime_env` 特性,在 Job 级别隔离 Python 依赖 (pip packages) 和环境变量。
* 支持为每个 Job 指定独立的 `working_dir` (指向 NFS 上的特定版本代码库)。
* **Log Persistence**:
* Stdout/Stderr 重定向至 NFS 挂载路径 (`/mnt/shared/logs/{job_id}/`),实现无状态容器的日志持久化。
### 5\. 总结
该架构通过**应用层集群化 (Application-Layer Clustering)** 技术,在异构且受限的 K8s 容器环境之上,构建了一套**逻辑上的 HPC 集群**。它解耦了底层基础设施管理(由 SSH 负责)与上层计算任务调度(由 Ray 负责),是处理 Verl/SkyRL 此类强耦合分布式应用的标准化解决方案。

View File

@@ -1,18 +0,0 @@
目标:设计一套AI任务调度和管理系统
环境:在K8S集群(商业化封装的算力平台)上运行若干个GPU容器和CPU容器
约束:CPU容器可以暴露端口供desktop访问,CPU容器可以通过ssh访问GPU容器,容器的生命周期在单独的算力平台控制台上管理;所有容器
有共享的NFS文件系统
目标:在CPU容器上部署一个web server 向desktop提供服务,后端运行一个类似skypilot的程序,能够注册和管理GPU容器实例进来。
- 用户在desktop上通过网站提交执行模型训练的任务,任务管理程序会将任务加入调度队列,等资源池有空闲资源的时候,就会调度任务到对应的GPU节点上执行任务。任务有单节点任务,和多节点任务两类,预先的节点也提前配置好了,多节点任务的容器之间是专门
走的IB网络。
任务:完成技术选型,主要是普通的skypilot不支持现成的ssh节点管理。你调研是否有节点满足需求的任务调度管理方案。
补充:运行的任务一般是 verl / skyRL 强化学习训练框架,以及llamafactory 框架等。GPU节点容器假设是已经预先安装好了对应的环境依赖,任务管理器只需要调度和查看任务执行情况,还有监控任务是否健康,有没有任务中断。
未来规划:
- 统一数据集管理,包括模型库、数据集库
- 统一日志采集&规范
- 统一容器GPU/CPU指标采集
- 统一的 weight & bias 指标服务器
结构图:见附件

View File

@@ -1,315 +0,0 @@
# 关于MinIO + JuiceFS 在H20部署
这是一个架构设计的关键决策点。在 **H20 节点运行 K3s** 的前提下,我建议采取 **“存储组件独立部署(Outside),客户端插件化接入(Inside)”** 的混合策略。
简单来说:**MinIO 和 Redis 跑在 K3s 外面(用 Docker),JuiceFS Client 通过 CSI 跑在 K3s 里面。**
以下是详细的架构拆解和理由:
### 1\. 架构图解
```mermaid
graph TD
subgraph "物理层 / Host OS (H20 Node)"
NVMe[NVMe SSD (物理盘)]
end
subgraph "K3s 集群 (容器层)"
Pod[训练任务 Pod]
CSI[JuiceFS CSI Driver (DaemonSet)]
Pod -- "PVC 挂载" --> CSI
end
subgraph "独立 Docker 容器 (非 K3s)"
Redis[Redis 容器]
MinIO[MinIO 容器]
end
%% 关键数据流
CSI -- "1. 读写缓存" --> NVMe
CSI -- "2. 网络 IO" --> MinIO
CSI -- "3. 元数据 IO" --> Redis
%% 避免环路
MinIO -. "数据持久化" .- NVMe
```
-----
### 2\. 组件部署位置详解
#### A. MinIO & Redis:建议 **独立于 K3s 部署 (Outside)**
**方式**:直接在宿主机(Host OS)上使用 `docker run` 或 `docker-compose` 启动,或者使用 `systemd` 管理。
**理由**:
1. **爆炸半径隔离(最重要)**:AI 实验初期,K3s 集群可能会因为 CNI 网络插件配置错误、Device Plugin 崩溃、或者各种误操作导致集群不可用(Crash)。如果存储后端(MinIO)跑在 K3s 里,K3s 一挂,你的数据就“锁”在里面了,连日志都拷不出来。
2. **资源竞争保护**:K8s 的调度器虽然有 QoS,但在只有 2 个节点的情况下,H20 的高负载很容易导致控制面不稳。把 MinIO 独立出来,保证存储服务的 CPU/内存资源不受 K3s 内部 Pod 挤压。
3. **网络直通**:宿主机直接部署 MinIO,使用的是 `host` 网络,少了一层 K8s Service/Ingress 转发,对于大带宽吞吐稍微有一点点性能优势。
#### B. JuiceFS Client:建议 **集成在 K3s 内部 (Inside)**
**方式**:使用 **JuiceFS CSI Driver**。
**理由**:
1. **符合“平台化”愿景**:你的目标是做一个 "AI Infra 平台"。对于上层用户(算法工程师),他们不应该关心宿主机挂载了什么目录。他们提交的 YAML 只需要写:
```yaml
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-juicefs
```
这是标准的云原生体验。
2. **权限与隔离**:CSI Driver 可以更好地处理容器内的挂载点权限问题。如果手动在宿主机 `mount` 然后用 `hostPath` 映射进容器,经常会遇到 `Permission Denied` 或者 `root` 用户归属问题,非常头疼。
3. **自动缓存管理**:CSI Driver 可以通过配置 `StorageClass`,自动帮你处理缓存路径的挂载和清理。
-----
### 3\. 实操配置指南 (关键点)
既然你只有两台 H20 并且要上 K3s,以下是落地的关键配置:
#### 第一步:在宿主机启动 MinIO 和 Redis (后端)
不要用 Helm,直接写一个 `docker-compose.yml` 放在 `/opt/ai-infra/` 下运行:
```yaml
version: '3'
services:
minio:
image: minio/minio
network_mode: "host" # 直接用宿主机网络,性能最好
volumes:
- /mnt/data1/minio_data:/data # 挂载到大容量HDD或SATA SSD
command: server /data --console-address ":9001"
redis:
image: redis:7
network_mode: "host"
volumes:
- /mnt/data1/redis_data:/data
command: redis-server --appendonly yes
```
#### 第二步:在 K3s 中安装 JuiceFS CSI Driver (前端)
1. **安装 CSI Driver**:
```bash
helm repo add juicefs https://juicedata.github.io/charts/
helm install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system
```
2. **创建 Secret (连接信息)**:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: juicefs-sc-secret
namespace: default
type: Opaque
stringData:
name: "myjfs"
metaurl: "redis://<宿主机IP>:6379/1" # 注意这里填宿主机内网IP
storage: "minio"
bucket: "http://<宿主机IP>:9000/mybucket"
access-key: "minioadmin"
secret-key: "minioadmin"
```
3. **创建 StorageClass (核心中的核心)**:
这里要配置**本地缓存**,让 JuiceFS 能够利用 H20 的 NVMe。
```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: juicefs-sc
provisioner: csi.juicedata.com
parameters:
csi.storage.k8s.io/node-publish-secret-name: juicefs-sc-secret
csi.storage.k8s.io/node-publish-secret-namespace: default
csi.storage.k8s.io/provisioner-secret-name: juicefs-sc-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
# === 关键性能参数 ===
cache-dir: /mnt/nvme0/juicefs-cache # H20 宿主机上的 NVMe 路径
cache-size: "2048000" # 2TB 缓存上限
buffer-size: "512" # 写缓冲
prefetch: "2" # 预读并发度
```
### 4\. 备选方案:如果 CSI 搞不定怎么办?
如果 M1 阶段你发现 CSI Driver 调试太麻烦(有时候 K3s 的路径和标准 K8s 不一样,导致 CSI 挂载失败),可以退回到 **“Host Mount + HostPath”** 模式:
1. **Outside**: 在宿主机直接运行 `juicefs mount ... /mnt/ai-data`。
2. **Inside**: 在 Pod YAML 里直接映射:
```yaml
volumes:
- name: data
hostPath:
path: /mnt/ai-data
type: Directory
```
**结论:**
优先尝试 **CSI Driver** 方案,这才是正规军的做法,能为你的“平台化”愿景打下基础。MinIO/Redis 请务必保持独立,不要让 K3s 的波动影响到底层数据安全。
----------------
# 关于Minio扩容
这是一个非常关键的运维问题。
首先要泼一盆冷水(也是为了避坑):**MinIO 不支持从“单机模式(Standalone)”无缝平滑扩容到“分布式模式(Distributed)”**。
* **单机模式**下,MinIO 是直接把文件存成普通文件。
* **分布式模式**下,MinIO 会启用**纠删码(Erasure Coding)**,把文件切片打散存储。
底层数据结构完全不同,因此你**不能**简单地把新节点加入旧集群。你必须通过\*\*“建立新集群 -\> 数据迁移 -\> 切换流量”\*\*的方式来完成。
鉴于你使用了 JuiceFS,这个迁移过程其实比纯 MinIO 迁移要灵活得多。以下是针对你 H20/K3s 环境的最佳实战方案:
-----
### 方案概览:蓝绿部署迁移法
我们不修改旧的 MinIO,而是搭建一个新的 3 节点集群,同步数据,然后改一下 K8s Secret 指向新集群。
#### 前置条件
假设你现有的环境是:
* **Old MinIO**: 跑在 Node A (192.168.1.10)
* **New Target**: 准备在 Node A, Node B, Node C 上跑 3 节点分布式 MinIO。
-----
### 第一步:搭建全新的 3 节点 MinIO 集群
由于旧的 MinIO 还在通过 `host` 网络运行(占用 9000 端口),新集群如果不关掉旧的,需要用**不同端口**(比如 9100)或者部署在不同机器上。
假设你新增了机器,或者错开端口。以下是 3 节点分布式 MinIO 的 `docker-compose.yml` 示例(需要在三台机器上都运行):
```yaml
version: '3'
services:
minio-distributed:
image: minio/minio
network_mode: "host"
hostname: "node1" # 另外两台改为 node2, node3
# 关键:分布式启动命令,必须列出所有节点
command: server http://192.168.1.10:9100/data http://192.168.1.11:9100/data http://192.168.1.12:9100/data --console-address ":9101"
volumes:
- /mnt/data_new:/data # 挂载新的数据盘(或者旧盘的新目录)
environment:
MINIO_ROOT_USER: "admin"
MINIO_ROOT_PASSWORD: "strongpassword"
```
*注意:3 节点 MinIO 允许挂掉 1 台机器而不丢失数据。*
-----
### 第二步:数据迁移 (两种路径)
鉴于你用的是 JuiceFS,这里有**两条路**可选:
#### 路径 A:底座迁移(推荐,速度快,原汁原味)
直接搬运 MinIO 里的对象块(Block)。因为 JuiceFS 把数据切成了固定的 Block 存在 MinIO 里,我们只需要把这些 Block 从旧 MinIO 搬到新 MinIO,**不需要经过 JuiceFS 客户端**。
1. **安装 `mc` (MinIO Client)** 命令行工具。
2. **配置别名**:
```bash
mc alias set oldm http://192.168.1.10:9000 minioadmin minioadmin
mc alias set newm http://192.168.1.10:9100 admin strongpassword
```
3. **全量镜像 (Mirror)**:
```bash
# 创建新桶
mc mb newm/mybucket
# 开始同步数据 (将旧桶数据镜像到新桶)
# --watch 参数可以持续监听增量数据,适合不停机迁移
mc mirror --watch oldm/mybucket newm/mybucket
```
#### 路径 B:JuiceFS 层面迁移(适合要换云厂商/存储类型)
如果你想顺便整理数据碎片,或者从 MinIO 迁移到 阿里云 OSS,可以用这个。但在你的场景下,路径 A 更快。
* 命令:`juicefs sync minio://... minio://...` (不推荐,因为需要解密再加密,消耗 CPU)。
-----
### 第三步:停机切换 (Cutover)
为了保证 100% 数据一致性,建议申请一个短时间的维护窗口(10-20分钟)。
1. **停止训练任务**:Scale down 所有的 Training Job。
2. **停止旧 MinIO 写入**:
* 确保 `mc mirror` 已经追平了数据(没有 pending)。
* 你可以把旧 MinIO 设为只读,或者直接停止旧容器。
3. **最后一次 Sync**:
* 运行 `mc mirror --overwrite` 确保最后一点差异也同步了。
4. **修改 K8s Secret**:
* 这是 JuiceFS 的魔力所在。你**不需要**重新格式化 JuiceFS,也**不需要**修改元数据引擎(Redis)。你只需要告诉 JuiceFS:“底下的对象存储换地方了”。
* 编辑 K8s 里的 Secret:
<!-- end list -->
```bash
kubectl edit secret juicefs-sc-secret
```
* 修改 `bucket` 和 `access-key/secret-key`:
<!-- end list -->
```yaml
stringData:
# Redis 配置保持不变!元数据还在那里
metaurl: "redis://192.168.1.10:6379/1"
# 修改 bucket 地址为新集群地址
# 注意:MinIO 分布式集群通常前面会加一个 Nginx 做负载均衡
# 或者你可以填任意一个节点的 IP (MinIO 会自动转发)
bucket: "http://192.168.1.10:9100/mybucket"
access-key: "admin"
secret-key: "strongpassword"
```
5. **重启 CSI Driver**:
* 删除 JuiceFS CSI 的 Pod,让它们重建并加载新的 Secret。
* 删除使用该 PVC 的 Pod。
-----
### 第四步:验证与回收
1. **验证**:
* 启动一个测试 Pod,挂载 PVC。
* `ls` 一下目录,确认文件都在。
* `cat` 一个文件,确认能读(JuiceFS 会去新 MinIO 拿数据块)。
2. **回收**:
* 确认一切正常运行几天后。
* 下线旧的单节点 MinIO 容器。
* 释放旧的磁盘空间。
### 专家建议 (Pro Tips)
1. **负载均衡 (Load Balancer)**:
* 到了 3 节点分布式阶段,建议在 3 台 MinIO 前面架设一个 **Nginx** 或者 **HAProxy**。
* 这样 JuiceFS Client 连接的是 `http://nginx:9000`,Nginx 轮询转发给后端 3 台 MinIO。
* **好处**:如果某台 MinIO 挂了,Nginx 自动剔除,训练任务完全无感。如果直连某台 IP,那台挂了训练就断了。
2. **元数据备份**:
* 在做这一切之前,**务必备份 Redis 的 dump.rdb**。
* 只要 Redis 在,JuiceFS 的文件结构就在。对象存储里的数据块丢了还能通过文件名找回来(虽然内容坏了),但 Redis 丢了,对象存储里那一堆 `chunk-xxx` 的文件就是一堆毫无意义的二进制垃圾,神仙难救。
3. **拓扑限制**:
* MinIO 扩容通常是“倍增”或者“对等扩容”。比如 4 节点扩容,通常是再加 4 节点(变成 2 个 Server Pool)。
* 所以,规划 3 节点时,最好磁盘大小一致,网络环境一致。

11966
doc/sw_arch.excalidraw Normal file

File diff suppressed because it is too large Load Diff