Files
frpc-console/Docs/architecture.md
T

11 KiB
Raw Permalink Blame History

架构设计

“代码定义了它如何工作,架构定义了它如何活着。”


架构总览

frpc-console 是一个轻量级生命周期管理工具,它的架构设计围绕着三个核心目标:

  1. 低资源占用 — 在边缘设备上也能运行
  2. 高可靠性 — 面板可挂,业务不能停
  3. 零依赖部署 — 单一二进制,开箱即用

整体架构图

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=alwaysconsole 退出时 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

关键交互流程

启动流程

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

配置更新流程

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 + 配置文件

真实设备实测数据见 工程设计哲学 - 稳定性与可观测性

文件系统布局

/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. 持续演化中:每次真实部署都可能带来新的架构调整

相关文档