diff --git a/README.md b/README.md index f907b86..4eb697b 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,67 @@ -# XuqmGroup Private Deploy - -私有化部署仓库只负责客户环境交付,不包含业务源码和 demo 前后端。 +# XuqmGroup 私有化部署 ## 快速开始 ```bash -./scripts/configure.sh -vim .env -vim config/secrets.env -./scripts/install.sh --profile base -./scripts/healthcheck.sh +curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh \ + -o install.sh && bash install.sh ``` -生产部署前必须完成: +脚本自动完成:依赖检测 → 配置生成 → 镜像拉取 → 容器启动 → 租户初始化(新建或迁移)→ 全量验证。 -- 配置镜像仓库 `REGISTRY` 和版本 `IMAGE_TAG`。 -- 选择 MySQL/Redis 模式:`external` 使用客户自备服务,`managed` 由脚本创建容器服务。 -- 配置控制台、文档站、文件、IM、Push、Update、License 域名。 -- 配置 SMTP、Push 厂商、应用市场发布凭据。 -- 确认证书和反向代理策略,默认 Nginx 配置只作为模板入口。 +部署完成后根据输出的端口表配置宿主机 nginx,详见 [docs/runbook.md](docs/runbook.md)。 -## 部署模式 +## 部署架构 -MySQL、Redis 支持两种模式: - -- `external`:客户自备连接,脚本只校验连通性和权限。 -- `managed`:脚本新建服务,自动创建数据库、账号、密码和数据目录。 - -生产环境默认推荐 `external/external`。 - -托管模式示例: - -```bash -./scripts/install.sh --profile base --mysql-mode managed --redis-mode managed +``` +用户 nginx(宿主机) + │ + ├── 127.0.0.1:11224 tenant-service /api/ /actuator/ + ├── 127.0.0.1:11225 file-service /file/ + ├── 127.0.0.1:11226 tenant-web / + ├── 127.0.0.1:11227 ops-web /ops + ├── 127.0.0.1:11228 im-service /api/im/ /ws/im + ├── 127.0.0.1:11229 update-service /api/v1/updates/ /api/v1/rn/ + ├── 127.0.0.1:11230 license-service /api/license/ + └── 127.0.0.1:11231 push-service (厂商回调,按需) ``` -外部模式示例: +各服务仅绑定 `127.0.0.1`,外部无法直接访问,只有宿主机 nginx 能代理进去。 -```bash -./scripts/install.sh --profile base --mysql-mode external --redis-mode external -``` +## 租户初始化方式 -## 可选服务 +安装脚本启动后交互式选择: -- `base`:基础控制台、运营平台、文档站、文件服务。 -- `im`:IM HTTP / WebSocket。 -- `push`:厂商推送。 -- `update`:版本管理、RN 热更新、应用市场自动发布。 -- `license`:License 校验。 +- **新建租户**:填写邮箱、用户名、密码,首次启动自动创建 +- **迁移租户**:在公有化平台安全中心生成迁移密钥(`pmk_` 开头),粘贴后自动完成导入 -后期启用: +## 服务说明 + +| Profile | 服务 | 说明 | +|---------|------|------| +| base | tenant-service, file-service, tenant-web, ops-web | 必选核心服务 | +| infra-mysql | mysql | 托管数据库 | +| infra-redis | redis | 托管缓存 | +| im | im-service | IM HTTP + WebSocket | +| push | push-service | 厂商推送 | +| update | update-service | 版本管理 + RN 热更新 | +| license | license-service | License 校验 | +| nginx-bundled | nginx | 内置 nginx(默认不启动,用户有宿主机 nginx 时不需要) | + +## 后期启用/禁用服务 ```bash ./scripts/enable-service.sh im -./scripts/enable-service.sh push -./scripts/enable-service.sh update -./scripts/enable-service.sh license -``` - -禁用服务只修改部署配置并停止对应容器,不删除数据: - -```bash ./scripts/disable-service.sh im ``` -## 租户迁移 - -将公有化平台的存量租户迁移到私有化部署(需源 MySQL 网络可达): - -```bash -./scripts/migrate-tenant.sh \ - --src-host <生产MySQL地址> \ - --src-user <用户名> \ - --src-password '<密码>' \ - --tenant <租户邮箱或用户名> -``` - -加 `--dry-run` 只打印 SQL 不执行。详见 `docs/runbook.md`。 - ## 注意事项 -- `tenant-service` 运行在容器内 **9001** 端口,nginx 代理必须指向该端口,不是 8080。 -- `application.yml` 中数据库 URL 硬编码了生产地址,私有化部署依赖 `docker-compose.yml` 中的 `SPRING_DATASOURCE_*` 覆盖,不能删除 `environment:` 节。 -- `docs-site` 镜像可选,不存在时 nginx 和 healthcheck 可正常工作(warn 级别)。 +- `application.yml` 中数据库 URL 硬编码了生产地址,`docker-compose.yml` 的 `environment:` 节负责覆盖,**不能删除** +- 所有容器绑定 `127.0.0.1`,nginx 中 `proxy_pass` 必须写 `127.0.0.1:1122x`,不能写 `localhost`(部分系统 localhost 解析为 IPv6) -## 接手入口 +## 文档 -- 实时部署进度:`.deploy-state/progress.md` -- 最近运行状态:`.deploy-state/current.json` -- 最近健康检查:`.deploy-state/last-healthcheck.json` -- 脚本审计日志:`logs/audit.log` -- 交付说明:`docs/runbook.md` -- 配置说明:`docs/configuration.md` -- 验收清单:`docs/acceptance-checklist.md` +- [运行手册](docs/runbook.md) — 完整部署流程、nginx 配置、常用运维命令 +- [配置说明](docs/configuration.md) — 各配置文件字段说明 +- [验收清单](docs/acceptance-checklist.md) — 交付验收检查项 diff --git a/docs/acceptance-checklist.md b/docs/acceptance-checklist.md index 7a1310b..a7ccd62 100644 --- a/docs/acceptance-checklist.md +++ b/docs/acceptance-checklist.md @@ -1,36 +1,50 @@ # 验收清单 -## 基础部署 +## 部署流程 -- `./scripts/configure.sh` 可重复执行。 -- `./scripts/install.sh --profile base` 可完成部署。 -- `./scripts/healthcheck.sh` 输出 `PASS` 或明确错误码。 -- 文档站加载 `config/sdk/xuqm-private-sdk.json`。 -- 租户注册入口关闭。 -- 首次启动自动创建内置租户。 +- [ ] `install.sh` 可一键完成完整部署(含租户初始化) +- [ ] 新建租户模式:账号可正常登录控制台 +- [ ] 迁移租户模式:使用迁移密钥(`pmk_`)完成导入,账号和应用数据完整 +- [ ] 部署完成后输出端口表和 nginx 参考配置 -## 中间件 +## 基础服务 -- `external` MySQL/Redis 不启动本地容器。 -- `managed` MySQL/Redis 自动启动并持久化数据。 -- 托管模式自动生成密码并写入 `config/secrets.env`。 +- [ ] tenant-service 健康:`curl http://127.0.0.1:11224/actuator/health` 返回 200 +- [ ] 控制台前端可访问:`curl http://127.0.0.1:11226` 返回 HTML +- [ ] 运营后台可访问:`curl http://127.0.0.1:11227` 返回 HTML +- [ ] 文件服务可访问:`curl http://127.0.0.1:11225/file/health` 返回正常 +- [ ] 私有化模式确认:`/api/private/deployment/status` 返回 `"mode":"PRIVATE"` +- [ ] 注册入口关闭:`"tenantRegisterEnabled":false` ## 可选服务 -- `im` 可后期独立启用和禁用。 -- `push` 可后期独立启用和禁用。 -- `update` 可后期独立启用和禁用。 -- `license` 可后期独立启用和禁用。 -- 禁用任一可选服务时,基础服务可继续运行。 +- [ ] im-service 健康:`curl http://127.0.0.1:11228/actuator/health` 返回 200 +- [ ] update-service 健康:`curl http://127.0.0.1:11229/actuator/health` 返回 200 +- [ ] license-service 健康:`curl http://127.0.0.1:11230/actuator/health` 返回 200 +- [ ] push-service 已启动(厂商凭据按需填写) -## 厂商能力 +## 中间件 -- Push 支持华为、小米、OPPO、vivo、荣耀。 -- 应用市场自动发布支持华为、小米、OPPO、vivo、荣耀。 -- 厂商凭据缺失时返回明确诊断,不影响基础服务启动。 +- [ ] MySQL managed 模式:容器自动启动,数据目录 `data/mysql/` 持久化 +- [ ] Redis managed 模式:容器自动启动,AOF 持久化 +- [ ] 重启容器后数据完整 + +## License + +- [ ] 所有应用在 `app_licenses` 表有对应记录 +- [ ] `/api/license/admin/apps/:appKey` 返回 200,不出现 404 + +## Nginx 配置 + +- [ ] 宿主机 nginx 配置后,通过外部地址可访问控制台 +- [ ] `/api/im/` 路由到 im-service(11228) +- [ ] `/ws/im` WebSocket 连接正常(需 `Upgrade` 头) +- [ ] `/api/v1/updates/` 路由到 update-service(11229),不被 `/api/` 拦截 +- [ ] `/api/license/` 路由到 license-service(11230),不被 `/api/` 拦截 +- [ ] `/file/` 支持大文件上传(500MB) ## 公有化隔离 -- 公有化域名 `dev.xuqinmin.com` 不写入私有化 SDK 配置。 -- 私有化改造不影响公有化配置和部署链路。 -- 公有化回归通过后才能发布私有化版本。 +- [ ] SDK 配置不包含公有化地址 `dev.xuqinmin.com` +- [ ] `config/sdk/xuqm-private-sdk.json` 中所有 URL 指向私有部署地址 +- [ ] 私有化改造不影响公有化配置和部署链路 diff --git a/docs/configuration.md b/docs/configuration.md index 51c4559..7d15044 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2,35 +2,32 @@ ## `.env` -部署入口配置,控制镜像版本、服务 profile、域名和 MySQL/Redis 模式。 +主配置文件,由 `install.sh` 自动生成,控制镜像版本、启用的服务和中间件连接信息。 关键字段: -- `REGISTRY`:私有 Docker 镜像仓库。 -- `IMAGE_TAG`:本次部署镜像版本。 -- `COMPOSE_PROFILES`:启用的服务集合,例如 `base,im,push,update,license`。 -- `MYSQL_MODE`:`external` 或 `managed`。 -- `REDIS_MODE`:`external` 或 `managed`。 -- `ENABLE_IM`、`ENABLE_PUSH`、`ENABLE_UPDATE`、`ENABLE_LICENSE`:运行时功能开关。 +| 字段 | 说明 | +|------|------| +| `REGISTRY` | Docker 镜像仓库地址 | +| `IMAGE_TAG` | 镜像版本,默认 `latest` | +| `COMPOSE_PROFILES` | 启用的服务集合,默认 `base,infra-mysql,infra-redis,im,push,update,license` | +| `MYSQL_MODE` | `managed`(容器托管)或 `external`(客户自备) | +| `REDIS_MODE` | `managed` 或 `external` | +| `CONSOLE_DOMAIN` | 对外访问地址,用于服务间跳转和 SDK 配置 | ## `config/secrets.env` -敏感配置文件,不提交 Git。 +敏感配置,权限 600,不提交 Git。 -关键字段: - -- `MYSQL_PASSWORD` -- `MYSQL_ROOT_PASSWORD` -- `REDIS_PASSWORD` -- `SMTP_PASSWORD` - -托管模式下,如果密码为空或为 `change-me`,脚本会自动生成并写回该文件。 +| 字段 | 说明 | +|------|------| +| `MYSQL_ROOT_PASSWORD` | MySQL root 密码 | +| `MYSQL_PASSWORD` | 业务账号密码 | +| `REDIS_PASSWORD` | Redis 密码 | ## `config/xuqm.env` -业务服务共享配置,包含私有化运行模式、单租户初始化、域名和基础中间件连接信息。 - -私有化必须保持: +业务服务容器内配置,所有服务共享。私有化部署必须保持: ```env DEPLOYMENT_MODE=PRIVATE @@ -38,14 +35,26 @@ TENANT_REGISTER_ENABLED=false TENANT_BOOTSTRAP_ENABLED=true ``` -## Spring Boot 数据库 URL 覆盖(重要) +SDK 对外地址也在此文件配置: -`tenant-service` 和 `file-service` 的 `application.yml` 中数据库 URL 编译期写死了生产地址。 -私有化部署**必须**通过 `docker-compose.yml` 的 `environment:` 节覆盖 Spring Boot 配置: +```env +CONSOLE_DOMAIN=http://your-domain-or-ip +SDK_FILE_SERVICE_URL=http://your-domain-or-ip +SDK_IM_API_URL=http://your-domain-or-ip +SDK_IM_WS_URL=ws://your-domain-or-ip/ws/im +``` + +## `config/tenant/bootstrap.env` + +初始租户配置,权限 600。迁移模式下由迁移流程自动覆盖。 + +## Spring Boot 数据库 URL 覆盖 + +`application.yml` 中数据库 URL 硬编码了生产地址。私有化部署**必须**通过 `docker-compose.yml` 的 `environment:` 节覆盖: ```yaml environment: - SPRING_DATASOURCE_URL: "jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xuqm_private}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true" + SPRING_DATASOURCE_URL: "jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xuqm_private}?..." SPRING_DATASOURCE_USERNAME: "${MYSQL_USERNAME:-xuqm}" SPRING_DATASOURCE_PASSWORD: "${MYSQL_PASSWORD}" SPRING_DATA_REDIS_HOST: "${REDIS_HOST}" @@ -54,58 +63,62 @@ environment: SPRING_DATA_REDIS_DATABASE: "${REDIS_DATABASE:-0}" ``` -这些 `${VAR}` 在启动时由 Docker Compose 从 `.env` 文件展开,优先级高于 `env_file:` 中的同名变量。 -当前 `docker-compose.yml` 已包含上述覆盖,不需要手动修改。 +`docker-compose.yml` 已包含此配置,不需要手动修改。 -## Nginx 服务端口 +## 服务端口 -| 服务 | 容器内端口 | nginx 路由 | -|------|-----------|-----------| -| tenant-service | **9001** | `/api/`(兜底),`/actuator/` | -| file-service | **8086** | `/file/` | -| im-service | **8082** | `/api/im/`,`/ws/im/`(WebSocket) | -| push-service | **8083** | 厂商回调(不直接暴露给前端) | -| update-service | **8084** | `/api/v1/updates/`,`/api/v1/rn/` | -| license-service | **8085** | 内部调用 | -| ops-web | 80 | `/ops` | -| tenant-web | 80 | `/`(根路径) | +各服务容器内端口固定,宿主机端口从 11224 顺序分配: -## 可选服务内部通信 +| 宿主机端口 | 服务 | 容器内端口 | nginx 路由 | +|-----------|------|-----------|-----------| +| 11224 | tenant-service | 9001 | `/api/` `/actuator/` | +| 11225 | file-service | 8086 | `/file/` | +| 11226 | tenant-web | 80 | `/`(兜底路由) | +| 11227 | ops-web | 80 | `/ops` | +| 11228 | im-service | 8082 | `/api/im/` `/ws/im` | +| 11229 | update-service | 8084 | `/api/v1/updates/` `/api/v1/rn/` | +| 11230 | license-service | 8085 | `/api/license/` | +| 11231 | push-service | 8083 | 厂商回调(按需) | -im-service 和 update-service 在调用 tenant-service 内部 API 时,需要显式覆盖默认地址: +所有端口绑定 `127.0.0.1`,nginx 需写 `proxy_pass http://127.0.0.1:1122x`。 + +## 容器内部通信 + +容器间通过 Docker 网络直接使用服务名,不经过宿主机端口: ```yaml # im-service -environment: - TENANT_SERVICE_URL: "http://tenant-service:9001" - PUSH_SERVICE_URL: "http://push-service:8083" +TENANT_SERVICE_URL: "http://tenant-service:9001" +PUSH_SERVICE_URL: "http://push-service:8083" # update-service -environment: - SDK_TENANT_SERVICE_URL: "http://tenant-service:9001" +SDK_TENANT_SERVICE_URL: "http://tenant-service:9001" ``` -push-service 默认已使用 `http://tenant-service:9001`,无需额外配置。 +`docker-compose.yml` 已包含上述配置,不需要手动修改。 -`docker-compose.yml` 已包含上述覆盖,不需要手动修改。 +## 内置 nginx(可选) -## docs-site 镜像 +`nginx-bundled` profile 提供内置 nginx 容器,默认不启动。通常用宿主机自己的 nginx 代理到各服务端口。需要内置 nginx 时: -`docs-site` 镜像在部分 ACR namespace 下不存在。`docker-compose.yml` 已将 nginx 对 `docs-site` 的依赖标记为 `required: false`,镜像缺失时 nginx 仍可正常启动,`healthcheck.sh` 将 docs-site 容器计为可选(WARN 而非 FAIL)。 +```env +# .env +COMPOSE_PROFILES=base,infra-mysql,infra-redis,im,push,update,license,nginx-bundled +``` -## `config/sdk/xuqm-private-sdk.json` +内置 nginx 绑定宿主机 80/443 端口,与宿主机已有 nginx 冲突时不可同时使用。 -私有化 SDK 初始化配置,由 `scripts/render-config.sh` 生成。 +## `config/vendors/` -文档站和客户应用示例必须使用该文件,不再指向 `dev.xuqinmin.com` 公有化逻辑。 - -## `config/vendors` - -厂商能力配置: - -- `push.env`:华为、小米、OPPO、vivo、荣耀 Push 凭据。 -- `store-submit.env`:华为、小米、OPPO、vivo、荣耀应用市场自动发布凭据。 +| 文件 | 说明 | +|------|------| +| `push.env` | 华为/小米/OPPO/vivo/荣耀/APNs/FCM 推送凭据,默认全部 `false` | +| `store-submit.env` | 应用市场自动发布凭据,默认全部 `false` | ## `config/mail/smtp.env` -邮件服务配置。生产环境必须使用客户提供的 SMTP 服务。 +邮件服务配置,不填则邮件功能不可用,不影响其他服务启动。 + +## `config/sdk/xuqm-private-sdk.json` + +SDK 初始化配置,由 `deploy.sh` 自动生成,客户端应用使用此文件初始化 SDK,不再指向公有化地址。 diff --git a/docs/deployment-defaults.md b/docs/deployment-defaults.md index 920576c..b6f546e 100644 --- a/docs/deployment-defaults.md +++ b/docs/deployment-defaults.md @@ -1,6 +1,6 @@ -# 私有化部署默认信息 +# 部署信息记录模板 -本文档记录数字医信私有化部署的默认配置,供运维和对接人员参考。 +部署完成后将此文件复制填写,**不要将含有真实凭据的版本提交到 Git**。 --- @@ -8,24 +8,11 @@ | 项目 | 值 | |------|-----| -| 部署版本 | 2026.05.19-private.1 | -| 部署主机 | 192.168.116.9 | +| 部署版本 | (见 VERSION 文件) | +| 部署主机 | | | 部署目录 | /opt/xuqm-private | -| 部署时间 | 2026-05-19 | - ---- - -## 访问地址 - -| 功能 | 地址 | -|------|------| -| 控制台(租户登录)| http://192.168.116.9 | -| 运营后台 | http://192.168.116.9/ops | -| 文档站 | http://192.168.116.9/docs/ | -| API 入口 | http://192.168.116.9/api/ | -| Actuator 健康 | http://192.168.116.9/actuator/health | - -> **说明**:采用纯 IP 部署,无需配置域名。局域网内任意机器均可通过上述地址访问完整功能。 +| 部署时间 | | +| 外部访问地址 | | --- @@ -33,11 +20,11 @@ | 项目 | 值 | |------|-----| -| 租户名称 | 数字医信 | -| 登录邮箱 | szyx@bjca.org.cn | -| 登录用户名 | szyx | -| 初始密码 | 与公有化平台相同(迁移时未重置) | -| 迁移来源 | 公有化平台(39.107.53.187) | +| 租户名称 | | +| 登录邮箱 | | +| 登录用户名 | | +| 初始密码 | (见 config/secrets.env 或部署时设置) | +| 迁移来源 | 新建 / 公有化平台迁移 | --- @@ -45,76 +32,24 @@ | 应用名称 | App Key | |----------|---------| -| 医网信 | ak_c6fce237cae94ef5ab71fda6 | -| 临床知识库 | ak_1178fd37b8f54cefb7031744 | +| | | --- -## 服务列表和端口 +## 服务端口 -### 对外服务(通过 nginx 统一入口) +| 宿主机端口 | 服务 | 容器内端口 | +|-----------|------|-----------| +| 11224 | tenant-service | 9001 | +| 11225 | file-service | 8086 | +| 11226 | tenant-web | 80 | +| 11227 | ops-web | 80 | +| 11228 | im-service | 8082 | +| 11229 | update-service | 8084 | +| 11230 | license-service | 8085 | +| 11231 | push-service | 8083 | -| 服务名 | 内部端口 | nginx 路由路径 | 说明 | -|--------|----------|----------------|------| -| tenant-service | 9001 | `/api/*` `/actuator/*` | 核心 API,认证、租户、SDK 配置 | -| file-service | 8086 | `/file/*` | 文件上传下载,最大 500MB | -| im-service | 8082 | `/api/im/*` `/ws/im/*` | IM HTTP API 和 WebSocket | -| update-service | 8084 | `/api/v1/updates/*` `/api/v1/rn/*` | APP 版本管理和 RN 热更新 | -| license-service | 8085 | 内部调用 | License 有效期校验 | -| push-service | 8083 | 内部调用 | 厂商推送通知 | -| docs-site | 80 | `/docs/*` | 私有化 SDK 文档站 | -| ops-web | 80 | `/ops` | 运营后台前端 | -| tenant-web | 80 | `/` | 控制台前端(兜底路由) | - -### 基础设施(Docker 内部,不对外暴露) - -| 服务名 | 内部端口 | 模式 | 说明 | -|--------|----------|------|------| -| mysql | 3306 | managed | MySQL 8.4,Docker 容器托管 | -| redis | 6379 | managed | Redis 7.4,AOF 持久化 | - ---- - -## Docker Compose Profiles - -| Profile | 包含服务 | 说明 | -|---------|----------|------| -| base | tenant-service, file-service, tenant-web, ops-web, docs-site, nginx | 必选核心服务 | -| infra-mysql | mysql | 托管数据库(MYSQL_MODE=managed 时启用) | -| infra-redis | redis | 托管缓存(REDIS_MODE=managed 时启用) | -| im | im-service | IM 服务(可选) | -| push | push-service | 推送服务(可选) | -| update | update-service | 版本管理服务(可选) | -| license | license-service | License 服务(可选) | - -**当前启用的 Profiles**:`base,infra-mysql,infra-redis,im,push,update,license`(全量部署) - ---- - -## 数据库 - -| 项目 | 值 | -|------|-----| -| 主机 | mysql(Docker 服务名) | -| 端口 | 3306 | -| 数据库名 | xuqm_private | -| 业务账号 | xuqm | -| 业务密码 | XuqmMysql@2026 | -| Root 密码 | XuqmRoot@2026 | -| 字符集 | utf8mb4 / utf8mb4_unicode_ci | -| 时区 | +08:00 | - ---- - -## Redis - -| 项目 | 值 | -|------|-----| -| 主机 | redis(Docker 服务名) | -| 端口 | 6379 | -| 数据库 | 0 | -| 密码 | XuqmRedis@2026 | -| 持久化 | AOF(appendonly yes) | +宿主机 nginx 配置参考见 [docs/runbook.md](runbook.md)。 --- @@ -122,80 +57,35 @@ | 路径 | 说明 | |------|------| -| `./data/mysql/` | MySQL 数据文件(重启后保留) | -| `./data/redis/` | Redis AOF 文件(重启后保留) | -| `./data/uploads/` | 文件服务上传目录 | -| `./data/update/` | 版本管理包存储目录 | -| `./data/backups/` | 迁移备份 | -| `./logs/` | 审计日志 | -| `./.deploy-state/` | 部署状态和验证结果 | - ---- - -## 配置文件清单 - -| 文件 | 说明 | -|------|------| -| `.env` | 主配置文件(COMPOSE_PROFILES、域名、功能开关) | -| `config/secrets.env` | 敏感凭据(chmod 600) | -| `config/xuqm.env` | 业务服务容器内配置 | -| `config/tenant/bootstrap.env` | 初始租户配置(迁移后由真实数据替换) | -| `config/nginx/conf.d/xuqm.conf` | Nginx 路由配置 | -| `config/sdk/xuqm-private-sdk.json` | SDK 初始化配置文件 | -| `config/docs/docs-runtime.json` | 文档站运行时配置 | -| `config/vendors/push.env` | 推送厂商凭据(默认全部关闭) | -| `config/vendors/store-submit.env` | 应用市场发布凭据(默认全部关闭) | -| `config/mail/smtp.env` | 邮件服务配置 | +| `data/mysql/` | MySQL 数据文件 | +| `data/redis/` | Redis AOF 文件 | +| `data/uploads/` | 文件服务上传目录 | +| `data/update/` | 版本管理包存储 | +| `data/backups/` | 备份文件 | +| `logs/` | 审计日志 | --- ## 常用运维命令 ```bash -# 进入部署目录 -cd /opt/xuqm-private - # 查看所有容器状态 docker compose -f docker-compose.yml -f docker-compose.infra.yml ps -# 查看某个服务日志 +# 查看服务日志 docker compose -f docker-compose.yml -f docker-compose.infra.yml logs --tail 100 tenant-service -# 运行一键验证 +# 运行全量验证 bash scripts/verify.sh -# 重新部署(幂等) -DEPLOY_HOST=192.168.116.9 bash scripts/deploy-szyx.sh - -# 手动迁移租户 -bash scripts/migrate-tenant.sh \ - --src-host 39.107.53.187 \ - --src-user xuqm \ - --src-password Xuqm@2026 \ - --src-db xuqm_tenant \ - --tenant szyx@bjca.org.cn - # 停止所有服务(保留数据) docker compose -f docker-compose.yml -f docker-compose.infra.yml down - -# 停止并清除所有数据(!不可恢复) -docker compose -f docker-compose.yml -f docker-compose.infra.yml down -v ``` --- -## 验证结果 - -验证报告保存在 `.deploy-state/last-verify.json`,包含所有检查项的 PASS / WARN / FAIL 状态。 - -详细验证步骤见 [docs/acceptance-checklist.md](acceptance-checklist.md)。 - ---- - ## 注意事项 -1. **注册功能已禁用**:`TENANT_REGISTER_ENABLED=false`,任何人都无法自行注册账号,只能用迁移的账号登录。 -2. **纯 IP 部署**:所有服务通过 `http://192.168.116.9` 访问,如需 HTTPS,请配置 SSL 证书并修改 nginx 配置(见 `docs/runbook.md`)。 -3. **数据持久化**:MySQL 和 Redis 数据存储在宿主机 `./data/` 目录,容器重启不丢失。重装需手动清除。 -4. **推送服务**:push-service 已启动,但各厂商推送默认关闭,需在 `config/vendors/push.env` 填写凭据并重启。 -5. **中文字符集**:所有服务使用 utf8mb4,JDBC 连接串包含 `characterEncoding=UTF-8`,中文数据正常存储。 +1. **注册功能已禁用**:`TENANT_REGISTER_ENABLED=false`,只能用初始化的账号登录。 +2. **数据持久化**:MySQL 和 Redis 数据存储在 `data/` 目录,容器重启不丢失。 +3. **推送服务**:push-service 已启动,各厂商推送默认关闭,需填写 `config/vendors/push.env` 并重启。 diff --git a/docs/runbook.md b/docs/runbook.md index 2678c6a..508e965 100644 --- a/docs/runbook.md +++ b/docs/runbook.md @@ -1,106 +1,135 @@ # 私有化部署运行手册 -## 目标 - -本仓库用于客户私有环境交付,只编排已有 Docker 镜像,不包含业务源码、不构建 demo 服务。 - -## 标准流程 - -1. 执行 `./scripts/configure.sh` 生成 `.env` 和 `config/secrets.env`。 -2. 修改 `.env`:镜像仓库、镜像版本、域名、可选服务、MySQL/Redis 模式。 -3. 修改 `config/secrets.env`:数据库密码、Redis 密码、SMTP 密码等敏感配置。 -4. 修改 `config/mail/smtp.env`、`config/vendors/*.env`。 -5. 执行 `./scripts/install.sh --profile base` 部署基础服务。 -6. 按需执行 `./scripts/enable-service.sh im|push|update|license` 启用可选服务。 -7. 执行 `./scripts/healthcheck.sh` 并检查 `.deploy-state/last-healthcheck.json`。 - -## MySQL/Redis 模式 - -`external` 模式: - -- 客户提供连接地址、账号、密码、数据库名。 -- 部署脚本只使用连接配置,不启动新服务。 -- 生产默认使用该模式。 - -`managed` 模式: - -- 部署脚本通过 Docker Compose 启动 MySQL/Redis。 -- 密码为空或为 `change-me` 时自动生成并写入 `config/secrets.env`。 -- 数据目录写入 `data/mysql` 和 `data/redis`。 - -## 可选服务 - -`im`、`push`、`update`、`license` 均可不部署,后期独立启用。 - -启用命令: +## 一键部署 ```bash -./scripts/enable-service.sh im -./scripts/install.sh --profile base,im +curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh \ + -o install.sh && bash install.sh ``` -禁用命令: +交互式向导依次完成: + +1. 选择租户初始化方式(新建 / 迁移) +2. 填写租户信息或迁移密钥 +3. 填写外部访问地址(宿主机 nginx 对外的地址,用于 SDK 配置) +4. 自动完成容器启动、数据库初始化、全量验证 + +完成后按输出的端口表配置宿主机 nginx。 + +--- + +## Nginx 配置 + +部署完成后,将以下 location 块加入宿主机 nginx 的 server 配置: + +```nginx +charset utf-8; +client_max_body_size 100m; + +location /api/v1/updates/ { proxy_pass http://127.0.0.1:11229/api/v1/updates/; } +location /api/v1/rn/ { proxy_pass http://127.0.0.1:11229/api/v1/rn/; } +location /api/im/ { proxy_pass http://127.0.0.1:11228/api/im/; } +location /ws/im { + proxy_pass http://127.0.0.1:11228/ws/im; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 3600s; +} +location /api/license/ { proxy_pass http://127.0.0.1:11231/api/license/; } +location /file/ { + proxy_pass http://127.0.0.1:11225/file/; + client_max_body_size 500m; + proxy_read_timeout 300s; +} +location /api/ { proxy_pass http://127.0.0.1:11224/api/; } +location /actuator/ { proxy_pass http://127.0.0.1:11224/actuator/; } +location /ops { proxy_pass http://127.0.0.1:11227; } +location / { proxy_pass http://127.0.0.1:11226; } +``` + +> location 顺序不可颠倒:精确路径(`/api/im/`、`/api/v1/`、`/api/license/`)必须在通用路径(`/api/`)前面。 + +--- + +## 端口对照表 + +| 宿主机端口 | 服务 | 容器内端口 | 说明 | +|-----------|------|-----------|------| +| 11224 | tenant-service | 9001 | 核心 API | +| 11225 | file-service | 8086 | 文件上传下载 | +| 11226 | tenant-web | 80 | 控制台前端 | +| 11227 | ops-web | 80 | 运营后台前端 | +| 11228 | im-service | 8082 | IM HTTP + WebSocket | +| 11229 | update-service | 8084 | 版本管理 + RN 热更新 | +| 11230 | license-service | 8085 | License 校验 | +| 11231 | push-service | 8083 | 厂商推送 | + +所有端口绑定 `127.0.0.1`,外部不可直接访问。 + +--- + +## 租户迁移 + +迁移通过一键部署向导完成,选择「迁移租户」后: + +1. 前往公有化平台控制台 → 安全中心 → 私有化部署迁移 → 生成迁移密钥 +2. 将 `pmk_` 开头的密钥粘贴进向导 +3. 脚本自动导出租户数据、导入私有库、写入 license 记录、重启服务 + +迁移为单租户操作,会清空现有 bootstrap 数据后写入迁移数据。 + +--- + +## 常用运维命令 ```bash -./scripts/disable-service.sh im +# 查看所有容器状态 +docker compose -f docker-compose.yml -f docker-compose.infra.yml ps + +# 查看服务日志 +docker compose -f docker-compose.yml -f docker-compose.infra.yml logs --tail 100 tenant-service + +# 重新运行全量验证 +bash scripts/verify.sh + +# 停止所有服务(保留数据) +docker compose -f docker-compose.yml -f docker-compose.infra.yml down + +# 启用可选服务 +bash scripts/enable-service.sh im + +# 禁用可选服务(不删数据) +bash scripts/disable-service.sh im + +# 备份数据 +bash scripts/backup.sh + +# 恢复数据 +bash scripts/restore.sh ``` -禁用服务不会删除数据,重新启用后继续使用原配置和数据目录。 +--- -## 租户迁移(公有化 → 私有化) +## 数据目录 -将公有化平台的存量租户迁移到私有化部署。 +| 路径 | 说明 | +|------|------| +| `data/mysql/` | MySQL 数据文件 | +| `data/redis/` | Redis AOF 文件 | +| `data/uploads/` | 文件服务上传目录 | +| `data/update/` | 版本管理包存储 | +| `data/backups/` | 备份文件 | +| `logs/` | 审计日志 | -### 前提条件 +--- -- 私有化基础服务已通过 `healthcheck.sh`。 -- 源 MySQL 可从部署机器网络连通(`mysql -h SRC_HOST ...` 成功)。 -- 私有化部署为单租户模式:迁移会**清空**当前 bootstrap 租户后写入迁移租户。 +## 重新部署(幂等) -### 执行迁移 +脚本幂等,可重复执行: ```bash -# Dry-run 确认要迁移的数据 -./scripts/migrate-tenant.sh \ - --src-host <生产MySQL> \ - --src-user <用户名> \ - --src-password '<密码>' \ - --src-db xuqm_tenant \ - --tenant <租户邮箱或用户名> \ - --dry-run - -# 确认无误后正式执行 -./scripts/migrate-tenant.sh \ - --src-host <生产MySQL> \ - --src-user <用户名> \ - --src-password '<密码>' \ - --src-db xuqm_tenant \ - --tenant <租户邮箱或用户名> +bash install.sh ``` -迁移脚本会自动: -1. 从源库导出 `t_tenant`、`t_app`、`t_feature_service`(含厂商配置)。 -2. 用显式列名 INSERT 规避生产与私有化 MySQL 的列序差异。 -3. 清空私有化部署的 bootstrap 租户后写入迁移数据。 -4. 重启 `tenant-service` 清空内存缓存。 -5. 通过 `/api/sdk/config` 和 `/api/private/deployment/status` 验证结果。 - -### 验证 - -```bash -# SDK config 应返回 200 -curl "http://DEPLOY_HOST/api/sdk/config?appKey=&platform=ANDROID" - -# 部署状态应为 PRIVATE,注册应为 false -curl "http://DEPLOY_HOST/api/private/deployment/status" -``` - -## 接手规则 - -任何 agent 开始执行前必须先查看: - -- `.deploy-state/progress.md` -- `.deploy-state/current.json` -- `logs/audit.log` - -执行关键步骤后必须追加进度,确保中断后可继续。 +已运行的容器不会被重建,数据目录不受影响。