feat: Docker 一键编排补齐 sftpgo 与 celldata 库,并修复镜像缺 CellData.sql/db_init
This commit is contained in:
+7
-4
@@ -14,10 +14,13 @@ RUN pip install -r requirements.txt
|
|||||||
|
|
||||||
COPY app/ ./app/
|
COPY app/ ./app/
|
||||||
COPY frontend/dist ./frontend/dist
|
COPY frontend/dist ./frontend/dist
|
||||||
# 默认配置/脚本:首次启动由 entrypoint 播种到数据卷 /data(已存在则保留用户修改)。
|
# 默认配置/脚本/特征库:首次启动由 entrypoint 播种到数据卷 /data(已存在则保留用户修改)。
|
||||||
COPY Configure.json ReportScript.sql ./defaults/
|
COPY Configure.json ReportScript.sql CellData.sql ./defaults/
|
||||||
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
COPY db_init/ ./defaults/db_init/
|
||||||
RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
|
COPY docker/ ./docker/
|
||||||
|
RUN sed -i 's/\r$//' /app/docker/entrypoint.sh \
|
||||||
|
&& cp /app/docker/entrypoint.sh /usr/local/bin/entrypoint.sh \
|
||||||
|
&& chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
EXPOSE 9081
|
EXPOSE 9081
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""首次播种 Configure.json 后,按容器环境变量改写「数据库 / SFTP 连接」。
|
||||||
|
|
||||||
|
仅在 entrypoint 首次创建 /data/Configure.json 时调用一次;用户之后在界面里的修改不会被覆盖。
|
||||||
|
保留数据格式相关配置(DataMappings / ExtractField / CellData.mapping 等)不变。
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
BASE_DIR = os.environ.get("CAPAREPORT_BASE_DIR", "/data")
|
||||||
|
CONFIG_PATH = os.path.join(BASE_DIR, "Configure.json")
|
||||||
|
|
||||||
|
|
||||||
|
def set_str(target: dict, key: str, env: str) -> None:
|
||||||
|
val = os.environ.get(env)
|
||||||
|
if val not in (None, ""):
|
||||||
|
target[key] = val
|
||||||
|
|
||||||
|
|
||||||
|
def set_int(target: dict, key: str, env: str) -> None:
|
||||||
|
val = os.environ.get(env)
|
||||||
|
if val not in (None, ""):
|
||||||
|
try:
|
||||||
|
target[key] = int(val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
if not os.path.exists(CONFIG_PATH):
|
||||||
|
return
|
||||||
|
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
|
||||||
|
# 主仓库 MySQL
|
||||||
|
main_db = cfg.setdefault("MySQL_DBInfo", {})
|
||||||
|
set_str(main_db, "host", "DB_HOST")
|
||||||
|
set_int(main_db, "port", "DB_PORT")
|
||||||
|
set_str(main_db, "user", "DB_USER")
|
||||||
|
set_str(main_db, "passwd", "DB_PASSWD")
|
||||||
|
set_str(main_db, "dbname", "MAIN_DB_NAME")
|
||||||
|
|
||||||
|
cell = cfg.setdefault("CellData", {})
|
||||||
|
# CellData MySQL
|
||||||
|
cell_db = cell.setdefault("mysql", {})
|
||||||
|
set_str(cell_db, "host", "DB_HOST")
|
||||||
|
set_int(cell_db, "port", "DB_PORT")
|
||||||
|
set_str(cell_db, "user", "DB_USER")
|
||||||
|
set_str(cell_db, "passwd", "DB_PASSWD")
|
||||||
|
set_str(cell_db, "dbname", "CELLDATA_DB_NAME")
|
||||||
|
|
||||||
|
# 容量数据源 SFTP
|
||||||
|
remote = cfg.setdefault("RemoteData", {})
|
||||||
|
set_str(remote, "host", "SFTP_HOST")
|
||||||
|
set_int(remote, "port", "SFTP_PORT")
|
||||||
|
set_str(remote, "user", "SFTP_USER")
|
||||||
|
set_str(remote, "passwd", "SFTP_PASSWD")
|
||||||
|
|
||||||
|
# CellData 数据源 SFTP
|
||||||
|
cell_remote = cell.setdefault("remote_data", {})
|
||||||
|
set_str(cell_remote, "host", "SFTP_HOST")
|
||||||
|
set_int(cell_remote, "port", "SFTP_PORT")
|
||||||
|
set_str(cell_remote, "user", "SFTP_USER")
|
||||||
|
set_str(cell_remote, "passwd", "SFTP_PASSWD")
|
||||||
|
|
||||||
|
with open(CONFIG_PATH, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(cfg, f, ensure_ascii=False, indent=2)
|
||||||
|
print("[entrypoint] 已按容器环境变量初始化 Configure.json 的数据库/SFTP 连接")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+14
-2
@@ -1,9 +1,21 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# 运行态都落在数据卷 /data:配置、脚本、历史、缓存、登录态、Token。
|
# 运行态都落在数据卷 /data:配置、脚本、特征库、历史、缓存、登录态。
|
||||||
mkdir -p /data/cache
|
mkdir -p /data/cache
|
||||||
[ -f /data/Configure.json ] || cp /app/defaults/Configure.json /data/Configure.json
|
|
||||||
|
seeded=0
|
||||||
|
if [ ! -f /data/Configure.json ]; then
|
||||||
|
cp /app/defaults/Configure.json /data/Configure.json
|
||||||
|
seeded=1
|
||||||
|
fi
|
||||||
[ -f /data/ReportScript.sql ] || cp /app/defaults/ReportScript.sql /data/ReportScript.sql
|
[ -f /data/ReportScript.sql ] || cp /app/defaults/ReportScript.sql /data/ReportScript.sql
|
||||||
|
[ -f /data/CellData.sql ] || cp /app/defaults/CellData.sql /data/CellData.sql
|
||||||
|
[ -d /data/db_init ] || cp -r /app/defaults/db_init /data/db_init
|
||||||
|
|
||||||
|
# 首次播种时按容器环境变量改写 数据库/SFTP 连接(用户后续在界面的修改不会被覆盖)
|
||||||
|
if [ "$seeded" = "1" ] && [ -f /app/docker/apply_env_config.py ]; then
|
||||||
|
python /app/docker/apply_env_config.py || true
|
||||||
|
fi
|
||||||
|
|
||||||
exec python -m uvicorn app.main:app --host 0.0.0.0 --port 9081
|
exec python -m uvicorn app.main:app --host 0.0.0.0 --port 9081
|
||||||
|
|||||||
@@ -1015,6 +1015,15 @@ CellData 处理日志细化(`app/services/cell_data.py`):
|
|||||||
- 准确率(MCP 实测,重叠 66001):网络 100%、制式 97.88%(排除 3DMM 即 100%)、频段 97.6%、带宽 99.75%、站型 99.94%、**物理站 99.59%、扇区 99.20%**;残差为不可还原的人工差异(室分多载波编号、700M 个别人工编号、源数据制表符等)。详见 `docs/sector_inference_research.md`。
|
- 准确率(MCP 实测,重叠 66001):网络 100%、制式 97.88%(排除 3DMM 即 100%)、频段 97.6%、带宽 99.75%、站型 99.94%、**物理站 99.59%、扇区 99.20%**;残差为不可还原的人工差异(室分多载波编号、700M 个别人工编号、源数据制表符等)。详见 `docs/sector_inference_research.md`。
|
||||||
- 关键坑:MySQL 字符串字面量会吞掉未知转义的反斜杠,正则字面量需写 `\\(`(.sql 文件)/ JSON 调用需 `\\\\(`;ICU 正则字符类内的 `[ ]` 易误判,统一把名称中的 `[]` 转 `()` 后只处理圆括号。
|
- 关键坑:MySQL 字符串字面量会吞掉未知转义的反斜杠,正则字面量需写 `\\(`(.sql 文件)/ JSON 调用需 `\\\\(`;ICU 正则字符类内的 `[ ]` 易误判,统一把名称中的 `[]` 转 `()` 后只处理圆括号。
|
||||||
|
|
||||||
|
## 2026-06-26:Docker 一键编排补齐(应用 + MySQL + sftpgo)
|
||||||
|
|
||||||
|
- `packaging/docker-compose.yml`:在原 capacity-app + capacity-mysql 基础上**新增 sftpgo 服务**(`drakkan/sftpgo:v2.7.1`,SFTP 2022、Web 18080:8080,卷 `sftpgo-config`/`sftpgo-data`,`SFTPGO_LOADDATA_FROM` 导入 SFTP 用户)。capacity-app 加 `build` 上下文与一组连接环境变量(DB_HOST/PORT/USER/PASSWD、MAIN_DB_NAME、CELLDATA_DB_NAME、SFTP_HOST/PORT/USER/PASSWD),depends_on mysql(healthy)+sftpgo。
|
||||||
|
- `packaging/sftpgo/sftpgo-init.json`:自动建 SFTP 用户 `capacity/capacity123`(home `/srv/sftpgo/data/capacity`);Web 管理员 `admin/gmcc123` 由 env 创建。
|
||||||
|
- `packaging/mysql/init/01-init-db.sql`:补建 `celldata` 库(原只建 CapacityReport);表仍由前置检查按需建。
|
||||||
|
- **修复镜像缺文件**:根 `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 通过。
|
||||||
|
|
||||||
## 2026-06-26:测试数据抽取工具(本地 test/,已 gitignore)
|
## 2026-06-26:测试数据抽取工具(本地 test/,已 gitignore)
|
||||||
|
|
||||||
- `.gitignore` 新增忽略 `test/` 与 `temp/`(生成的测试数据)。`test/` 目录及其脚本不入库,仅本地用。
|
- `.gitignore` 新增忽略 `test/` 与 `temp/`(生成的测试数据)。`test/` 目录及其脚本不入库,仅本地用。
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Docker 一键编排(应用 + MySQL + sftpgo)
|
||||||
|
|
||||||
|
`docker-compose.yml` 编排三个服务,开箱即用、互相连通:
|
||||||
|
|
||||||
|
| 服务 | 容器 | 端口(宿主:容器) | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| capacity-app | capacity-report-app | 9081:9081 | 应用(前端+后端) |
|
||||||
|
| 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
|
||||||
|
|
||||||
|
# 2) 构建并启动
|
||||||
|
docker compose build
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 默认账号 / 连接(首次启动自动写入应用配置)
|
||||||
|
- 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`)。之后你在界面里的修改不会被覆盖。
|
||||||
|
|
||||||
|
## 放数据
|
||||||
|
通过 SFTP(localhost:2022,capacity/capacity123)或 Web(18080)把数据上传到 `capacity` 用户目录:
|
||||||
|
- 容量数据:上传到 `/CapacityReportData`(对应 `RemoteData.remote_dir`,结构 `4G/ 5G/ RJ/`)。
|
||||||
|
- CellData:上传到 `/网优日常优化数据文档/...`(对应 `CellData.scan_paths`)。
|
||||||
|
> 用 `test/make_test_data.py` 生成的小样本可直接传上来做测试。
|
||||||
|
|
||||||
|
## 数据卷(持久化)
|
||||||
|
- `capacity-data`:应用 `/data`(配置、脚本、特征库、历史、缓存)。
|
||||||
|
- `capacity-mysql-data`:MySQL 数据。
|
||||||
|
- `sftpgo-config` / `sftpgo-data`:sftpgo 状态与文件。
|
||||||
|
|
||||||
|
## 修改密码等
|
||||||
|
改 `docker-compose.yml` 里的环境变量与 `sftpgo/sftpgo-init.json`,重新 `up -d` 即可(首次播种后应用侧连接不再自动改写,需要的话删除 `capacity-data` 卷重置)。
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
# 一键编排:CapacityReport 应用 + MySQL + sftpgo
|
||||||
|
# 构建前先在仓库根构建前端:cd frontend && npm ci && npm run build(产出 frontend/dist)
|
||||||
|
# 然后在本目录:docker compose build && docker compose up -d
|
||||||
services:
|
services:
|
||||||
capacity-app:
|
capacity-app:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
image: capacity-report-app:latest
|
image: capacity-report-app:latest
|
||||||
container_name: capacity-report-app
|
container_name: capacity-report-app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -10,9 +16,22 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
- PYTHONUNBUFFERED=1
|
- PYTHONUNBUFFERED=1
|
||||||
|
# 首次启动按以下变量初始化 Configure.json 的连接(用户后续在界面改动不被覆盖)
|
||||||
|
- DB_HOST=capacity-mysql
|
||||||
|
- DB_PORT=3306
|
||||||
|
- DB_USER=root
|
||||||
|
- DB_PASSWD=gmcc123
|
||||||
|
- MAIN_DB_NAME=CapacityReport
|
||||||
|
- CELLDATA_DB_NAME=celldata
|
||||||
|
- SFTP_HOST=sftpgo
|
||||||
|
- SFTP_PORT=2022
|
||||||
|
- SFTP_USER=capacity
|
||||||
|
- SFTP_PASSWD=capacity123
|
||||||
depends_on:
|
depends_on:
|
||||||
capacity-mysql:
|
capacity-mysql:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
sftpgo:
|
||||||
|
condition: service_started
|
||||||
networks:
|
networks:
|
||||||
- capacity-network
|
- capacity-network
|
||||||
|
|
||||||
@@ -49,6 +68,28 @@ services:
|
|||||||
retries: 5
|
retries: 5
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
|
sftpgo:
|
||||||
|
image: drakkan/sftpgo:v2.7.1
|
||||||
|
container_name: capacity-sftpgo
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "2022:2022" # SFTP(上传容量/CellData 数据)
|
||||||
|
- "18080:8080" # Web 管理后台
|
||||||
|
environment:
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
# Web 后台管理员
|
||||||
|
- SFTPGO_DEFAULT_ADMIN_USERNAME=admin
|
||||||
|
- SFTPGO_DEFAULT_ADMIN_PASSWORD=gmcc123
|
||||||
|
# 启动时导入 SFTP 用户(capacity/capacity123);MODE=1 保留文件、每次启动确保用户存在
|
||||||
|
- SFTPGO_LOADDATA_FROM=/sftpgo-init.json
|
||||||
|
- SFTPGO_LOADDATA_MODE=1
|
||||||
|
volumes:
|
||||||
|
- sftpgo-config:/var/lib/sftpgo
|
||||||
|
- sftpgo-data:/srv/sftpgo/data
|
||||||
|
- ./sftpgo/sftpgo-init.json:/sftpgo-init.json:ro
|
||||||
|
networks:
|
||||||
|
- capacity-network
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
capacity-network:
|
capacity-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
@@ -58,3 +99,7 @@ volumes:
|
|||||||
driver: local
|
driver: local
|
||||||
capacity-data:
|
capacity-data:
|
||||||
driver: local
|
driver: local
|
||||||
|
sftpgo-config:
|
||||||
|
driver: local
|
||||||
|
sftpgo-data:
|
||||||
|
driver: local
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
-- MySQL initialization for CapacityReport.
|
-- MySQL initialization for CapacityReport.
|
||||||
-- This file runs only when the MySQL data directory is empty.
|
-- This file runs only when the MySQL data directory is empty.
|
||||||
|
-- 建两个库:CapacityReport(主仓库/容量结果)与 celldata(CellData 小区/扇区)。
|
||||||
|
-- 仅建库;具体表由应用前置检查(app/db_init.py + db_init/)按需创建。
|
||||||
|
|
||||||
CREATE DATABASE IF NOT EXISTS CapacityReport
|
CREATE DATABASE IF NOT EXISTS CapacityReport
|
||||||
CHARACTER SET utf8mb4
|
CHARACTER SET utf8mb4
|
||||||
COLLATE utf8mb4_unicode_ci;
|
COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
USE CapacityReport;
|
CREATE DATABASE IF NOT EXISTS celldata
|
||||||
|
CHARACTER SET utf8mb4
|
||||||
|
COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
SELECT 'CapacityReport database initialized with utf8mb4 charset' AS status;
|
SELECT 'CapacityReport & celldata databases initialized with utf8mb4 charset' AS status;
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"username": "capacity",
|
||||||
|
"password": "capacity123",
|
||||||
|
"status": 1,
|
||||||
|
"home_dir": "/srv/sftpgo/data/capacity",
|
||||||
|
"permissions": {
|
||||||
|
"/": ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user