Files

287 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构设计
> *“代码定义了它如何工作,架构定义了它如何活着。”*
---
## 架构总览
frpc-console 是一个**轻量级生命周期管理工具**,它的架构设计围绕着三个核心目标:
1. **低资源占用** — 在边缘设备上也能运行
2. **高可靠性** — 面板可挂,业务不能停
3. **零依赖部署** — 单一二进制,开箱即用
### 整体架构图
```mermaid
graph TB
subgraph User["用户侧"]
Browser["浏览器"]
CLI["命令行"]
end
subgraph Console["frpc-console"]
WebUI["Web UI<br/>(Vue 3 + 深色磨砂玻璃)"]
APIServer["API Server<br/>(Gin)"]
Lifecycle["生命周期管理器"]
ConfigMgr["配置管理器<br/>(TOML 解析/生成)"]
ProcessMgr["进程管理器<br/>(SetSid / PID 1 接管)"]
DB["SQLite<br/>(用户/隧道/配置)"]
Static["静态资源<br/>(内嵌)"]
end
subgraph FRP["被管理对象"]
FRPC["frpc 进程"]
TOML["frpc.toml"]
end
Browser --> WebUI
CLI --> APIServer
WebUI --> APIServer
APIServer --> DB
APIServer --> ConfigMgr
ConfigMgr --> TOML
APIServer --> Lifecycle
Lifecycle --> ProcessMgr
ProcessMgr --> FRPC
FRPC --> TOML
Static -.-> WebUI
```
> **说明:** `Static`(前端静态资源)在编译时通过 `embed` 直接打包进二进制,运行时无需额外加载。因此图中以虚线表示其与 WebUI 的关联,且不占用独立部署单元。
---
## 部署模型
frpc-console 支持两种部署模型,架构核心逻辑完全一致,只是运行环境不同。
### 二进制部署模型
```
┌──────────────────────────────────────────┐
│ 操作系统 (Linux/Windows) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ frpc-console │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ Web UI │ API Server │ │ │
│ │ ├──────────────────────────────┤ │ │
│ │ │ 生命周期管理 / 配置管理 │ │ │
│ │ └──────────┬───────────────────┘ │ │
│ └─────────────┼──────────────────────┘ │
│ │ SetSid + 独立会话 │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ frpc 子进程 │ │
│ │ (被 PID 1 接管,独立生命周期) │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ 数据目录: /opt/frpc-console/data │ │
│ │ ├── frpc-console.db │ │
│ │ ├── frpc.toml │ │
│ │ ├── frpc (二进制) │ │
│ │ ├── frpc.pid │ │
│ │ └── version.ini │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
```
**关键机制:**
- frpc-console 启动时,通过 `SetSid` 为 frpc 创建**独立会话**
- frpc 进程完全脱离父进程的生命周期控制
- 即使 console 崩溃或被 killfrpc 会被 initPID 1)接管,继续运行
### Docker 部署模型
```
┌──────────────────────────────────────────┐
│ Docker Host │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Container: frpc-console │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ Web UI │ API Server │ │ │
│ │ ├──────────────────────────────┤ │ │
│ │ │ 生命周期管理 / 配置管理 │ │ │
│ │ └──────────┬───────────────────┘ │ │
│ │ │ 启动 frpc │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ frpc 子进程 (容器内) │ │ │
│ │ └──────────────────────────────┘ │ │
│ └──────────────┬─────────────────────┘ │
│ │ Volume 挂载 │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 数据卷: /opt/frpc-console/data │ │
│ │ ├── frpc-console.db │ │
│ │ ├── frpc.toml │ │
│ │ ├── frpc.pid │ │
│ │ └── version.ini │ │
│ └────────────────────────────────────┘ │
│ │
│ 重启策略: --restart=always │
└──────────────────────────────────────────┘
```
**关键机制:**
- 容器配置 `--restart=always`console 退出时 Docker 自动重启
- 数据目录通过 Volume 挂载持久化
- 容器重启后自动重新拉起 frpc
---
## 核心模块
### 1. Web UI(前端)
- **框架:** Vue 3
- **风格:** 深色磨砂玻璃视觉
- **设计原则:** 需要时清晰易用,不需要时不打扰
- **构建产物:** 静态资源通过 Go embed 内嵌于二进制
### 2. API Server
- **框架:** Gin
- **认证:** Session / JWT
- **职责:** 提供 RESTful API,处理前端请求
### 3. 生命周期管理器
负责 frpc 进程的完整生命周期:
| 操作 | 行为 |
|---|---|
| 启动 | 根据当前 frpc.toml 启动 frpc 进程 |
| 停止 | 向 frpc 发送终止信号 |
| 重启 | 停止 → 重新加载配置 → 启动 |
| 状态检查 | 读取 PID 文件,验证进程是否存在 |
| 热加载 | 修改配置后自动重启 frpc(无需手动操作) |
### 4. 配置管理器
- 解析和生成 TOML 格式的 frp 配置文件
- 支持从现有 frpc.toml 导入
- 修改配置后自动触发重启
### 5. 进程管理器
- 通过 `SetSid` 创建独立会话(Linux
- frpc 二进制内置在部署包中,无需额外下载
- 记录 PID 到文件,用于状态检查和进程管理
- Windows 版本使用相应的进程管理 API
### 6. SQLite 数据库
- **表结构:**
- `users` — 管理员账户
- `tunnels` — 隧道配置
- `configs` — 全局配置
- **备份机制:** 部署脚本在降级前自动备份数据库文件
- **位置:** `data/frpc-console.db`
---
## 关键交互流程
### 启动流程
```mermaid
sequenceDiagram
participant User
participant Console
participant FRPC
User->>Console: 启动 frpc-console
Console->>Console: 读取 data/frpc.toml
alt 配置文件存在
Console->>FRPC: 启动 frpc (SetSid)
FRPC-->>Console: PID 写入 frpc.pid
Console-->>User: 服务就绪
else 配置文件不存在
Console-->>User: 等待 WebUI 导入配置
User->>Console: WebUI 导入 frpc.toml
Console->>FRPC: 启动 frpc
end
```
### 配置更新流程
```mermaid
sequenceDiagram
participant User
participant WebUI
participant API
participant ConfigMgr
participant FRPC
User->>WebUI: 修改隧道配置
WebUI->>API: PUT /api/tunnels/:id
API->>ConfigMgr: 更新配置
ConfigMgr->>ConfigMgr: 写入 data/frpc.toml
ConfigMgr-->>API: 配置已更新
API-->>WebUI: 200 OK
API->>FRPC: 重启 frpc (热加载)
FRPC-->>API: 启动成功
```
---
## 资源边界
### 运行时资源
| 资源 | 典型值 | 说明 |
|---|---|---|
| CPUidle | ~0% | 无后台轮询 |
| 内存(idle | < 20MB | 无额外守护进程 |
| 存储(二进制) | ~15MB | 静态编译,无依赖 |
| 存储(数据) | < 1MB | SQLite + 配置文件 |
> 真实设备实测数据见 [工程设计哲学 - 稳定性与可观测性](./engineering-philosophy.md#稳定性与可观测性)
### 文件系统布局
```
/opt/frpc-console/ # 默认部署目录
├── data/ # 数据目录(持久化)
│ ├── frpc-console.db # SQLite 数据库
│ ├── frpc.toml # 当前 frpc 配置
│ ├── frpc # FRP 二进制(内置)
│ ├── frpc.pid # frpc 进程 PID
│ ├── frpc.log # frpc 日志(可选)
│ └── version.ini # 当前版本标识
├── frpc-console # 主二进制(二进制部署)
└── .old_backup_* # 旧版本备份(迁移时生成)
```
---
## 架构演进
当前架构不是一次性设计完成的,而是经历了以下阶段:
1. **最初**:一个简单的 Web UI,通过命令行调用 frpc
2. **发现问题**:SSH 断开后 frpc 也跟着退出 → 引入 SetSid
3. **发现问题**:配置文件修改需要手动重启 → 引入热加载
4. **发现问题**ARMHF 设备跑不动 Docker → 引入二进制部署
5. **发现问题**:边缘设备内存不足 → 优化运行时内存占用
6. **发现问题**:更新时数据丢失 → 引入事务性部署脚本
7. **持续演化中**:每次真实部署都可能带来新的架构调整
---
## 相关文档
- [工程设计哲学](./engineering-philosophy.md) — 架构决策背后的设计原则
- [设计决策记录](./design-decisions.md) — 每个“为什么”的详细记录
- [边缘节点部署](./edge-node.md) — 在受限环境中的架构适配
- [更新策略](./update-strategy.md) — 版本管理和升级机制
- [部署指南](./INSTALL_DOCKER.md) — Docker 部署详细步骤
- [二进制安装指南](./INSTALL_BINARY.md) — 二进制部署详细步骤