From 56d91edb814fdaa4ca95c2a25fd34144ed5d1118 Mon Sep 17 00:00:00 2001 From: Nixevol Date: Fri, 26 Jun 2026 14:04:35 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=BC=96=E6=8E=92=20README=20=E8=A1=A5?= =?UTF-8?q?=E5=85=A8=E4=B8=80=E9=94=AE=E6=9E=84=E5=BB=BA=E6=95=B4=E5=A5=97?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=8C=87=E5=8D=97=EF=BC=8C=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E5=8C=85=E8=A1=A5=20sftpgo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++ docs/project_context.md | 3 + packaging/README.md | 136 ++++++++++++++++++++++++++++++++-------- scripts/build_docker.py | 4 ++ 4 files changed, 129 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f680f8c..5118df8 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,17 @@ docker load -i dist/docker/capacity-report-app-latest.tar docker compose -f dist/docker/docker-compose.yml up -d ``` +### Docker 编排(应用 + MySQL + sftpgo) + +整套系统(应用、MySQL、sftpgo 文件服务)可用 `packaging/docker-compose.yml` 一键构建运行: + +```bash +cd frontend && npm ci && npm run build && cd ../packaging +docker compose build && docker compose up -d +``` + +完整的编排说明(在线构建、内网离线部署、默认账号、上传数据、数据卷、运维命令)见 [packaging/README.md](packaging/README.md)。 + ## 文档 - [使用说明 USAGE.md](USAGE.md):Web 端各功能的操作方法与注意事项。 diff --git a/docs/project_context.md b/docs/project_context.md index e0cf4a3..32a7385 100644 --- a/docs/project_context.md +++ b/docs/project_context.md @@ -1023,6 +1023,9 @@ CellData 处理日志细化(`app/services/cell_data.py`): - **修复镜像缺文件**:根 `Dockerfile` 原只拷 `Configure.json/ReportScript.sql`,漏了 `CellData.sql` 与 `db_init/`(容器内跑 CellData/前置检查会缺);现增拷 `CellData.sql`、`db_init/`、整个 `docker/`。`docker/entrypoint.sh` 增加播种 `CellData.sql`、`db_init/` 到 /data,并在**首次播种**时调用新脚本 `docker/apply_env_config.py` 按 env 改写 Configure.json 的数据库/SFTP 连接(用户后续界面改动不被覆盖)。 - `packaging/README.md`:一键编排使用说明(构建前端→compose build/up、默认账号、放数据路径、数据卷)。 - 校验:`docker compose config -q` 通过;JSON/py_compile 通过。 +- 文档:`packaging/README.md` 重写为「一键构建整套系统」完整指南(方式A 联网 build+up、方式B 内网离线 load+up、默认账号、上传数据路径、数据卷、运维命令);主 `README.md` 增「Docker 编排」段落并链接 packaging/README.md。 +- 修复 `scripts/build_docker.py` 离线包缺口:`make_bundle` 原只拷 `mysql/`,现补拷 `sftpgo/` 与 `packaging/README.md`(compose 引用 `./sftpgo/sftpgo-init.json`,否则离线包启动缺文件)。 +- 离线镜像:`F:\CR\env\images` 已 `docker save` 三个基础镜像(mysql_8.0.44.tar/sftpgo_v2.7.1.tar/python_3.13.11-slim.tar)+ `load_images.py`(扫描同目录 *.tar 逐个 `docker load -i ./xxx.tar`,已实测导入成功)。注:F: 盘离线资产不在仓库内。 ## 2026-06-26:测试数据抽取工具(本地 test/,已 gitignore) diff --git a/packaging/README.md b/packaging/README.md index 59434bc..b577a9b 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1,38 +1,124 @@ -# Docker 一键编排(应用 + MySQL + sftpgo) +# Docker 编排:一键构建并运行整套系统(应用 + MySQL + sftpgo) -`docker-compose.yml` 编排三个服务,开箱即用、互相连通: +`docker-compose.yml` 把整套系统编排为三个互相连通的服务,开箱即用。 -| 服务 | 容器 | 端口(宿主:容器) | 说明 | -|---|---|---|---| -| capacity-app | capacity-report-app | 9081:9081 | 应用(前端+后端) | -| capacity-mysql | capacity-mysql | 13306:3306 | MySQL 8(建 `CapacityReport` 与 `celldata` 两库) | +| 服务 | 容器名 | 端口(宿主:容器) | 说明 | +| --- | --- | --- | --- | +| capacity-app | capacity-report-app | 9081:9081 | 应用(前端 + 后端),数据落在 `/data` 卷 | +| capacity-mysql | capacity-mysql | 13306:3306 | MySQL 8,自动建 `CapacityReport` 与 `celldata` 两库 | | sftpgo | capacity-sftpgo | 2022:2022(SFTP)、18080:8080(Web) | 文件服务,供应用拉取数据 | -## 构建并启动 -```bash -# 1) 先构建前端(产出 frontend/dist,镜像会拷贝它) -cd ../frontend && npm ci && npm run build && cd ../packaging +> 应用镜像 `capacity-report-app:latest` 由本仓库根的 `Dockerfile` 构建;MySQL、sftpgo 为公共镜像。 -# 2) 构建并启动 +--- + +## 前置要求 + +- 已安装 Docker(含 Docker Compose v2,命令为 `docker compose`)。 +- 构建应用镜像需要先产出前端 `frontend/dist`(下方步骤会做)。 +- 联网构建需要能拉取 `python:3.13.11-slim`、`mysql:8.0.44`、`drakkan/sftpgo:v2.7.1`; + 内网离线见「方式 B」。 + +--- + +## 方式 A:联网机器,一键构建并启动 + +```bash +# 1) 构建前端(产出 frontend/dist,镜像会拷贝它) +cd ../frontend +npm ci && npm run build +cd ../packaging + +# 2) 构建应用镜像并启动整套系统 docker compose build docker compose up -d + +# 3) 查看状态 / 日志 +docker compose ps +docker compose logs -f capacity-app ``` -## 默认账号 / 连接(首次启动自动写入应用配置) -- MySQL:`root / gmcc123`,库 `CapacityReport`、`celldata`(应用内主机用服务名 `capacity-mysql`)。 -- sftpgo:SFTP 用户 `capacity / capacity123`(home `/srv/sftpgo/data/capacity`);Web 管理员 `admin / gmcc123`(http://localhost:18080)。 -- 应用首次启动时,`entrypoint` 会按 compose 里的环境变量把 `Configure.json` 的「数据库/SFTP 连接」改写为容器服务(主机用服务名 `capacity-mysql` / `sftpgo`)。之后你在界面里的修改不会被覆盖。 +启动后访问 `http://localhost:9081`(默认登录 `root` / `Capacity`)。 -## 放数据 -通过 SFTP(localhost:2022,capacity/capacity123)或 Web(18080)把数据上传到 `capacity` 用户目录: -- 容量数据:上传到 `/CapacityReportData`(对应 `RemoteData.remote_dir`,结构 `4G/ 5G/ RJ/`)。 -- CellData:上传到 `/网优日常优化数据文档/...`(对应 `CellData.scan_paths`)。 -> 用 `test/make_test_data.py` 生成的小样本可直接传上来做测试。 +> 也可以用脚本一步构建并导出离线包:在仓库根执行 `python scripts/build_docker.py`, +> 产物在 `dist/docker/`(含 `capacity-report-app-latest.tar` + `docker-compose.yml` + `mysql/` + `sftpgo/` + 默认脚本)。 + +--- + +## 方式 B:内网离线部署(无外网) + +在有网机器准备好以下文件,拷贝到内网机器: + +1. **基础/公共镜像**(python、mysql、sftpgo)——可用离线镜像目录方案: + - 有网机器:`docker pull` 三个镜像后 `docker save -o xxx.tar`,连同导入脚本放一个目录。 + - 内网机器:在该目录执行 `python load_images.py` 逐个 `docker load -i ./xxx.tar`。 + - (示例:本项目已在 `F:\CR\env\images` 准备了 `mysql_8.0.44.tar`、`sftpgo_v2.7.1.tar`、`python_3.13.11-slim.tar` 与 `load_images.py`。) +2. **应用镜像**:在有网机器 `docker compose build` 后 + `docker save capacity-report-app:latest -o capacity-report-app.tar`,拷到内网 `docker load -i ./capacity-report-app.tar`。 + - 或直接用 `python scripts/build_docker.py` 生成 `dist/docker/` 整包带走。 +3. **编排文件**:本目录的 `docker-compose.yml` + `mysql/` + `sftpgo/`。 + +内网机器导入镜像后,在编排文件目录执行: + +```bash +docker compose up -d # 镜像已在本地,不会联网拉取 +``` + +> 若内网机器**不便构建**应用镜像,务必走「先在有网机器 build 出 `capacity-report-app:latest` 再 save」, +> 这样内网仅需 `docker load` + `docker compose up -d`,无需 python 基础镜像与构建。 + +--- + +## 默认账号 / 连接 + +| 项 | 值 | +| --- | --- | +| 应用登录 | `root` / `Capacity` | +| MySQL | `root` / `gmcc123`,库 `CapacityReport`、`celldata`(容器内主机名 `capacity-mysql`) | +| SFTP 用户 | `capacity` / `capacity123`(home `/srv/sftpgo/data/capacity`) | +| sftpgo Web | `admin` / `gmcc123`(http://localhost:18080) | + +应用**首次启动**时,`entrypoint` 会按 `docker-compose.yml` 里的环境变量把 `Configure.json` 的 +「数据库 / SFTP 连接」自动改写为容器服务(主机名用 `capacity-mysql` / `sftpgo`); +之后你在界面里的修改不会被覆盖。要改默认密码等,编辑 compose 的环境变量与 `sftpgo/sftpgo-init.json`。 + +--- + +## 上传数据 + +通过 SFTP(`localhost:2022`,`capacity`/`capacity123`)或 sftpgo Web(`:18080`)上传到 `capacity` 用户目录: + +- 容量数据 → `/CapacityReportData`(对应 `RemoteData.remote_dir`,结构 `4G/ 5G/ RJ/`)。 +- CellData → `/网优日常优化数据文档/...`(对应 `CellData.scan_paths`)。 + +> 用仓库 `test/make_test_data.py` 生成的小样本可直接传上来做快速测试。 +> 上传后在「数据处理」页执行处理;首次会自动建表(`db_init/` 前置检查)。 + +--- ## 数据卷(持久化) -- `capacity-data`:应用 `/data`(配置、脚本、特征库、历史、缓存)。 -- `capacity-mysql-data`:MySQL 数据。 -- `sftpgo-config` / `sftpgo-data`:sftpgo 状态与文件。 -## 修改密码等 -改 `docker-compose.yml` 里的环境变量与 `sftpgo/sftpgo-init.json`,重新 `up -d` 即可(首次播种后应用侧连接不再自动改写,需要的话删除 `capacity-data` 卷重置)。 +| 卷 | 内容 | +| --- | --- | +| `capacity-data` | 应用 `/data`:Configure.json、ReportScript.sql、CellData.sql、db_init、历史、缓存 | +| `capacity-mysql-data` | MySQL 数据 | +| `sftpgo-config` / `sftpgo-data` | sftpgo 状态与上传的文件 | + +--- + +## 常用运维 + +```bash +docker compose ps # 状态 +docker compose logs -f capacity-app # 应用日志 +docker compose restart capacity-app # 重启应用 +docker compose down # 停止(保留数据卷) +docker compose down -v # 停止并删除数据卷(彻底重置,慎用) + +# 改了代码 / 前端后更新应用: +cd ../frontend && npm run build && cd ../packaging +docker compose build capacity-app && docker compose up -d capacity-app +``` + +> 重置应用侧连接:`Configure.json` 仅在首次播种时按环境变量初始化;如需重新按 env 生成, +> 删除 `capacity-data` 卷(`docker volume rm packaging_capacity-data`)后重新 `up -d`。 diff --git a/scripts/build_docker.py b/scripts/build_docker.py index 0a50ddd..aa99d4a 100644 --- a/scripts/build_docker.py +++ b/scripts/build_docker.py @@ -44,6 +44,10 @@ def make_bundle(save_tar: bool) -> Path: shutil.copy2(COMPOSE_FILE, out_dir / "docker-compose.yml") shutil.copytree(_env.PACKAGING_DIR / "mysql", out_dir / "mysql", dirs_exist_ok=True) + shutil.copytree(_env.PACKAGING_DIR / "sftpgo", out_dir / "sftpgo", dirs_exist_ok=True) + readme = _env.PACKAGING_DIR / "README.md" + if readme.exists(): + shutil.copy2(readme, out_dir / "README.md") for name in BUNDLE_FILES: src = _env.ROOT / name if src.exists():