docs: 部署文档
- README:项目概览、快速开始、目录结构、重要提示 - 01 环境准备:硬件/系统/Docker 版本、镜像仓库、端口、防火墙、可选外部服务 - 02 配置说明:.env 必填与可选项、10 份应用配置逐项说明、启动前自检 - 03 启动与验证:首次初始化流程、状态检查、6 步验证清单、首次登录必做项 - 04 可选服务:挡板 onelink-mock、飞书 bot、自带 nginx(含 HTTPS)、组合启动 - 05 升级与备份:版本固定、升级回滚、备份脚本与恢复、日志清理、监控指标 - 06 故障排查:启动/功能/性能/网络四类共 20 个问题
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# IotLCM 部署仓
|
||||
|
||||
IotLCM 物联网卡管理平台的部署编排与数据库初始化脚本。使用 Docker Compose 在单机上拉起完整平台。
|
||||
|
||||
## 部署内容
|
||||
|
||||
| 类别 | 服务 |
|
||||
| --- | --- |
|
||||
| 基础组件 | MySQL、Redis、RabbitMQ、Consul |
|
||||
| 业务服务 | admin-svr(管理端后端)、admin-ui(管理端前端)、openapi(对外 API)、app-server(小程序后端)、app-web(小程序前端)、upstream-chan(运营商对接)、upstream-proxy(通道缓存转发)、worker-svr(异步任务)、sms(短信)、docs(文档站) |
|
||||
| 可选 | onelink-mock(运营商接口挡板)、bot(飞书通知)、nginx(反向代理) |
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 1. 准备环境变量
|
||||
cp .env.example .env
|
||||
vi .env # 填镜像仓库、各项口令
|
||||
|
||||
# 2. 准备配置
|
||||
cp -r config.example config
|
||||
vi config/*/config.yaml # 逐份填写(标注「必改」的项)
|
||||
|
||||
# 3. 启动
|
||||
docker compose up -d
|
||||
|
||||
# 4. 查看状态
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
首次启动会自动建库并导入 schema,MySQL 初始化约需 1~2 分钟。等待 `iotlcm-mysql` 健康后其余服务才会启动。
|
||||
|
||||
启动完成后访问 `http://<宿主机IP>:8009`,账号 `admin`,口令为 `.env` 中的 `MYSQL_ADMIN_PASSWORD`。
|
||||
|
||||
## 文档
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [环境准备](docs/01-环境准备.md) | 硬件、系统、Docker 版本要求 |
|
||||
| [配置说明](docs/02-配置说明.md) | `.env` 与 `config/` 各项含义 |
|
||||
| [启动与验证](docs/03-启动与验证.md) | 启动流程、健康检查、首次登录 |
|
||||
| [可选服务](docs/04-可选服务.md) | 挡板、飞书通知、自带反向代理 |
|
||||
| [升级与备份](docs/05-升级与备份.md) | 版本固定、升级、数据备份 |
|
||||
| [故障排查](docs/06-故障排查.md) | 常见问题与处理 |
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
iotlcm-deploy/
|
||||
├── docker-compose.yml # 服务编排
|
||||
├── .env.example # 环境变量模板 → 复制为 .env
|
||||
├── config.example/ # 配置模板 → 复制为 config/
|
||||
│ ├── admin-svr/
|
||||
│ ├── admin-ui/
|
||||
│ ├── app-server/
|
||||
│ ├── bot/
|
||||
│ ├── nginx/
|
||||
│ ├── openapi/
|
||||
│ ├── sms/
|
||||
│ ├── upstream-chan/
|
||||
│ ├── upstream-proxy/
|
||||
│ └── worker-svr/
|
||||
├── schema/ # 数据库初始化脚本(首次启动自动执行)
|
||||
├── docs/ # 部署文档
|
||||
├── config/ # 实际配置(不入版本库)
|
||||
└── data/ # 运行数据(不入版本库)
|
||||
```
|
||||
|
||||
`config/` 与 `data/` 在 `.gitignore` 中,不会被提交。
|
||||
|
||||
## 重要提示
|
||||
|
||||
- **`JWT_SIGNING_KEY` 必须在 `admin-svr`、`openapi`、`app-server` 三者间完全一致**,否则令牌跨服务不通
|
||||
- **镜像标签不要用 `latest`**,生产环境请固定到具体版本
|
||||
- **改 `schema/` 下的脚本不会自动生效**,需要清空 `data/mysql` 重新初始化(会丢失全部数据)
|
||||
- 默认只监听 `127.0.0.1` 的服务需通过反向代理对外,见[可选服务](docs/04-可选服务.md)
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
# 环境准备
|
||||
|
||||
## 硬件要求
|
||||
|
||||
按数据规模选择配置:
|
||||
|
||||
| 场景 | CPU | 内存 | 磁盘 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 试用 / 演示 | 2 核 | 4 GB | 40 GB | 少量卡片,关闭定时任务 |
|
||||
| 生产(中小规模) | 4 核 | 8 GB | 200 GB | 万级卡片,开启全量同步 |
|
||||
| 生产(大规模) | 8 核+ | 16 GB+ | 500 GB+ | 十万级卡片,建议数据库独立部署 |
|
||||
|
||||
磁盘估算:MySQL 数据约为卡片数的 1~2 KB/张;日志按每日同步任务量增长,建议单独挂载并配置轮转。
|
||||
|
||||
内存分配参考(生产 8 GB 场景):
|
||||
|
||||
| 服务 | 大致占用 |
|
||||
| --- | --- |
|
||||
| MySQL | 1~2 GB |
|
||||
| Redis | 200~500 MB |
|
||||
| RabbitMQ | 300~500 MB |
|
||||
| worker-svr | 500 MB~1 GB(与并发同步的卡片数相关) |
|
||||
| 其余业务服务 | 每个 100~200 MB |
|
||||
|
||||
## 系统要求
|
||||
|
||||
| 项 | 要求 |
|
||||
| --- | --- |
|
||||
| 操作系统 | Linux x86_64(CentOS 7+ / Ubuntu 20.04+ / Debian 11+) |
|
||||
| 内核 | 3.10 以上 |
|
||||
| 文件系统 | ext4 / xfs |
|
||||
| 时区 | 建议设为 `Asia/Shanghai`,与 `.env` 中的 `TZ` 保持一致 |
|
||||
|
||||
## Docker 要求
|
||||
|
||||
| 组件 | 最低版本 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| Docker Engine | 20.10 | 需要支持 `healthcheck` 与 `profiles` |
|
||||
| Docker Compose | v2.0(插件版) | `docker compose` 而非 `docker-compose` |
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
docker version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
`docker compose version` 输出的版本号需 ≥ v2.0。若只有 `docker-compose`(v1),请升级到 Compose V2 插件。
|
||||
|
||||
## 镜像仓库
|
||||
|
||||
平台镜像由官方镜像仓库分发,需要:
|
||||
|
||||
1. 能访问镜像仓库地址(内网仓库需先配置网络或代理)
|
||||
2. 具备拉取权限(私有仓库需先登录)
|
||||
|
||||
```bash
|
||||
docker login <你的镜像仓库地址>
|
||||
```
|
||||
|
||||
`.env` 中的 `REGISTRY` 填写仓库地址(不含 `https://` 与末尾斜杠):
|
||||
|
||||
```bash
|
||||
REGISTRY=registry.example.com
|
||||
```
|
||||
|
||||
基础组件从 `<REGISTRY>/library/` 拉取(mysql、redis、rabbitmq、consul、nginx),业务镜像从 `<REGISTRY>/iotlcm/` 拉取。
|
||||
|
||||
## 端口
|
||||
|
||||
默认占用的宿主机端口:
|
||||
|
||||
| 端口 | 服务 | 对外 |
|
||||
| --- | --- | --- |
|
||||
| 8000 | openapi | 需经反向代理 |
|
||||
| 8008 | admin-svr | 需经反向代理 |
|
||||
| 8009 | admin-ui | 需经反向代理 |
|
||||
| 8010 | app-server | 需经反向代理 |
|
||||
| 8018 | app-web | 需经反向代理 |
|
||||
| 8019 | docs | 需经反向代理 |
|
||||
| 8080 | onelink-mock | 仅联调时启用 |
|
||||
| 3306 | MySQL | 建议仅内网 |
|
||||
| 6379 | Redis | 建议仅内网 |
|
||||
| 5672 / 15672 | RabbitMQ | 建议仅内网 |
|
||||
| 8500 | Consul | 建议仅内网 |
|
||||
| 8110 / 8310 | upstream-chan | 建议仅内网 |
|
||||
| 8510 | upstream-proxy | 建议仅内网 |
|
||||
| 11190 / 11200 | sms | 建议仅内网 |
|
||||
| 80 | nginx | 启用 with-nginx 时 |
|
||||
|
||||
端口冲突时在 `.env` 中修改对应变量即可,不要直接改 `docker-compose.yml`。
|
||||
|
||||
## 防火墙
|
||||
|
||||
仅需对外开放反向代理端口(默认 80/443)。其余服务端口应限制为内网访问:
|
||||
|
||||
```bash
|
||||
# 示例:firewalld 仅放行 80/443
|
||||
firewall-cmd --permanent --add-service=http
|
||||
firewall-cmd --permanent --add-service=https
|
||||
firewall-cmd --reload
|
||||
```
|
||||
|
||||
## 依赖外部服务(可选)
|
||||
|
||||
| 服务 | 用途 | 是否必需 |
|
||||
| --- | --- | --- |
|
||||
| TDengine 3.x | 存流量历史数据 | 可选。不配置则历史流量查询不可用 |
|
||||
| 短信服务商 | 发送验证码 | 可选。不配置则无法发送短信 |
|
||||
| 微信支付 | 在线支付 | 可选。不配置则支付功能不可用 |
|
||||
| 飞书 | 运维通知 | 可选。不配置则不启动 bot |
|
||||
|
||||
TDengine 需开启 WebSocket 接口(默认 6041 端口),在 `.env` 中配置:
|
||||
|
||||
```bash
|
||||
TDENGINE_HOST=tdengine.example.com
|
||||
TDENGINE_PORT=6041
|
||||
TDENGINE_USER=root
|
||||
TDENGINE_PASSWORD=
|
||||
TDENGINE_DAILY_DB=iotlcm_daily
|
||||
TDENGINE_MONTHLY_DB=iotlcm_monthly
|
||||
```
|
||||
|
||||
不使用时全部留空即可,主流程不受影响。
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
# 配置说明
|
||||
|
||||
平台配置分两层:
|
||||
|
||||
| 层 | 位置 | 管什么 | 是否入库 |
|
||||
| --- | --- | --- | --- |
|
||||
| 部署层 | `.env` | 镜像仓库、口令、端口、外部服务地址 | 否 |
|
||||
| 应用层 | `config/<服务>/config.yaml` | 业务参数、连接串、功能开关 | 否 |
|
||||
|
||||
两者都由 `config.example/` 与 `.env.example` 复制而来,`.gitignore` 已排除。**不要把自己的配置提交回仓库。**
|
||||
|
||||
## 一、`.env`
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 必填项
|
||||
|
||||
| 变量 | 说明 |
|
||||
| --- | --- |
|
||||
| `REGISTRY` | 镜像仓库地址,不含协议与末尾斜杠 |
|
||||
| `TAG` | 镜像标签。生产请用具体版本号,不要用 `latest` |
|
||||
| `MYSQL_ROOT_PASSWORD` | MySQL root 口令 |
|
||||
| `MYSQL_APP_PASSWORD` | 应用账号 `u_iotlcm` 的口令,各服务用它连库 |
|
||||
| `MYSQL_ADMIN_PASSWORD` | 平台 admin 账号的初始登录口令 |
|
||||
| `REDIS_PASSWORD` | Redis 口令 |
|
||||
| `RABBITMQ_PASSWORD` | RabbitMQ 口令 |
|
||||
| `JWT_SIGNING_KEY` | JWT 签名密钥 |
|
||||
|
||||
以上任意一项未设置时,`docker compose` 会直接报错退出,不会用空值或弱口令启动。
|
||||
|
||||
生成强口令:
|
||||
|
||||
```bash
|
||||
openssl rand -base64 24 # 用于各类密码
|
||||
openssl rand -hex 32 # 用于 JWT_SIGNING_KEY
|
||||
```
|
||||
|
||||
::: warning JWT_SIGNING_KEY 必须三处一致
|
||||
`admin-svr`、`openapi`、`app-server` 共用同一个 `JWT_SIGNING_KEY`(都从 `.env` 读取)。不一致的表现是:能登录管理端,但调用外部 API 或小程序端提示未授权。
|
||||
|
||||
**更换此值会使已签发的全部登录态与接口令牌立即失效**,请在维护窗口操作。
|
||||
:::
|
||||
|
||||
### 可选项
|
||||
|
||||
| 变量 | 不填的影响 |
|
||||
| --- | --- |
|
||||
| `DIAGNOSIS_INTERNAL_TOKEN` | 控制台「智能诊断」不可用 |
|
||||
| `SMS_ACCESS_KEY_ID` / `SMS_ACCESS_KEY_SECRET` | 无法发送短信验证码 |
|
||||
| `FEISHU_APP_ID` / `SECRET` / `CHAT_ID` | 不启动 bot 服务即可 |
|
||||
| `TDENGINE_*` | 历史流量查询不可用,主流程正常 |
|
||||
|
||||
### 端口
|
||||
|
||||
全部端口变量见 `.env.example`,均有默认值。改端口只改 `.env`,不要改 `docker-compose.yml`。
|
||||
|
||||
## 二、应用配置
|
||||
|
||||
```bash
|
||||
cp -r config.example config
|
||||
```
|
||||
|
||||
得到:
|
||||
|
||||
```
|
||||
config/
|
||||
├── admin-svr/config.yaml
|
||||
├── admin-ui/default.conf
|
||||
├── app-server/config.yaml
|
||||
├── bot/config.yaml
|
||||
├── nginx/iotlcm.conf
|
||||
├── openapi/config.yaml
|
||||
├── sms/config.yaml
|
||||
├── upstream-chan/config.yaml
|
||||
├── upstream-proxy/config.yaml
|
||||
└── worker-svr/config.yaml
|
||||
```
|
||||
|
||||
### 通用:环境变量占位
|
||||
|
||||
所有配置都支持 `${VAR}` 与 `${VAR:default}` 语法,由 compose 从 `.env` 注入。因此**口令类字段不必写进 yaml**,保持 `${MYSQL_APP_PASSWORD}` 这样的引用即可。
|
||||
|
||||
### 逐份说明
|
||||
|
||||
#### admin-svr(管理端后端)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `database.default.link` | 库连接串,默认已用 `${MYSQL_APP_PASSWORD}` 拼好 |
|
||||
| `database.legacyCard.link` | 旧平台库,没有就留空 |
|
||||
| `jwt.signingKey` | 保持 `${JWT_SIGNING_KEY}`,不要手写 |
|
||||
| `warning.sms.enabled` | 不用短信改 `false` |
|
||||
| `warning.wechat.*` | 不用微信订阅消息改 `false` 并留空 |
|
||||
| `register.email.*` | 邮件验证码的 SMTP,不用则留空 |
|
||||
| `tsdb.tdengine.dsn` | 不用时序库则留空 |
|
||||
| `alipay.*` | 不用支付宝整段删除 |
|
||||
| `upstream.appDiagnosisToken` | 与 `upstream-proxy` 的 `appDiagnosis.internalToken` 一致 |
|
||||
|
||||
#### openapi(对外 API)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `jwt.signingKey` | 与 admin-svr 一致 |
|
||||
| `database.default.link` | 建议单独建只读账号与之隔离 |
|
||||
|
||||
#### worker-svr(异步任务)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `batch.inbound.upstreamRateLimit` | **运营商接口限流,必须按上游实际配额设置**。调太大会被运营商限流甚至封禁 |
|
||||
| `rabbitmq.batchExecute.maxRetries` | 批次执行失败重试次数 |
|
||||
| `tsdb.tdengine.dsn` | 不用时序库则留空 |
|
||||
|
||||
#### upstream-chan(运营商对接)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `registry.address` | Consul 地址,默认 `consul:8500` |
|
||||
| `dependencies.sim_yd_mock_v5.url` | 挡板地址。对接真实运营商时删除本段 |
|
||||
| `dependencies.token_refresh.skew_seconds` | 运营商 Token 提前刷新窗口 |
|
||||
|
||||
运营商通道本身(AppKey、AppSecret、接口地址)不在本文件配置,而是在平台「通道管理」中录入,存数据库。
|
||||
|
||||
#### upstream-proxy(通道缓存转发)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `appDiagnosis.internalToken` | 与 admin-svr 的 `upstream.appDiagnosisToken` 一致 |
|
||||
| `gateway.batchTimeout` | 批量转发总预算上限,**worker 侧超时必须大于此值** |
|
||||
|
||||
#### app-server(小程序后端)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `jwt.signingKey` | 与 admin-svr 一致 |
|
||||
| `payment.wechat.*` | 不用支付把 `enabled` 改 `false`;启用需把支付证书放入 `data/certs/` |
|
||||
| `appCardRecognition.*` | 拍照识别卡号,不用改 `false` |
|
||||
| `upstream.onelinkMock.*` | 挡板联调配置,对接真实运营商时 `enabled: false` |
|
||||
|
||||
#### sms(短信服务)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `serviceType` | `1`=阿里云,`2`=腾讯云 |
|
||||
| `accessKeyId` / `accessKeySecret` | 从 `.env` 注入 |
|
||||
| `signName` | 短信签名,需服务商审核通过 |
|
||||
| `sceneDbDsn` | 场景模板库连接,默认已拼好 |
|
||||
|
||||
#### bot(飞书通知,可选)
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| `feishu.appId` / `appSecret` / `chatId` | 全部从 `.env` 注入 |
|
||||
|
||||
#### admin-ui(管理端 nginx)
|
||||
|
||||
`default.conf` 里 `/api/` 反代到 `admin-svr:8008`,`/upload/` 指向共享上传目录。一般无需修改。
|
||||
|
||||
#### nginx(对外入口,可选)
|
||||
|
||||
`iotlcm.conf` 按域名分三组 server:`api.*` → openapi,`admin.*` → 管理端 + 文档站,`app.*` → 小程序端。**把 `your-domain.example.com` 替换为实际域名。**
|
||||
|
||||
不使用自带 nginx 时,把其中的 `location` 段落复制到宿主机 nginx 配置中即可。
|
||||
|
||||
## 三、配置自检
|
||||
|
||||
启动前先验证语法:
|
||||
|
||||
```bash
|
||||
# 检查 compose 展开是否正确(不会启动容器)
|
||||
docker compose config
|
||||
|
||||
# 只检查必填项是否齐全
|
||||
docker compose config --quiet
|
||||
```
|
||||
|
||||
配置文件语法错误(缩进、冒号)会导致服务启动后立刻退出,用日志定位:
|
||||
|
||||
```bash
|
||||
docker compose logs --tail=50 admin-svr
|
||||
```
|
||||
@@ -0,0 +1,173 @@
|
||||
# 启动与验证
|
||||
|
||||
## 启动
|
||||
|
||||
```bash
|
||||
# 前台启动(首次部署建议,便于观察初始化过程)
|
||||
docker compose up
|
||||
|
||||
# 确认无误后改为后台
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 首次启动会发生什么
|
||||
|
||||
1. **MySQL 建库并导入 schema**(约 1~2 分钟)
|
||||
`schema/` 下的 12 个脚本按文件名顺序自动执行:建表 → 结构补齐 → 创建应用账号 → 重置种子账号口令 → 导入通道模板/字典/菜单等种子数据
|
||||
2. MySQL 通过健康检查后,`admin-svr`、`openapi`、`worker-svr` 等服务依次启动
|
||||
3. 各服务向 Consul 注册
|
||||
|
||||
观察初始化进度:
|
||||
|
||||
```bash
|
||||
docker compose logs -f mysql
|
||||
```
|
||||
|
||||
看到 `[initdb] 应用账号 u_iotlcm 已创建` 与 `[initdb] 种子账号口令已统一重置` 表示初始化完成。
|
||||
|
||||
::: warning 首次初始化失败的处理
|
||||
MySQL 只在 `data/mysql` 为空时执行 `schema/`。若初始化中途失败,修改脚本后**必须清空数据卷**才会重跑:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
sudo rm -rf ./data/mysql
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
这会删除全部数据,仅在首次部署阶段使用。
|
||||
:::
|
||||
|
||||
## 检查运行状态
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
期望结果:
|
||||
|
||||
| 服务 | 状态 |
|
||||
| --- | --- |
|
||||
| iotlcm-mysql | Up (healthy) |
|
||||
| iotlcm-redis | Up (healthy) |
|
||||
| iotlcm-rabbitmq | Up (healthy) |
|
||||
| iotlcm-consul | Up |
|
||||
| iotlcm-admin-svr | Up |
|
||||
| iotlcm-admin-ui | Up |
|
||||
| iotlcm-openapi | Up |
|
||||
| iotlcm-upstream-chan | Up |
|
||||
| iotlcm-upstream-proxy | Up |
|
||||
| iotlcm-worker-svr | Up |
|
||||
| iotlcm-app-server | Up |
|
||||
| iotlcm-app-web | Up |
|
||||
| iotlcm-sms | Up (healthy) |
|
||||
| iotlcm-docs | Up |
|
||||
|
||||
任一服务显示 `Restarting` 或 `Exited` 需查日志:
|
||||
|
||||
```bash
|
||||
docker compose logs --tail=100 <服务名>
|
||||
```
|
||||
|
||||
## 验证清单
|
||||
|
||||
按顺序逐项确认,任一步失败先解决再继续。
|
||||
|
||||
### 1. 数据库
|
||||
|
||||
```bash
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT COUNT(*) AS tables_count FROM information_schema.tables WHERE table_schema=\"db_iotlcm\";"'
|
||||
```
|
||||
|
||||
预期输出 `tables_count` 为 **89**。
|
||||
|
||||
```bash
|
||||
# 确认种子数据
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm -e "SELECT COUNT(*) AS menus FROM sys_menu; SELECT COUNT(*) AS users FROM sys_user;"'
|
||||
```
|
||||
|
||||
预期:菜单约 447 条,账号 18 个。
|
||||
|
||||
### 2. 管理端后端
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8008/api.json
|
||||
```
|
||||
|
||||
预期 `200`。
|
||||
|
||||
### 3. 管理端前端
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8009/
|
||||
```
|
||||
|
||||
预期 `200`。
|
||||
|
||||
### 4. 对外 API
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/api.json
|
||||
```
|
||||
|
||||
预期 `200`。
|
||||
|
||||
### 5. 短信服务
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:11190/healthz
|
||||
```
|
||||
|
||||
预期 `200`。
|
||||
|
||||
### 6. 浏览器登录
|
||||
|
||||
访问 `http://<宿主机IP>:8009`:
|
||||
|
||||
| 项 | 值 |
|
||||
| --- | --- |
|
||||
| 账号 | `admin` |
|
||||
| 口令 | `.env` 里的 `MYSQL_ADMIN_PASSWORD` |
|
||||
|
||||
能进入首页工作台、左侧菜单完整显示,即部署成功。
|
||||
|
||||
## 首次登录后必做
|
||||
|
||||
1. **修改 admin 口令**:右上角个人中心 → 安全设置
|
||||
2. **修改其余种子账号口令**:种子账号(`user02`、`2admin` 等 17 个)默认与 admin 同一口令,如不使用请停用或删除
|
||||
3. **确认字典与菜单加载正常**:进入「卡信息」页,确认筛选下拉框选项不为空
|
||||
|
||||
## 后端服务自检
|
||||
|
||||
```bash
|
||||
# admin-svr 是否连上数据库
|
||||
docker compose logs admin-svr | grep -i 'error\|panic' | tail -20
|
||||
|
||||
# worker-svr 是否连上 RabbitMQ
|
||||
docker compose logs worker-svr | tail -30
|
||||
|
||||
# upstream-chan 是否连上 Redis 与 Consul
|
||||
docker compose logs upstream-chan | tail -30
|
||||
```
|
||||
|
||||
正常日志里不应出现 `connection refused`、`access denied`、`panic`。
|
||||
|
||||
## 停止与重启
|
||||
|
||||
```bash
|
||||
docker compose stop # 停止容器,保留数据
|
||||
docker compose restart # 重启全部
|
||||
docker compose restart admin-svr # 重启单个服务
|
||||
docker compose down # 停止并删除容器(数据卷在 ./data,不受影响)
|
||||
```
|
||||
|
||||
::: danger 不要执行 `docker compose down -v`
|
||||
`-v` 会删除命名数据卷。虽然本编排的数据都在 `./data` 宿主机目录下,但 `down -v` 仍可能影响其他同项目的卷。停止服务用 `down` 即可。
|
||||
:::
|
||||
|
||||
## 下一步
|
||||
|
||||
- 需要运营商挡板联调 → [可选服务](04-可选服务.md)
|
||||
- 需要对外域名访问 → [可选服务](04-可选服务.md) 的反向代理章节
|
||||
- 遇到报错 → [故障排查](06-故障排查.md)
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
# 可选服务
|
||||
|
||||
以下服务默认不启动,按需通过 profile 开启。
|
||||
|
||||
## 一、运营商接口挡板(onelink-mock)
|
||||
|
||||
### 用途
|
||||
|
||||
模拟中国移动 OneLink 接口。**没有真实运营商环境时,靠它跑通完整链路**:
|
||||
|
||||
```
|
||||
admin-svr → worker-svr → upstream-chan → onelink-mock
|
||||
```
|
||||
|
||||
不开挡板时,`upstream-chan` 会尝试连接真实运营商接口,没有凭据则批次执行、状态同步、流量查询全部失败。
|
||||
|
||||
### 启动
|
||||
|
||||
```bash
|
||||
docker compose --profile with-mock up -d
|
||||
```
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/api.json
|
||||
```
|
||||
|
||||
预期 `200`。管理界面在 `http://127.0.0.1:8080/swagger`。
|
||||
|
||||
### 配置
|
||||
|
||||
挡板自身无需配置,数据存在容器内 SQLite(`./data/mock/onelink_mock.db`)。
|
||||
|
||||
`upstream-chan` 的配置里已预置指向:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
sim_yd_mock_v5:
|
||||
url: "http://onelink-mock:8080/v5/"
|
||||
```
|
||||
|
||||
数据库种子脚本 `schema/08-seed-mock-channel.sql` 已插入一条 Mock 通道(`channel_yd_mock`)并指向该地址。
|
||||
|
||||
`app-server` 若要使用挡板,把 `upstream.onelinkMock.enabled` 改为 `true` 并填写 `baseUrl: "http://onelink-mock:8080/v5"`。
|
||||
|
||||
### 造测试卡
|
||||
|
||||
挡板支持生成模拟卡片,用于验证查询、开停复机、续费等流程。具体接口见挡板 Swagger 页面。
|
||||
|
||||
### 对接真实运营商
|
||||
|
||||
1. 删除或注释 `upstream-chan` 配置里的 `sim_yd_mock_v5` 段
|
||||
2. 在平台「通道管理」中录入真实运营商通道(AppKey、AppSecret、接口地址)
|
||||
3. 停用 Mock 通道,避免卡片误挂到 Mock 上
|
||||
|
||||
```bash
|
||||
docker compose --profile with-mock stop onelink-mock
|
||||
```
|
||||
|
||||
## 二、飞书通知(bot)
|
||||
|
||||
### 用途
|
||||
|
||||
把全量同步完成、失败告警等运维事件推送到飞书群。
|
||||
|
||||
### 准备
|
||||
|
||||
在飞书开放平台创建自建应用,获取:
|
||||
|
||||
| 项 | 获取方式 |
|
||||
| --- | --- |
|
||||
| `appId` / `appSecret` | 应用凭证页面 |
|
||||
| `chatId` | 目标群的会话 ID |
|
||||
|
||||
填入 `.env`:
|
||||
|
||||
```bash
|
||||
FEISHU_APP_ID=cli_xxxxxxxx
|
||||
FEISHU_APP_SECRET=xxxxxxxx
|
||||
FEISHU_CHAT_ID=oc_xxxxxxxx
|
||||
```
|
||||
|
||||
### 启动
|
||||
|
||||
```bash
|
||||
docker compose --profile with-bot up -d
|
||||
```
|
||||
|
||||
bot 依赖 `worker-svr` 生成的全量同步归档(`./data/logs/worker-svr/full-sync`),需该目录已有数据才会产生通知。
|
||||
|
||||
## 三、自带反向代理(nginx)
|
||||
|
||||
### 用途
|
||||
|
||||
把分散在各端口的服务统一到域名下按路径分流。宿主机已有 nginx 或面板时不需要。
|
||||
|
||||
### 域名字段
|
||||
|
||||
编辑 `config/nginx/iotlcm.conf`,把示例域名替换为实际域名:
|
||||
|
||||
| 域名 | 分流到 |
|
||||
| --- | --- |
|
||||
| `api.your-domain.example.com` | openapi(`/openapi/v3/`、`/route/open/`) |
|
||||
| `admin.your-domain.example.com` | 管理端前端 + `/docs/` 文档站 |
|
||||
| `app.your-domain.example.com` | 小程序前端 + `/app/api/v1/` 后端 |
|
||||
|
||||
### 启动
|
||||
|
||||
```bash
|
||||
docker compose --profile with-nginx up -d
|
||||
```
|
||||
|
||||
默认监听 80 端口,改 `.env` 的 `NGINX_HTTP_PORT` 可调整。
|
||||
|
||||
### 使用宿主机 nginx
|
||||
|
||||
不启动容器时,把 `config/nginx/iotlcm.conf` 中的 `upstream` 与 `location` 段落复制到宿主机 nginx 配置。
|
||||
|
||||
需注意:
|
||||
|
||||
- 宿主机 nginx 无法解析 compose 内的服务名,`upstream` 要改为 `127.0.0.1:<端口>`
|
||||
- 例如 `server admin-svr:8008;` → `server 127.0.0.1:8008;`
|
||||
|
||||
### HTTPS
|
||||
|
||||
自带 nginx 配置未包含证书。启用 HTTPS 需:
|
||||
|
||||
1. 准备证书文件
|
||||
2. 在 `iotlcm.conf` 的 server 块加入:
|
||||
|
||||
```nginx
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
```
|
||||
|
||||
3. 在 compose 的 nginx 服务增加证书目录挂载:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data/certs:/etc/nginx/certs:ro
|
||||
```
|
||||
|
||||
4. 增加 80 → 443 跳转:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name admin.your-domain.example.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
## 四、组合启动
|
||||
|
||||
多个 profile 可同时启用:
|
||||
|
||||
```bash
|
||||
docker compose --profile with-mock --profile with-nginx up -d
|
||||
```
|
||||
|
||||
查看当前启用的 profile 与对应的服务:
|
||||
|
||||
```bash
|
||||
docker compose --profile with-mock config --services
|
||||
```
|
||||
@@ -0,0 +1,185 @@
|
||||
# 升级与备份
|
||||
|
||||
## 版本固定
|
||||
|
||||
生产环境**必须固定镜像标签**,不要用 `latest`。原因:
|
||||
|
||||
- `latest` 会随仓库推送变化,同一份 compose 在不同时间拉到的镜像不同
|
||||
- 出问题无法确定运行的是哪个版本
|
||||
- 回滚时没有明确目标
|
||||
|
||||
`.env` 中指定:
|
||||
|
||||
```bash
|
||||
TAG=1.0.3
|
||||
```
|
||||
|
||||
记录当前部署版本:
|
||||
|
||||
```bash
|
||||
echo "$(date '+%Y-%m-%d %H:%M') TAG=$(grep '^TAG=' .env | cut -d= -f2)" >> deploy-history.log
|
||||
```
|
||||
|
||||
## 升级流程
|
||||
|
||||
```bash
|
||||
# 1. 备份(见下节,不要跳过)
|
||||
./backup.sh
|
||||
|
||||
# 2. 拉取新镜像
|
||||
vi .env # 修改 TAG
|
||||
docker compose pull
|
||||
|
||||
# 3. 只更新发生变化的服务
|
||||
docker compose up -d
|
||||
|
||||
# 4. 验证
|
||||
docker compose ps
|
||||
docker compose logs --tail=50 admin-svr
|
||||
```
|
||||
|
||||
滚动更新单个服务,减少中断:
|
||||
|
||||
```bash
|
||||
docker compose up -d --no-deps admin-svr
|
||||
```
|
||||
|
||||
## 回滚
|
||||
|
||||
```bash
|
||||
# 改回上一个版本
|
||||
vi .env # TAG 改回旧版本
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
::: warning 数据库变更不可自动回滚
|
||||
若新版本包含数据库结构变更,回滚代码后数据库仍是新结构。升级前务必确认变更脚本可逆,或保留升级前的完整备份。
|
||||
:::
|
||||
|
||||
## 什么情况下需要重新初始化数据库
|
||||
|
||||
`schema/` 下的脚本**只在 `data/mysql` 为空时执行**。以下情况才需要清空重建:
|
||||
|
||||
| 情况 | 是否需要 |
|
||||
| --- | --- |
|
||||
| 升级应用镜像 | 否 |
|
||||
| 修改 `config/` | 否,重启对应服务即可 |
|
||||
| 修改 `schema/` 脚本 | 是(会丢数据) |
|
||||
| 首次初始化失败 | 是 |
|
||||
|
||||
清空重建:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
sudo rm -rf ./data/mysql
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
::: danger 生产环境禁止清空 data/mysql
|
||||
生产数据必须通过数据库工具单独备份与迁移,不能依赖 schema 重建。上面这条命令仅用于首次部署阶段。
|
||||
:::
|
||||
|
||||
## 备份
|
||||
|
||||
### 全量备份脚本
|
||||
|
||||
保存为 `backup.sh`(不要提交到仓库,`.gitignore` 已排除 `backup.sh` 外的脚本时请自行确认):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
STAMP=$(date '+%Y%m%d-%H%M%S')
|
||||
DEST="./backups/${STAMP}"
|
||||
mkdir -p "$DEST"
|
||||
|
||||
echo "[1/3] 导出数据库..."
|
||||
docker compose exec -T mysql sh -c \
|
||||
'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction --routines --triggers --events db_iotlcm' \
|
||||
| gzip > "${DEST}/db_iotlcm.sql.gz"
|
||||
|
||||
echo "[2/3] 备份配置..."
|
||||
tar czf "${DEST}/config.tar.gz" config/ .env
|
||||
|
||||
echo "[3/3] 备份上传文件(可选,量大可跳过)..."
|
||||
tar czf "${DEST}/upload.tar.gz" data/upload/ 2>/dev/null || echo " 上传目录为空,跳过"
|
||||
|
||||
echo "完成:${DEST}"
|
||||
ls -lh "$DEST"
|
||||
```
|
||||
|
||||
```bash
|
||||
chmod +x backup.sh
|
||||
./backup.sh
|
||||
```
|
||||
|
||||
### 只备份数据库
|
||||
|
||||
```bash
|
||||
docker compose exec -T mysql sh -c \
|
||||
'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction db_iotlcm' \
|
||||
| gzip > "db_iotlcm-$(date +%Y%m%d).sql.gz"
|
||||
```
|
||||
|
||||
### 恢复数据库
|
||||
|
||||
```bash
|
||||
gunzip -c db_iotlcm-20260101.sql.gz | \
|
||||
docker compose exec -T mysql sh -c \
|
||||
'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm'
|
||||
```
|
||||
|
||||
### 备份内容清单
|
||||
|
||||
| 内容 | 位置 | 重要性 |
|
||||
| --- | --- | --- |
|
||||
| 数据库 | MySQL 容器内 `db_iotlcm` | **最高**,业务数据全在这里 |
|
||||
| 配置 | `config/` + `.env` | 高,丢失需重新配置 |
|
||||
| 上传文件 | `data/upload/` | 中,附件与图片 |
|
||||
| Redis 数据 | `data/redis/` | 低,缓存可重建 |
|
||||
| RabbitMQ 队列 | `data/rabbitmq/` | 低,未消费消息会丢失 |
|
||||
| 日志 | `data/logs/` | 低,排障用 |
|
||||
|
||||
### 备份策略建议
|
||||
|
||||
| 场景 | 频率 | 保留 |
|
||||
| --- | --- | --- |
|
||||
| 生产 | 每日一次 + 升级前 | 30 天 |
|
||||
| 试用 | 有数据变更时 | 7 天 |
|
||||
|
||||
备份文件应转存到异机或对象存储,不要与数据库放同一块盘。
|
||||
|
||||
## 日志清理
|
||||
|
||||
日志写在 `data/logs/` 下,按服务分目录,应用侧已配置按小时轮转(`{Y-m-d-H}.log`)。磁盘吃紧时清理旧日志:
|
||||
|
||||
```bash
|
||||
# 删除 7 天前的日志
|
||||
find ./data/logs -name '*.log' -mtime +7 -delete
|
||||
```
|
||||
|
||||
建议用系统 cron 定期执行:
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/iotlcm-logrotate
|
||||
0 3 * * * root find /path/to/iotlcm-deploy/data/logs -name '*.log' -mtime +7 -delete
|
||||
```
|
||||
|
||||
## 监控
|
||||
|
||||
基础组件自带的监控端点:
|
||||
|
||||
| 服务 | 端点 |
|
||||
| --- | --- |
|
||||
| RabbitMQ | `http://<host>:15672`(管理界面) |
|
||||
| Consul | `http://<host>:8500/ui` |
|
||||
| MySQL | `docker compose exec mysql mysqladmin status` |
|
||||
|
||||
建议对以下指标告警:
|
||||
|
||||
- MySQL 连接数与磁盘使用率
|
||||
- Redis 内存使用率
|
||||
- RabbitMQ 队列积压数(`iotlcm.batch.execute`、`iotlcm.app.business`)
|
||||
- worker-svr 全量同步任务失败数
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
# 故障排查
|
||||
|
||||
## 通用排查步骤
|
||||
|
||||
```bash
|
||||
# 1. 看容器状态
|
||||
docker compose ps
|
||||
|
||||
# 2. 看某个服务的日志
|
||||
docker compose logs --tail=100 <服务名>
|
||||
|
||||
# 3. 跟随日志
|
||||
docker compose logs -f <服务名>
|
||||
|
||||
# 4. 进容器排查
|
||||
docker compose exec <服务名> sh
|
||||
```
|
||||
|
||||
## 启动类
|
||||
|
||||
### MySQL 一直不 healthy
|
||||
|
||||
**现象**:`iotlcm-mysql` 显示 `Up (healthrestarting)` 或一直 `starting`,其余服务不启动。
|
||||
|
||||
**排查**:
|
||||
|
||||
```bash
|
||||
docker compose logs mysql | tail -50
|
||||
```
|
||||
|
||||
| 日志关键词 | 原因 | 处理 |
|
||||
| --- | --- | --- |
|
||||
| `Access denied` | root 口令与旧数据卷中的不一致 | 改 `.env` 的 `MYSQL_ROOT_PASSWORD` 与卷内一致,或清空 `data/mysql` 重建 |
|
||||
| `Can't create/write to file` | 目录权限问题 | `sudo chown -R 999:999 data/mysql` |
|
||||
| `No space left on device` | 磁盘满 | 清理磁盘 |
|
||||
| `mysqld: Can't open shared library` | 架构不匹配 | 确认镜像与宿主机架构一致 |
|
||||
|
||||
### schema 初始化失败
|
||||
|
||||
**现象**:MySQL 起来了,但表数量不对,或日志中有 SQL 报错。
|
||||
|
||||
**排查**:
|
||||
|
||||
```bash
|
||||
docker compose logs mysql | grep -iE 'error|ERROR' | head -30
|
||||
```
|
||||
|
||||
常见原因:
|
||||
|
||||
| 原因 | 处理 |
|
||||
| --- | --- |
|
||||
| `MYSQL_APP_PASSWORD` 未设置,`04-users.sh` 退出 | 在 `.env` 补上后清空 `data/mysql` 重建 |
|
||||
| `MYSQL_ADMIN_PASSWORD` 未设置,`05-reset-passwords.sh` 退出 | 同上 |
|
||||
| SQL 脚本本身语法问题 | 单独执行该脚本定位,见 [schema/README](../schema/README.md) |
|
||||
|
||||
::: warning 改脚本后必须清空数据卷
|
||||
MySQL 只在 `data/mysql` 为空时执行 `schema/`。文件改了不会自动重跑:
|
||||
|
||||
```bash
|
||||
docker compose down && sudo rm -rf ./data/mysql && docker compose up -d
|
||||
```
|
||||
:::
|
||||
|
||||
### 业务服务反复重启
|
||||
|
||||
**排查**:
|
||||
|
||||
```bash
|
||||
docker compose logs --tail=80 admin-svr
|
||||
```
|
||||
|
||||
| 报错 | 原因 | 处理 |
|
||||
| --- | --- | --- |
|
||||
| `possible config files "config" not found` | `config/` 目录不存在或挂载失败 | `cp -r config.example config` 并确认 `config/admin-svr/config.yaml` 存在 |
|
||||
| `dial tcp mysql:3306: connect: connection refused` | MySQL 未就绪 | 等 MySQL healthy,或检查 `depends_on` 是否生效 |
|
||||
| `Access denied for user 'u_iotlcm'` | 应用账号密码与数据库内不一致 | 确认 `.env` 的 `MYSQL_APP_PASSWORD` 与初始化时一致;改过则需重建库 |
|
||||
| `panic: unsupported provider xxx` | 数据库通道模板与镜像版本不匹配 | 确认镜像版本与 schema 版本配套 |
|
||||
|
||||
## 功能类
|
||||
|
||||
### 登录后提示未授权 / 接口 401
|
||||
|
||||
**原因**:`JWT_SIGNING_KEY` 在服务间不一致。
|
||||
|
||||
**处理**:确认 `admin-svr`、`openapi`、`app-server` 三份配置里的 `jwt.signingKey` 都引用 `${JWT_SIGNING_KEY}`,且 `.env` 里有值。改完重启三个服务:
|
||||
|
||||
```bash
|
||||
docker compose restart admin-svr openapi app-server
|
||||
```
|
||||
|
||||
### 登录成功但页面空白 / 菜单不显示
|
||||
|
||||
**排查**:
|
||||
|
||||
1. 浏览器 F12 看 Network 有无 4xx/5xx
|
||||
2. 检查菜单数据:
|
||||
|
||||
```bash
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm -e "SELECT COUNT(*) FROM sys_menu WHERE status=0;"'
|
||||
```
|
||||
|
||||
菜单为 0 说明种子数据未导入,需重建库。
|
||||
|
||||
3. 检查角色菜单关联:
|
||||
|
||||
```bash
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm -e "SELECT COUNT(*) FROM sys_role_menu;"'
|
||||
```
|
||||
|
||||
### 卡信息页通道列空白 / 筛选无选项
|
||||
|
||||
**原因**:Mock 通道未插入,或通道数据缺失。
|
||||
|
||||
**处理**:
|
||||
|
||||
```bash
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm -e "SELECT channel_id, channel_name FROM t_sim_channels;"'
|
||||
```
|
||||
|
||||
为空则手工执行种子脚本:
|
||||
|
||||
```bash
|
||||
docker compose exec -T mysql sh -c \
|
||||
'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm' < schema/08-seed-mock-channel.sql
|
||||
```
|
||||
|
||||
### 批次执行一直失败
|
||||
|
||||
**排查顺序**:
|
||||
|
||||
1. **挡板是否启动**(无真实运营商时)
|
||||
|
||||
```bash
|
||||
docker compose ps | grep onelink-mock
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/api.json
|
||||
```
|
||||
|
||||
未启动则:`docker compose --profile with-mock up -d`
|
||||
|
||||
2. **worker-svr 是否连上 RabbitMQ**
|
||||
|
||||
```bash
|
||||
docker compose logs worker-svr | grep -i 'rabbit\|amqp' | tail -20
|
||||
```
|
||||
|
||||
3. **upstream-chan 是否能连到上游**
|
||||
|
||||
```bash
|
||||
docker compose logs upstream-chan --tail=50
|
||||
```
|
||||
|
||||
4. **运营商是否限流**
|
||||
|
||||
看 `worker-svr` 日志中是否有 `rate limit`、`429`、`12021` 等错误。检查 `batch.inbound.upstreamRateLimit` 配置的 QPS 是否超过上游配额。
|
||||
|
||||
### 历史流量查询无数据
|
||||
|
||||
**原因**:TDengine 未配置或未连接。
|
||||
|
||||
**处理**:
|
||||
|
||||
```bash
|
||||
docker compose logs worker-svr | grep -i 'tdengine\|taos' | tail -20
|
||||
```
|
||||
|
||||
确认 `.env` 中 `TDENGINE_HOST` 等变量已填,且 TDengine 的 WebSocket 端口(默认 6041)可达:
|
||||
|
||||
```bash
|
||||
docker compose exec worker-svr sh -c 'nc -zv $TDENGINE_HOST $TDENGINE_PORT'
|
||||
```
|
||||
|
||||
不用该功能时留空即可,不影响主流程。
|
||||
|
||||
### 短信发不出去
|
||||
|
||||
**排查**:
|
||||
|
||||
```bash
|
||||
# 1. 短信服务健康
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:11190/healthz
|
||||
|
||||
# 2. 服务日志
|
||||
docker compose logs sms --tail=50
|
||||
```
|
||||
|
||||
| 报错 | 原因 |
|
||||
| --- | --- |
|
||||
| `InvalidAccessKeyId` | `.env` 里 AK 未填或错误 |
|
||||
| `isv.SMS_SIGNATURE_ILLEGAL` | `signName` 与服务商审核的签名不一致 |
|
||||
| `isv.SMS_TEMPLATE_ILLEGAL` | 模板 ID 未在服务商侧审核通过 |
|
||||
| `缺少 config.templateId` | 场景模板库未配置,调用方需自带 templateId |
|
||||
|
||||
### 图片上传失败 / 图片不显示
|
||||
|
||||
**原因**:`data/upload` 目录权限或挂载问题。
|
||||
|
||||
**处理**:
|
||||
|
||||
```bash
|
||||
ls -la data/upload/
|
||||
sudo chown -R 1000:1000 data/upload
|
||||
docker compose restart admin-svr admin-ui
|
||||
```
|
||||
|
||||
## 性能类
|
||||
|
||||
### CPU 被 worker-svr 打满
|
||||
|
||||
**原因**:定时任务开启了全量同步,大量卡片并发查询上游。
|
||||
|
||||
**处理**:
|
||||
|
||||
1. 降低并发:
|
||||
|
||||
```yaml
|
||||
batch:
|
||||
inbound:
|
||||
upstreamConcurrency: 50 # 从 300 降低
|
||||
upstreamBatchSize: 1
|
||||
```
|
||||
|
||||
2. 降低限流 QPS,与上游配额匹配
|
||||
|
||||
3. 演示/试用环境建议直接停用定时任务:
|
||||
|
||||
```bash
|
||||
docker compose exec mysql sh -c \
|
||||
'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" db_iotlcm -e "UPDATE sys_job SET status=1;"'
|
||||
```
|
||||
|
||||
种子数据中定时任务默认已全部停用(`status=1`)。
|
||||
|
||||
### 磁盘持续增长
|
||||
|
||||
按占用从大到小排查:
|
||||
|
||||
```bash
|
||||
du -sh data/* | sort -rh
|
||||
```
|
||||
|
||||
| 目录 | 处理 |
|
||||
| --- | --- |
|
||||
| `data/logs` | 清理旧日志,见 [升级与备份](05-升级与备份.md) 的日志清理 |
|
||||
| `data/upload` | 检查是否有异常大的上传文件 |
|
||||
| `data/mysql` | 数据库增长正常,关注 binlog:`docker compose exec mysql du -sh /var/lib/mysql` |
|
||||
| `data/redis` | AOF 文件,正常 |
|
||||
|
||||
## 网络类
|
||||
|
||||
### 容器间无法互访
|
||||
|
||||
```bash
|
||||
# 查看网络
|
||||
docker network inspect iotlcm-network
|
||||
|
||||
# 从容器内测试
|
||||
docker compose exec admin-svr sh -c 'nc -zv mysql 3306'
|
||||
```
|
||||
|
||||
服务名即主机名,配置里应使用 `mysql:3306`、`redis:6379` 这样的形式,不要写 `127.0.0.1`。
|
||||
|
||||
### 宿主机访问不了 127.0.0.1 绑定的服务
|
||||
|
||||
`admin-svr`、`admin-ui`、`openapi`、`app-server`、`app-web`、`docs` 默认只绑定 `127.0.0.1`,仅本机可访问。对外访问需:
|
||||
|
||||
1. 用 `--profile with-nginx` 启动反向代理,或
|
||||
2. 在宿主机配置 nginx 转发到 `127.0.0.1:<端口>`
|
||||
|
||||
不建议直接把端口改成 `0.0.0.0` 暴露到公网。
|
||||
|
||||
## 获取帮助信息
|
||||
|
||||
排查时附上这些信息便于定位:
|
||||
|
||||
```bash
|
||||
# 版本信息
|
||||
docker compose version
|
||||
docker version --format '{{.Server.Version}}'
|
||||
|
||||
# 服务状态
|
||||
docker compose ps
|
||||
|
||||
# 相关服务日志
|
||||
docker compose logs --tail=200 <服务名>
|
||||
|
||||
# 磁盘与内存
|
||||
df -h
|
||||
free -h
|
||||
```
|
||||
Reference in New Issue
Block a user