docs: 新增部署与运维页面映射 (#15)

从 docs/templates/deployment.md 建立 Deployment-and-Operations 页面映射,由 harness.py sync 导出核心镜像。
This commit is contained in:
ila
2026-09-15 16:27:36 +08:00
parent 20e13e909b
commit bdb38970e0
2 changed files with 201 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
<!-- gitea-wiki-mirror:start -->
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Deployment-and-Operations
wiki_url: https://git.ilapage.cn/OPC/lexgo/wiki/Deployment-and-Operations.-
wiki_revision: 2b08a33c0c246841deb52450d7fa411d76dc2eee
synchronized_at: 2026-09-15T08:25:07Z
<!-- gitea-wiki-mirror:end -->
# 部署与运维
本页面向 LexGo 的内部维护者:在一台干净的机器上首次部署、日常运维、健康检查、升级回滚与备份恢复。所有命令以仓库根为工作目录。**本页只写配置项名称与来源,不写任何真实密码、令牌或生产数据库地址。**
## 本页用途
让维护者在一台新机器上完成首次部署,并在需要时把实例从备份恢复回来,同时知道哪些步骤不可逆、哪些证据必须留下。
## 安全边界
- 凭据只从运维密码库或 `.env.local`(已被 `.gitignore` 忽略)读取;`.env.local` 权限应为仅本人可读写。
- 备份文件含全部用户数据(账号、书籍原文、词条、复习记录、审计日志、词典归档),必须按个人数据对待:存放位置受控、不进入 Git、不进入工单附件。
- `restore` 会写入数据库:默认只写空库,覆盖已有库必须显式 `--force`,任何情况下都必须 `--confirm`。
- 服务默认只监听 `127.0.0.1`;对外提供访问时经反向代理,不要直接暴露应用端口。
## 服务概览
| 项目 | 内容 |
|---|---|
| 组件 | Go 后端(`server/`)、学习端 SPA(`learner/`)、管理端 SPA(`admin/`)、MySQL 8 |
| 后端监听 | `LEXGO_LISTEN`,默认 `127.0.0.1:8000` |
| 前端托管 | 反向代理(nginx)托管已构建的 `dist`,同一域名下把 `/api/` 转发到后端 |
| 数据库 | MySQL 8(本机验证版本 8.4.3);库名经 `LEXGO_DB_NAME` 指定 |
| 运行时 | 后端为单个静态二进制,无需运行时依赖;构建需要 Go 1.26.5、Node 22、pnpm 9 |
| 进程托管 | supervisor(本项目开发机即为 `lexgo-api` / `lexgo-learner` / `lexgo-admin` 三个 program) |
| 日志 | supervisor 的 `stdout`/`stderr` 日志文件;应用自身不写文件日志 |
| 备份对象 | MySQL 全库(用户数据、原文、词典归档、审计)+ `.env.local`(单独从密码库取) |
## 环境要求
| 组件 | 版本要求 | 检查命令 | 预期结果 |
|---|---|---|---|
| 操作系统 | Windows 或 Linux | — | 本项目在 Windows 开发机验证;Linux 步骤为等价命令 |
| MySQL 服务端 | 8.x | `mysql --version`(服务端 `SELECT VERSION()`) | 8.4.3 已验证 |
| MySQL 客户端 | **不低于服务端** | `python scripts/ops.py install-check` | 「客户端版本不低于服务端」为 ok;5.7 客户端连 8.4 服务端会被判 fail |
| Go | 1.26.5 | `go version` | 供 `scripts/server.py` 固定工具链构建 |
| Node / pnpm | Node 22、pnpm 9 | `node --version`、`pnpm --version` | 仅在需要构建前端时要求 |
| WordNet 资源 | `server/wordnet-resource.json` 固定的 ZIP | `python scripts/ops.py install-check` | 「WordNet 资源 pin」为 ok;资源只在显式导入时使用,不在运行时下载 |
## 首次部署
### 1. 取得代码并检查依赖
```bash
git clone <仓库地址> <部署目录>
cd <部署目录>
git rev-parse HEAD # 记录本次部署的提交哈希
python scripts/ops.py install-check
```
预期结果:提交哈希被记录到部署记录;`install-check` 全部 `[ok]`,否则按其提示补齐后再继续。
### 2. 创建数据库与配置
```bash
python scripts/ops.py init-database --database lexgo_prod
```
预期结果:输出「已创建库」并打印需要授予的最小权限(`SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES`,仅限该库)。不要用管理员账号运行应用。
把 `.env.local`(从 `.env.example` 复制)填好:`LEXGO_DB_HOST/PORT/NAME/USER/PASSWORD`、`LEXGO_BOOTSTRAP_USERNAME/PASSWORD`、`LEXGO_LISTEN`。凭据值取自运维密码库,不进 Git、不进日志。
### 3. 迁移与初始化管理员
```bash
python scripts/server.py migrate # 只有这一步会改表结构
python scripts/server.py bootstrap # 首次建立唯一管理员
```
预期结果:`migrate` 输出 schema 版本;`bootstrap` 输出创建成功。**库中已有账号时 `bootstrap` 会拒绝执行**,不会覆盖既有管理员。空库不含默认密码与任何演示数据。
### 4. 构建产物
```bash
python scripts/server.py build # 产出 server/lexgo(.exe)
cd learner && pnpm install && pnpm run build
cd ../admin && pnpm install && pnpm run build
```
预期结果:后端二进制与两份 `dist` 生成。前端由反向代理托管;反向代理需把未知路径回落到 `index.html`(SPA 路由),并把 `/api/` 转发到后端。
### 5. 词典资源
词典归档在显式导入后存于 MySQL,备份与恢复会一并带走,运行时不下载。
### 6. 启动与健康检查
按 supervisor 配置启动三个 program(后端 + 两个静态站点或由反向代理托管)。然后执行下方「健康检查」全部命令。
## 配置与凭据来源
| 配置项 | 用途 | 来源 | 是否敏感 |
|---|---|---|---|
| `LEXGO_DB_HOST/PORT/NAME/USER/PASSWORD` | 数据库连接 | `.env.local`,值取自运维密码库 | 是(密码) |
| `LEXGO_BOOTSTRAP_USERNAME/PASSWORD` | 首次建立管理员 | 同上 | 是(密码) |
| `LEXGO_LISTEN` | 后端监听地址 | `.env.local` | 否 |
| `LEXGO_MYSQL_BIN` | 指定 MySQL 客户端目录 | 运维环境变量 | 否 |
| `LEXGO_TEST_DB_NAME` | 集成测试库(仅开发) | 环境变量 | 否 |
`scripts/ops.py` 的 manifest 与日志只记录配置项**名称**、库名、schema 版本与提交哈希,不记录任何凭据值。
## 日常运维
| 操作 | 命令 | 预期结果 |
|---|---|---|
| 查看状态 | `supervisorctl status lexgo-api` | `RUNNING`,uptime 持续增长 |
| 重启后端 | `supervisorctl restart lexgo-api` | `stopped` 后 `started` |
| 查看日志 | `supervisorctl tail -f lexgo-api stderr` | 持续输出应用日志 |
| 备份 | `python scripts/ops.py backup --out <目录>` | 生成 `lexgo-<时间戳>.sql.gz` 与 `manifest.json` |
| 校验实例 | `python scripts/ops.py verify --database <库名>` | 打印每项检查结果,最后「校验通过」 |
| 清理过期审计 | `python scripts/server.py audit-cleanup` | 只清理两张审计表中超过 90 天的记录 |
| 关闭确认 | `supervisorctl stop lexgo-api` | 服务停止;学习端与反代仍在,接口不可用 |
## 健康检查
```bash
supervisorctl status lexgo-api
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/healthz
python scripts/ops.py verify --database <库名>
```
预期结果:状态 `RUNNING`;`curl` 返回 `200`;`verify` 全部 `[ok]`。任何一项不符合时不视为部署成功,按「升级与回滚」处理。
## 升级与回滚
### 升级
```bash
git rev-parse HEAD # 记录升级前提交,回滚需要
python scripts/ops.py backup --out <目录> # 有迁移时必须先备份
git fetch --all && git checkout <目标提交或标签>
python scripts/server.py build
cd learner && pnpm install && pnpm run build && cd ../admin && pnpm install && pnpm run build
python scripts/server.py migrate # 只有迁移单需要
supervisorctl restart lexgo-api
```
预期结果:重启后状态 `RUNNING`,健康检查全部通过。前端 `dist` 更新后由反代直接生效,无需重启后端。
### 回滚
```bash
git checkout <升级前记录的提交>
python scripts/server.py build
supervisorctl restart lexgo-api
```
预期结果:健康检查全部通过。
> **注意**:已执行的迁移通常不能用切回代码撤销。LexGo 的用法是:每个版本的迁移只新增对象(`CREATE TABLE IF NOT EXISTS`),旧二进制认版本号,因此回退到旧二进制前要把 `lexgo_schema.version` 写回旧版本号;若迁移删改了数据或旧二进制无法读写新结构,则按「备份与恢复」处理。**本节只描述规则,真实回滚尚未演练过,属于已知限制。**
## 备份与恢复
### 备份对象与频率
- **数据库**:一个实例的全部持久数据(账号与会话、书籍与章节原文、导入任务、词典归档、词条、复习排期与作答、阅读进度、审计日志)。
- **环境配置**:`.env.local`(含凭据)单独从运维密码库保存,**不放进备份目录**。
- **代码与二进制**:由 Git 提交哈希重建,manifest 中记录了该哈希。
- 建议频率:每次升级或有迁移前必须备份;日常按使用强度自行决定(本项目未启用定时任务)。保留份数与存放位置由运维决定。
```bash
python scripts/ops.py backup --out <备份目录>
```
预期结果:目录中出现 `lexgo-<时间戳>.sql.gz` 与 `manifest.json`(schema 版本、提交哈希、逐表行数、dump 的 sha256、客户端与服务端版本)。manifest 不含凭据。
### 恢复步骤
```bash
python scripts/ops.py restore --dump <备份目录>/lexgo-<时间戳>.sql.gz --database <新库名> --confirm
python scripts/ops.py verify --database <新库名> --manifest <备份目录>/manifest.json \
--api http://127.0.0.1:<演练端口> --user <账号前缀> --password-env <密码环境变量名>
```
预期结果:恢复写入空库、自动校验通过;`verify` 打印完整性与两账号隔离检查,最后「校验通过」。恢复**不会**写入备份里的源库,工具会在恢复前后比对源库的内容校验和(本机演练已验证)。
> **注意**:`restore` 默认拒绝写入已有数据的库;覆盖必须 `--force`,执行前先备份当前库。库名必须包含 `lexgo` 且不能是 MySQL 系统库。
### 恢复演练记录
2026-09-15 在本机完成完整演练:空库安装(init-database → migrate → bootstrap → 管理员建两个演练账号 → 走通粘贴/阅读/查词/保存/复习/完成章节/进度)与「备份 lexgo_dev → 恢复到空库 → 起第二个 API 实例 → 两账号闭环与越权校验」,恢复后逐表行数与内容校验和都和源库一致,演练库用后删除。详细命令与结果见工单 #15 与本地开发页。
## 已知限制
- **真实回滚演练未做**:本文档给出规则,但没有在真实实例上执行过「升级 → 回滚」全过程。
- 未验证 HTTPS、域名、多机与灰度部署;本机演练只用 `127.0.0.1` 与模拟触摸视口。
- 未启用定时备份、监控与告警;备份由人工触发。
- **附件(封面/音频)尚未实现(工单 #21)**:本页的备份恢复范围目前只覆盖数据库;#21 落地后必须把附件存储纳入备份与恢复验收。
- 恢复演练是单机顺序执行,未验证大库恢复耗时与磁盘空间上限。
+4
View File
@@ -83,6 +83,10 @@
{
"page": "Go-Analysis-Alternative",
"path": "docs/linguacafe-go-analysis.md"
},
{
"page": "Deployment-and-Operations",
"path": "docs/11-deployment-and-operations.md"
}
]
}