Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c8314a423 | |||
| 9cd518227d | |||
| d78379486c | |||
| e98f8561f7 | |||
| 70749bea7a | |||
| fd42b5976e | |||
| a7c15cf891 | |||
| 2548976f73 | |||
| 17c839daac | |||
| f76e988689 | |||
| 1634d27a43 | |||
| 42d12d905a | |||
| 89a15c4fca | |||
| 34669c9e1f | |||
| 12512b06ff |
@@ -47,7 +47,7 @@ jobs:
|
|||||||
curl -sS -X POST \
|
curl -sS -X POST \
|
||||||
"https://gitee.com/api/v5/enterprises/${DST_OWNER}/repos?access_token=${DST_TOKEN}" \
|
"https://gitee.com/api/v5/enterprises/${DST_OWNER}/repos?access_token=${DST_TOKEN}" \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{\"name\":\"${REPO_NAME}\",\"auto_init\":false,\"description\":\"iotLCM 物联网卡全生命周期管理平台(开源版)\"}" \
|
-d "{\"name\":\"${REPO_NAME}\",\"auto_init\":false,\"description\":\"iotLCM 物联网卡全生命周期管理平台\"}" \
|
||||||
-o /tmp/repo-create.json -w '建仓 HTTP %{http_code}\n' || true
|
-o /tmp/repo-create.json -w '建仓 HTTP %{http_code}\n' || true
|
||||||
head -c 300 /tmp/repo-create.json 2>/dev/null; echo
|
head -c 300 /tmp/repo-create.json 2>/dev/null; echo
|
||||||
else
|
else
|
||||||
@@ -69,6 +69,27 @@ jobs:
|
|||||||
echo "----- 推送尝试 $attempt/5"
|
echo "----- 推送尝试 $attempt/5"
|
||||||
if git push --mirror "https://${DST_USER}:${DST_TOKEN}@${DST}" 2>&1; then
|
if git push --mirror "https://${DST_USER}:${DST_TOKEN}@${DST}" 2>&1; then
|
||||||
echo "✅ 已同步到 Gitee"
|
echo "✅ 已同步到 Gitee"
|
||||||
|
|
||||||
|
# 推送后校验:远端 main 与 tag 集合必须与本地一致
|
||||||
|
# (避免“绿了但其实没推上去” —— Gitee 限流时容易发生)
|
||||||
|
LOCAL_MAIN=$(git rev-parse refs/heads/main 2>/dev/null || true)
|
||||||
|
REMOTE_MAIN=$(git ls-remote "https://${DST_USER}:${DST_TOKEN}@${DST}" refs/heads/main | awk '{print $1}')
|
||||||
|
LOCAL_TAGS=$(git for-each-ref --format='%(refname:short)' refs/tags | sort | tr '\n' ' ')
|
||||||
|
REMOTE_TAGS=$(git ls-remote --tags "https://${DST_USER}:${DST_TOKEN}@${DST}" \
|
||||||
|
| awk '{print $2}' | sed 's#refs/tags/##' | grep -v '\^{}$' | sort | tr '\n' ' ')
|
||||||
|
echo "本地 main: ${LOCAL_MAIN:-<无>}"
|
||||||
|
echo "远端 main: ${REMOTE_MAIN:-<无>}"
|
||||||
|
echo "本地 tag: ${LOCAL_TAGS:-<无>}"
|
||||||
|
echo "远端 tag: ${REMOTE_TAGS:-<无>}"
|
||||||
|
if [ -n "$LOCAL_MAIN" ] && [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
|
||||||
|
echo "❌ 校验失败:远端 main 与本地不一致"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "${LOCAL_TAGS% }" != "${REMOTE_TAGS% }" ]; then
|
||||||
|
echo "❌ 校验失败:远端 tag 与本地不一致"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ 校验通过:Gitee 端 main 与 tag 均已对齐"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
wait_s=$((attempt * 30))
|
wait_s=$((attempt * 30))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# make test 跑全部 Go 模块的单元测试
|
# make test 跑全部 Go 模块的单元测试
|
||||||
# make images 本地构建全部镜像(默认 tag 用 git describe)
|
# make images 本地构建全部镜像(默认 tag 用 git describe)
|
||||||
# make docs 本地构建文档站
|
# make docs 本地构建文档站
|
||||||
|
# make website 本地构建官网
|
||||||
# make clean 清理构建产物
|
# make clean 清理构建产物
|
||||||
#
|
#
|
||||||
# 镜像仓库与版本可覆盖:
|
# 镜像仓库与版本可覆盖:
|
||||||
@@ -15,25 +16,27 @@ BASE_REGISTRY ?= docker.io/library
|
|||||||
|
|
||||||
GO_MODULES := admin-svr/server app/server bot onelink-mock openapi sms upstream-chan upstream-proxy worker-svr
|
GO_MODULES := admin-svr/server app/server bot onelink-mock openapi sms upstream-chan upstream-proxy worker-svr
|
||||||
|
|
||||||
# 目录|镜像名|构建上下文|Dockerfile
|
# 目录|镜像名|构建上下文|Dockerfile|固定版本(留空=跟随 VERSION)
|
||||||
|
# 小程序线 app 固定 v1.0.2:版本号与功能一一对应,平台发新 tag 时不跟着动。
|
||||||
IMAGE_MAP := \
|
IMAGE_MAP := \
|
||||||
admin-svr|iotlcm-admin-svr|admin-svr/server|build/Dockerfile \
|
admin-svr|iotlcm-admin-svr|admin-svr/server|build/Dockerfile| \
|
||||||
admin-ui|iotlcm-admin-ui|admin-ui|vue/build/Dockerfile \
|
admin-ui|iotlcm-admin-ui|admin-ui|vue/build/Dockerfile| \
|
||||||
openapi|iotlcm-openapi|openapi|build/Dockerfile \
|
openapi|iotlcm-openapi|openapi|build/Dockerfile| \
|
||||||
worker-svr|iotlcm-worker-svr|worker-svr|build/Dockerfile \
|
worker-svr|iotlcm-worker-svr|worker-svr|build/Dockerfile| \
|
||||||
upstream-chan|iotlcm-upstream-chan|upstream-chan|build/Dockerfile \
|
upstream-chan|iotlcm-upstream-chan|upstream-chan|build/Dockerfile| \
|
||||||
upstream-proxy|iotlcm-upstream-proxy|upstream-proxy|build/Dockerfile \
|
upstream-proxy|iotlcm-upstream-proxy|upstream-proxy|build/Dockerfile| \
|
||||||
app|iotlcm-app-server|app/server|Dockerfile \
|
app|iotlcm-app-server|app/server|Dockerfile|v1.0.2 \
|
||||||
app|iotlcm-app-web|app/app|Dockerfile \
|
app|iotlcm-app-web|app/app|Dockerfile|v1.0.2 \
|
||||||
sms|iotlcm-sms|sms|build/Dockerfile \
|
sms|iotlcm-sms|sms|build/Dockerfile| \
|
||||||
bot|iotlcm-bot|bot|Dockerfile \
|
bot|iotlcm-bot|bot|Dockerfile| \
|
||||||
docs|iotlcm-docs|docs|Dockerfile \
|
docs|iotlcm-docs|docs|Dockerfile| \
|
||||||
onelink-mock|iotlcm-onelink-mock|onelink-mock|Dockerfile
|
website|iotlcm-website|website|Dockerfile| \
|
||||||
|
onelink-mock|iotlcm-onelink-mock|onelink-mock|Dockerfile|
|
||||||
|
|
||||||
.PHONY: help build test images docs clean
|
.PHONY: help build test images docs website clean
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@sed -n '2,12p' Makefile | sed 's/^# \{0,1\}//'
|
@grep -E '^# make' Makefile | sed 's/^# //'
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@set -e; for m in $(GO_MODULES); do \
|
@set -e; for m in $(GO_MODULES); do \
|
||||||
@@ -50,21 +53,27 @@ test:
|
|||||||
|
|
||||||
images:
|
images:
|
||||||
@set -e; echo "镜像前缀: $(REGISTRY) 版本: $(VERSION)"; \
|
@set -e; echo "镜像前缀: $(REGISTRY) 版本: $(VERSION)"; \
|
||||||
echo "$(IMAGE_MAP)" | tr ' ' '\n' | while IFS='|' read -r dir img ctx df; do \
|
echo "$(IMAGE_MAP)" | tr ' ' '\n' | while IFS='|' read -r dir img ctx df pin; do \
|
||||||
[ -z "$$dir" ] && continue; \
|
[ -z "$$dir" ] && continue; \
|
||||||
echo ""; echo "==> $$img:$$VERSION (context=$$ctx dockerfile=$$df)"; \
|
v="$${pin:-$(VERSION)}"; \
|
||||||
|
echo ""; echo "==> $$img:$$v (context=$$ctx dockerfile=$$df$${pin:+ [固定版本]})"; \
|
||||||
docker build -f "$$ctx/$$df" \
|
docker build -f "$$ctx/$$df" \
|
||||||
--build-arg BASE_REGISTRY="$(BASE_REGISTRY)" \
|
--build-arg BASE_REGISTRY="$(BASE_REGISTRY)" \
|
||||||
--build-arg BuildVersion="$(VERSION)" \
|
--build-arg BuildVersion="$$v" \
|
||||||
--build-arg CommitID="$$(git rev-parse --short=7 HEAD)" \
|
--build-arg CommitID="$$(git rev-parse --short=7 HEAD)" \
|
||||||
--build-arg BuildTime="$$(date -u +%FT%TZ)" \
|
--build-arg BuildTime="$$(date -u +%FT%TZ)" \
|
||||||
-t "$(REGISTRY):$$img-$(VERSION)" "$$ctx"; \
|
-t "$(REGISTRY):$$img-$$v" "$$ctx"; \
|
||||||
done
|
done
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
cd docs && npm ci && npm run build
|
cd docs && npm ci && npm run build
|
||||||
@echo "✅ 文档站产物:docs/.vitepress/dist"
|
@echo "✅ 文档站产物:docs/.vitepress/dist"
|
||||||
|
|
||||||
|
website:
|
||||||
|
cd website && npm ci && npm run build
|
||||||
|
@echo "✅ 官网产物:website/.vitepress/dist"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf docs/.vitepress/dist docs/.vitepress/cache
|
@rm -rf docs/.vitepress/dist docs/.vitepress/cache
|
||||||
|
@rm -rf website/.vitepress/dist website/.vitepress/cache
|
||||||
@echo "✅ 已清理"
|
@echo "✅ 已清理"
|
||||||
|
|||||||
@@ -1,51 +1,77 @@
|
|||||||
# iotLCM —— 物联网卡全生命周期管理平台(开源版)
|
# iotLCM 物联网卡全生命周期管理平台
|
||||||
|
|
||||||
一站式物联网 SIM 卡管理平台:卡片从运营商渠道入库 → 划拨给代理商 → 激活 / 续费 / 停机 → 流量与状态同步 → 销户。对接中国移动 OneLink、中国电信 5G CMP、中国联通 10646 等运营商接口,并通过共享 Token 模式接入多家三方渠道商。
|
iotLCM 面向物联网 SIM 卡的全生命周期管理:卡片从运营商渠道入库 → 划拨给代理商 → 激活 / 续费 / 停机 → 流量与状态同步 → 销户。
|
||||||
|
|
||||||
**单仓多服务**:平台全部后端服务、前端应用、文档站与部署编排都在本仓,一次 clone 即可获得完整源码。
|
平台对接**中国移动 OneLink**、**中国电信 5G CMP**、**中国联通 10646** 等运营商接口,支持以共享 Token 模式接入三方渠道商,并提供对外的 OpenAPI 服务。
|
||||||
|
|
||||||
## 目录
|
## 文档
|
||||||
|
|
||||||
| 目录 | 说明 | 镜像 |
|
| 手册 | 内容 | 入口 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `admin-svr/` | 管理端后端(GoFrame):卡信息、通信管理、资费、告警工单、统计、账号治理 | `iotlcm-admin-svr` |
|
| **使用手册 · Web 管理端** | 查卡、智能诊断、业务受理、套餐与定价、库存出入库、通道管理、企业用户与角色、工单、API 凭证、常见问题 | <http://open.5iot.com:5051/docs/manual/web/> |
|
||||||
| `admin-ui/` | 管理端前端(Vue 3 + Vben Admin) | `iotlcm-admin-ui` |
|
| **使用手册 · 小程序端** | 首页公开查卡、卡片排查、客户管理与划拨、工单、批次执行日志、消息与个人中心 | <http://open.5iot.com:5051/docs/manual/mini-program/> |
|
||||||
| `openapi/` | 对外 API 网关:V3 接口、旧版兼容、运营商能力代理 | `iotlcm-openapi` |
|
| **部署手册** | 推荐环境、一键部署、配置说明、离线部署、拆分部署、自建镜像、运维与排错 | <http://open.5iot.com:5051/docs/deploy/> |
|
||||||
| `worker-svr/` | 异步执行:RabbitMQ 消费者、全量同步、批量任务 | `iotlcm-worker-svr` |
|
| **OpenAPI 合同** | 鉴权、V3 接口、旧版兼容接口、运营商能力代理 | <http://open.5iot.com:5051/docs/openapi/> |
|
||||||
| `upstream-chan/` | 运营商 / 三方渠道对接层(OneLink、CMP、10646、共享 Token) | `iotlcm-upstream-chan` |
|
| **共享 Token 接口** | 共享 Token 获取与白名单转发 | <http://open.5iot.com:5051/docs/openapi/operator/> |
|
||||||
| `upstream-proxy/` | 通道缓存转发层(挡在 chan 前面的本地缓存) | `iotlcm-upstream-proxy` |
|
|
||||||
| `app/server/` | 用户端服务(GoFrame) | `iotlcm-app-server` |
|
|
||||||
| `app/app/` | 用户端前端(uni-app,基于 unibest,MIT) | `iotlcm-app-web` |
|
|
||||||
| `sms/` | 短信 HTTP / gRPC 服务(阿里云、腾讯云) | `iotlcm-sms` |
|
|
||||||
| `bot/` | 飞书通知机器人(运维自用,可选) | `iotlcm-bot` |
|
|
||||||
| `docs/` | 文档站(VitePress):使用手册 + OpenAPI 合同 + 部署手册 | `iotlcm-docs` |
|
|
||||||
| `onelink-mock/` | OneLink 接口挡板(联调 / 演示,可选) | `iotlcm-onelink-mock` |
|
|
||||||
| `deploy/` | Docker Compose 编排与数据库初始化 | 参考 `deploy/README.md` |
|
|
||||||
|
|
||||||
每个子目录都有自己的 `README.md`,说明该服务的职责、配置项与本地运行方式。
|
在线文档站:**<http://open.5iot.com:5051/docs/>**。文档源码在本仓 [`docs/`](docs) 目录,随平台一起发布(自建实例访问 `http://<平台地址>:8019/docs/`)。
|
||||||
|
|
||||||
## 快速开始(只跑起来)
|
## 快速开始
|
||||||
|
|
||||||
不需要编译,直接用预构建镜像拉起整栈:
|
需要 Docker 20.10+ 与 Docker Compose v2,单机 4 核 / 8 GB 起。预构建镜像已就绪,不需要编译:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <本仓库地址> iotlcm
|
git clone <仓库地址> iotlcm
|
||||||
cd iotlcm/deploy
|
cd iotlcm/deploy
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
首次启动自动完成 MySQL 建库建表(95 张)、种子数据导入、时序库建表,实测 30 秒 ~ 1 分钟。
|
首次启动自动完成建库建表、种子数据导入与时序库建表,约 1 分钟。启动完成后访问 `http://127.0.0.1:8009`。
|
||||||
|
|
||||||
默认账号 `admin`,口令见 `deploy/README.md`(**正式使用前必须修改**)。详细的端口、配置项、可选服务(挡板 / 飞书通知 / 反向代理)、离线部署与排错,见 `deploy/README.md` 与文档站 `docs/deploy/`。
|
默认账号口令、端口清单、可选服务(接口挡板 / 飞书通知 / 反向代理)、修改口令与上线检查,见 [`deploy/README.md`](deploy/README.md) 与[部署手册](http://open.5iot.com:5051/docs/deploy/)。
|
||||||
|
|
||||||
> 对外端口默认只监听 `127.0.0.1`,需要局域网或公网访问时,用 `deploy/` 里的 nginx 编排改绑定地址,或并入宿主机已有的反向代理。
|
> 业务端口默认只绑定 `127.0.0.1`。需要局域网或公网访问时,用 `--profile with-nginx` 起反向代理,或改用 `--profile with-gateway` 的单端口入口(默认 5051)。
|
||||||
|
|
||||||
|
## 功能概览
|
||||||
|
|
||||||
|
| 域 | 能力 |
|
||||||
|
| --- | --- |
|
||||||
|
| 卡资产 | 卡信息、批量导入、入库 / 库存 / 出库、批量开停复机、续费、变更套餐、达量断网 |
|
||||||
|
| 通信管理 | 通道与接入模板、运营商能力对接、共享 Token 接入三方渠道、通道缓存转发 |
|
||||||
|
| 资费 | 套餐与流量池、定价、生效与到期策略 |
|
||||||
|
| 代理商 | 代理商与分佣、划拨与回收 |
|
||||||
|
| 数据同步 | 流量 / 状态 / IMEI 全量同步与增量对齐、历史账期时序数据 |
|
||||||
|
| OpenAPI | V3 接口、旧版兼容接口、运营商能力代理(白名单转发 / 共享 Token) |
|
||||||
|
| 运营 | 工单、预警、执行日志、审计、智能诊断 |
|
||||||
|
| 端 | Web 管理端、小程序 / H5 用户端 |
|
||||||
|
|
||||||
|
## 服务构成
|
||||||
|
|
||||||
|
| 目录 | 说明 | 镜像 tag |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `admin-svr/` | 管理端后端(GoFrame) | `iotlcm-admin-svr` |
|
||||||
|
| `admin-ui/` | 管理端前端(Vue 3 + Vben Admin) | `iotlcm-admin-ui` |
|
||||||
|
| `openapi/` | 对外 API 网关 | `iotlcm-openapi` |
|
||||||
|
| `worker-svr/` | 异步执行(RabbitMQ 消费者、全量同步、批量任务) | `iotlcm-worker-svr` |
|
||||||
|
| `upstream-chan/` | 运营商 / 三方渠道对接层 | `iotlcm-upstream-chan` |
|
||||||
|
| `upstream-proxy/` | 通道缓存转发层 | `iotlcm-upstream-proxy` |
|
||||||
|
| `app/server/` | 用户端服务(GoFrame) | `iotlcm-app-server` |
|
||||||
|
| `app/app/` | 用户端前端(uni-app,基于 unibest) | `iotlcm-app-web` |
|
||||||
|
| `sms/` | 短信服务(HTTP / gRPC,阿里云 / 腾讯云) | `iotlcm-sms` |
|
||||||
|
| `bot/` | 飞书通知机器人(运维自用,可选) | `iotlcm-bot` |
|
||||||
|
| `docs/` | 文档站(VitePress)与 OpenAPI 合同 | `iotlcm-docs` |
|
||||||
|
| `website/` | 官网(VitePress):项目介绍、功能矩阵、快速开始、教程入口 | `iotlcm-website` |
|
||||||
|
| `onelink-mock/` | OneLink 接口挡板(联调 / 演示,可选) | `iotlcm-onelink-mock` |
|
||||||
|
| `deploy/` | Docker Compose 编排、数据库初始化、反向代理 / 单端口网关配置 | — |
|
||||||
|
|
||||||
|
各服务职责、配置项与本地运行方式见各自目录下的 `README.md`。
|
||||||
|
|
||||||
## 从源码构建
|
## 从源码构建
|
||||||
|
|
||||||
每个 Go 服务是独立模块(各自带 `go.mod`),在对应目录内构建:
|
每个 Go 服务是独立模块,在对应目录内构建:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd worker-svr && go build -o out/ . # 其它 Go 服务同理
|
cd worker-svr && go build -o out/ . # 其余 Go 服务同理
|
||||||
```
|
```
|
||||||
|
|
||||||
前端:
|
前端:
|
||||||
@@ -56,31 +82,38 @@ cd app/app && pnpm install && pnpm build
|
|||||||
cd docs && npm ci && npm run build
|
cd docs && npm ci && npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
或一键编译检查全部 Go 模块:
|
一键编译全部 Go 服务 / 本地构建全部镜像:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make build # 所有 Go 服务编译
|
make build # 编译检查
|
||||||
make images # 本地构建全部镜像
|
make images # 构建镜像(REGISTRY / VERSION 可覆盖)
|
||||||
```
|
```
|
||||||
|
|
||||||
构建镜像所需的 Dockerfile 位置与构建上下文,见 `docs/docs/deploy/build-image.md`。
|
各服务的 Dockerfile 位置与构建上下文见[自建镜像](http://open.5iot.com:5051/docs/deploy/build-image)。
|
||||||
|
|
||||||
## 发布与镜像
|
## 版本与镜像
|
||||||
|
|
||||||
所有镜像发布到**同一个镜像仓库**,用 tag 区分服务与版本:
|
镜像统一发布在同一个仓库,用 tag 区分服务与版本:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
<镜像仓库>/iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4
|
<镜像仓库>/iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4
|
||||||
└─ 仓库 ┘ └─ 服务名 ─┘└版本┘
|
└─ 仓库 ┘ └─ 服务名 ─┘└版本┘
|
||||||
```
|
```
|
||||||
|
|
||||||
打 `v*` tag 会经由内网 CI 构建全部镜像并推送,见 `.gitea/workflows/`。
|
| 服务 | 当前版本 |
|
||||||
|
| --- | --- |
|
||||||
|
| 除小程序线外 | `v1.0.4` |
|
||||||
|
| `iotlcm-app-server` / `iotlcm-app-web` | `v1.0.2`(小程序线独立版本线) |
|
||||||
|
|
||||||
|
升级时固定到具体版本,不要使用 `latest`。
|
||||||
|
|
||||||
|
## 反馈
|
||||||
|
|
||||||
|
问题与建议请提 Issue,或联系平台维护者。
|
||||||
|
|
||||||
## 许可
|
## 许可
|
||||||
|
|
||||||
本仓整体采用 [Apache License 2.0](LICENSE)。
|
本仓整体采用 [Apache License 2.0](LICENSE)。以下子目录基于上游 MIT 项目衍生,保留其原始许可:
|
||||||
|
|
||||||
以下子目录基于上游 MIT 项目衍生,保留其原始许可:
|
|
||||||
|
|
||||||
| 目录 | 上游 | 许可 |
|
| 目录 | 上游 | 许可 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
iotLCM 物联网卡全生命周期管理平台的**小程序端 + 用户端服务**。
|
iotLCM 物联网卡全生命周期管理平台的**小程序端 + 用户端服务**。
|
||||||
|
|
||||||
|
> **版本线独立**:本目录对应小程序线的 **v1.0.2**,不跟随平台 tag(平台当前为 v1.0.4)。
|
||||||
|
> 功能变更时才提升本线版本,镜像 tag 仍为 `iotlcm-app-server-<版本>` / `iotlcm-app-web-<版本>`。
|
||||||
|
|
||||||
- `app/` —— uni-app 小程序前端(基于 [unibest](https://github.com/unibest-tech/unibest),MIT)
|
- `app/` —— uni-app 小程序前端(基于 [unibest](https://github.com/unibest-tech/unibest),MIT)
|
||||||
- `server/` —— 用户端 GoFrame 服务(基于 XiuAdmin 框架,Apache-2.0)
|
- `server/` —— 用户端 GoFrame 服务(基于 XiuAdmin 框架,Apache-2.0)
|
||||||
|
|
||||||
|
|||||||
+63
-7
@@ -18,7 +18,7 @@ docker compose up -d
|
|||||||
docker compose logs -f mysql
|
docker compose logs -f mysql
|
||||||
```
|
```
|
||||||
|
|
||||||
启动完成后访问 `http://<宿主机IP>:8009`:
|
启动完成后在本机访问 `http://127.0.0.1:8009`(编排默认把业务端口绑定在 127.0.0.1,需要局域网/公网访问见下方「重要提示」):
|
||||||
|
|
||||||
| 项 | 值 |
|
| 项 | 值 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -30,12 +30,59 @@ docker compose logs -f mysql
|
|||||||
## 可选服务
|
## 可选服务
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose --profile with-mock up -d # 运营商接口挡板
|
docker compose --profile with-gateway up -d # 单端口入口(默认对外 5051)
|
||||||
docker compose --profile with-bot up -d # 飞书通知(运维自用)
|
docker compose --profile with-mock up -d # 运营商接口挡板
|
||||||
docker compose --profile with-nginx up -d # 自带反向代理
|
docker compose --profile with-bot up -d # 飞书通知(运维自用)
|
||||||
|
docker compose --profile with-nginx up -d # 多域名反向代理(对外 80)
|
||||||
|
docker compose --profile with-website up -d # 官网(项目门户站)
|
||||||
```
|
```
|
||||||
|
|
||||||
多个 profile 可组合:`--profile with-mock --profile with-nginx up -d`
|
多个 profile 可组合:`--profile with-gateway --profile with-mock up -d`
|
||||||
|
|
||||||
|
### 单端口入口(with-gateway)
|
||||||
|
|
||||||
|
只暴露一个端口时用它。容器内监听 80,宿主机端口由 `GATEWAY_PORT` 控制(默认 **5051**):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile with-gateway up -d
|
||||||
|
# 或换端口
|
||||||
|
GATEWAY_PORT=8088 docker compose --profile with-gateway up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
| 路径 | 去向 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/` | 管理端(admin-ui,内部已代理 `/api/` 到 admin-svr) |
|
||||||
|
| `/docs/` | 文档站 |
|
||||||
|
| `/www/` | 官网(需同时启用 `with-website`) |
|
||||||
|
| `/openapi/` | 对外 API |
|
||||||
|
| `/route/open/` | 运营商能力代理(白名单 / 共享 Token) |
|
||||||
|
|
||||||
|
配置见 `config/gateway/nginx.conf`。小程序 / H5 端的静态资源是根路径部署的,不能挂在同一域名的子路径下,需要单独域名或端口(见 `with-nginx` 的 app 段)。
|
||||||
|
|
||||||
|
### 官网(with-website)
|
||||||
|
|
||||||
|
项目门户站(项目介绍、功能矩阵、快速开始、教程入口),源码在仓库的 `website/` 目录,与文档站同构(VitePress)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile with-website up -d --build website
|
||||||
|
```
|
||||||
|
|
||||||
|
镜像发布到公共仓库之前用 `--build` 本地构建;发布后去掉 `--build` 即可。
|
||||||
|
|
||||||
|
**两种形态**由构建参数 `WEBSITE_SITE_BASE` 决定:
|
||||||
|
|
||||||
|
| 形态 | 参数 | 访问方式 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 子路径(过渡,无独立域名) | `/www/`(默认) | 网关的 `http://<主机>:5051/www/` |
|
||||||
|
| 独立域名 | `/` | 域名根路径,如 `https://<官网域名>/` |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 独立域名形态
|
||||||
|
WEBSITE_SITE_BASE=/ docker compose --profile with-website up -d --build website
|
||||||
|
```
|
||||||
|
|
||||||
|
形态切换只改构建参数与入口配置,页面内容同源,不用改代码。独立域名形态下把 DNS 指到本机,
|
||||||
|
并在 `config/nginx/iotlcm.conf` 里加一段 `server_name <官网域名>` 的 vhost 指向 `website` 容器。
|
||||||
|
|
||||||
`with-bot` 是把全量同步等运维事件推送到飞书群的**内部运维工具**,不是平台功能。它需要你自己的飞书自建应用凭证(`config/bot/config.yaml` 的 `appId` / `appSecret` / `chatId`),没填就不启动。
|
`with-bot` 是把全量同步等运维事件推送到飞书群的**内部运维工具**,不是平台功能。它需要你自己的飞书自建应用凭证(`config/bot/config.yaml` 的 `appId` / `appSecret` / `chatId`),没填就不启动。
|
||||||
|
|
||||||
@@ -54,7 +101,14 @@ crpi-.../iotlcm/iotlcm:iotlcm-app-server-v1.0.2
|
|||||||
|
|
||||||
tag 格式统一为 **`<服务名>-<版本>`**。
|
tag 格式统一为 **`<服务名>-<版本>`**。
|
||||||
|
|
||||||
当前业务版本:大部分服务为 `v1.0.4`,`iotlcm-app-server` / `iotlcm-app-web` 为 `v1.0.2`(源仓最新 tag 就是 v1.0.2)。
|
当前业务版本:
|
||||||
|
|
||||||
|
| 服务 | 版本 |
|
||||||
|
| --- | --- |
|
||||||
|
| 除 app 线外的全部业务服务 | `v1.0.4` |
|
||||||
|
| `iotlcm-app-server` / `iotlcm-app-web` | **`v1.0.2`**(小程序线独立版本,不跟随平台 tag) |
|
||||||
|
|
||||||
|
> 版本号与功能一一对应:小程序线的功能停在 v1.0.2,因此镜像 tag 也停在 v1.0.2;平台后续发 v1.0.5 时它依然不动。
|
||||||
|
|
||||||
升级时在 `docker-compose.yml` 中同步更新 tag 的版本部分,不要改用 `latest`。
|
升级时在 `docker-compose.yml` 中同步更新 tag 的版本部分,不要改用 `latest`。
|
||||||
|
|
||||||
@@ -122,7 +176,9 @@ TDengine 版本为 `3.3.6.13`(公开镜像可得),生产用的是 `3.4.0.9
|
|||||||
- **`JWT_SIGNING_KEY` 必须在 `admin-svr`、`openapi`、`app-server` 三者间完全一致**,否则令牌跨服务不通
|
- **`JWT_SIGNING_KEY` 必须在 `admin-svr`、`openapi`、`app-server` 三者间完全一致**,否则令牌跨服务不通
|
||||||
- **镜像标签不要用 `latest`**,生产环境请固定到具体版本
|
- **镜像标签不要用 `latest`**,生产环境请固定到具体版本
|
||||||
- **改 `schema/` 下的脚本不会自动生效**,需要清空 `data/mysql` 重新初始化(会丢失全部数据)
|
- **改 `schema/` 下的脚本不会自动生效**,需要清空 `data/mysql` 重新初始化(会丢失全部数据)
|
||||||
- 默认只监听 `127.0.0.1` 的服务需通过反向代理对外
|
- 业务端口默认只绑定 `127.0.0.1`(admin-ui/admin-svr/openapi/app-web/docs/sms),要从其他机器访问,二选一:
|
||||||
|
- 用 `--profile with-nginx` 起自带反向代理(对外 80,按域名/路径分流,配置见 `config/nginx/iotlcm.conf`)
|
||||||
|
- 或把 `docker-compose.yml` 里对应服务的 `127.0.0.1:xxxx` 改成 `0.0.0.0:xxxx`(需自备防火墙策略)
|
||||||
|
|
||||||
## 许可
|
## 许可
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
# ============================================================
|
||||||
|
# iotlcm 内存上限 override —— 8 vCPU / 32 GB 宿主机,与其他服务共用
|
||||||
|
#
|
||||||
|
# 定位:这台机器是「一机多环境」,iotlcm 只是其中一个占用方。
|
||||||
|
# 所以只给全套 20 个服务留 **约 8.5 GB 上限**(实测常驻约 2 GB),
|
||||||
|
# 剩余 20+ GB 留给宿主机上要新增的其它服务。
|
||||||
|
#
|
||||||
|
# 没有本文件会怎样:编排里没有内存限制,任何一个服务泄漏/跑批都会
|
||||||
|
# 把整机内存吃到 OOM Killer 随机杀进程(表现为容器反复 Restarting
|
||||||
|
# 且日志里看不到业务异常,只能 dmesg 里看到 oom-kill)。
|
||||||
|
#
|
||||||
|
# 用法(顺序不能反):
|
||||||
|
# docker compose -f docker-compose.yml -f compose.memlimit.yml up -d
|
||||||
|
#
|
||||||
|
# 只调 resources(+ MySQL 自身缓存参数),不动镜像、端口、卷、依赖。
|
||||||
|
# 换成更小的机器(4 GB)时按比例下调:mysql 1024M / tdengine 512M /
|
||||||
|
# worker-svr 768M / 其余 320M;8 GB 机器可用 1024M / 768M / 512M。
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ---------- 基础组件 ----------
|
||||||
|
mysql:
|
||||||
|
# buffer pool 由 128M(默认)提到 768M,连接数 151 → 300
|
||||||
|
command:
|
||||||
|
- --character-set-server=utf8mb4
|
||||||
|
- --collation-server=utf8mb4_general_ci
|
||||||
|
- --default-time-zone=+08:00
|
||||||
|
- --innodb-buffer-pool-size=768M
|
||||||
|
- --max-connections=300
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 2048M
|
||||||
|
reservations:
|
||||||
|
memory: 768M
|
||||||
|
|
||||||
|
redis:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 384M
|
||||||
|
reservations:
|
||||||
|
memory: 96M
|
||||||
|
|
||||||
|
rabbitmq:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
memory: 192M
|
||||||
|
|
||||||
|
tdengine:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1024M
|
||||||
|
reservations:
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
|
# 一次性建表任务,跑完即退出
|
||||||
|
tdengine-init:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
# 单节点 consul 常驻约 110~120 MB,给足余量避免贴边
|
||||||
|
consul:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
reservations:
|
||||||
|
memory: 96M
|
||||||
|
|
||||||
|
# ---------- 业务服务 ----------
|
||||||
|
admin-svr:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
admin-ui:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 64M
|
||||||
|
|
||||||
|
openapi:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 384M
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
upstream-chan:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 384M
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
upstream-proxy:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 384M
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
# 全量同步(流量/状态/IMEI)时内存抬升最明显,按文档「500 MB ~ 1 GB」给 1 GB
|
||||||
|
worker-svr:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1024M
|
||||||
|
reservations:
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
|
app-server:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
app-web:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 64M
|
||||||
|
|
||||||
|
sms:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 192M
|
||||||
|
|
||||||
|
docs:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 64M
|
||||||
|
|
||||||
|
# ---------- profile 可选服务 ----------
|
||||||
|
bot:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 192M
|
||||||
|
|
||||||
|
onelink-mock:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 192M
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128M
|
||||||
|
|
||||||
|
# 单端口入口(with-gateway);之前没有任何上限
|
||||||
|
gateway:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
# DNS 解析:nginx 只在启动时解析一次 upstream 主机名,admin-svr 重建换 IP 后
|
||||||
|
# /api/ 会一直 502。127.0.0.11 是 Docker 内置 DNS,resolve + zone 让运行期自动跟随。
|
||||||
|
resolver 127.0.0.11 valid=10s ipv6=off;
|
||||||
|
|
||||||
|
upstream gw_admin_svr { zone gw_admin_svr 64k; server admin-svr:8008 resolve; }
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
@@ -40,7 +46,7 @@ server {
|
|||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
chunked_transfer_encoding off;
|
chunked_transfer_encoding off;
|
||||||
proxy_pass http://admin-svr:8008/api/v1/;
|
proxy_pass http://gw_admin_svr/api/v1/;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# 单端口入口(默认对外 5051)
|
||||||
|
#
|
||||||
|
# 用途:把管理端、文档站、OpenAPI 收在一个端口下,便于在外部网关 / DNS
|
||||||
|
# 只暴露一个地址。编排里由 gateway 服务(profile: with-gateway)加载本文件,
|
||||||
|
# 容器内监听 80,宿主机发布端口用 GATEWAY_PORT 控制(默认 5051)。
|
||||||
|
#
|
||||||
|
# docker compose --profile with-gateway up -d
|
||||||
|
# GATEWAY_PORT=8088 docker compose --profile with-gateway up -d
|
||||||
|
#
|
||||||
|
# 路由:
|
||||||
|
# / -> 管理端(admin-ui,内部已代理 /api/ 到 admin-svr)
|
||||||
|
# /docs/ -> 文档站(docs)
|
||||||
|
# /www/ -> 官网(website,需启用 with-website profile)
|
||||||
|
# /openapi/ -> 对外 API(openapi)
|
||||||
|
# /route/open/ -> 运营商能力代理(openapi)
|
||||||
|
#
|
||||||
|
# 小程序 / H5 端的静态资源是根路径部署的,不能挂在同一域名的子路径下,
|
||||||
|
# 需要单独域名或单独端口(见 config/nginx/iotlcm.conf 的 app 段)。
|
||||||
|
|
||||||
|
# DNS 解析:nginx 默认只在启动时把 upstream 主机名解析一次,容器重建/重启换了 IP
|
||||||
|
# 就一直往旧地址打(2026-11-03 踩到:整站 /openapi 全 502,重启网关才恢复)。
|
||||||
|
# 127.0.0.11 是 Docker 内置 DNS;下面的 resolve + zone 让它在运行期自动跟随。
|
||||||
|
resolver 127.0.0.11 valid=10s ipv6=off;
|
||||||
|
|
||||||
|
upstream gw_admin_ui { zone gw_admin_ui 64k; server admin-ui:80 resolve; }
|
||||||
|
upstream gw_openapi { zone gw_openapi 64k; server openapi:8000 resolve; }
|
||||||
|
upstream gw_docs { zone gw_docs 64k; server docs:80 resolve; }
|
||||||
|
# 官网(可选组件,profile with-website)。容器未启动时该路径返回 502,
|
||||||
|
# 不影响其它路径;resolve 让容器 IP 变化后自动跟随。
|
||||||
|
upstream gw_website { zone gw_website 64k; server website:80 resolve; }
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
client_max_body_size 200m;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access_gateway.log;
|
||||||
|
error_log /var/log/nginx/error_gateway.log;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_read_timeout 120s;
|
||||||
|
proxy_send_timeout 120s;
|
||||||
|
|
||||||
|
# ---------- 文档站 ----------
|
||||||
|
location = /docs {
|
||||||
|
return 301 /docs/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /docs/ {
|
||||||
|
proxy_pass http://gw_docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- 官网(子路径形态) ----------
|
||||||
|
# 官网以 SITE_BASE=/www/ 构建时,资源引用是 /www/assets/...,
|
||||||
|
# 所以这里不能剥前缀(proxy_pass 不带尾斜杠),由官网容器内的
|
||||||
|
# alias 规则自己剥。域名定下来后改用独立 vhost,这段可删。
|
||||||
|
location = /www {
|
||||||
|
return 301 /www/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /www/ {
|
||||||
|
proxy_pass http://gw_website;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- 对外 API:版本化接口 ----------
|
||||||
|
location ^~ /openapi/ {
|
||||||
|
proxy_pass http://gw_openapi;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- 对外 API:运营商能力代理(白名单 / 共享 Token)----------
|
||||||
|
location ^~ /route/open/ {
|
||||||
|
proxy_pass http://gw_openapi;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- 管理端(含 /api/ 与 /upload/,由 admin-ui 自行转发)----------
|
||||||
|
location / {
|
||||||
|
proxy_pass http://gw_admin_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_min_length 1k;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;
|
||||||
|
}
|
||||||
@@ -8,28 +8,47 @@
|
|||||||
# 把 your-domain.example.com 替换为你的实际域名。
|
# 把 your-domain.example.com 替换为你的实际域名。
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
# ---------- 后端地址解析 ----------
|
||||||
|
# 这些 upstream 写的是 compose 服务名。nginx 默认只在**启动时**解析一次,
|
||||||
|
# 容器重建后 IP 变了就会持续 502(需重启 nginx)。resolve + zone 让它在运行期自动跟随。
|
||||||
|
# 注意:127.0.0.11 是 Docker 内置 DNS,仅在容器内有效:
|
||||||
|
# ・在容器内用本文件 → 保持下面的 resolver 不动
|
||||||
|
# ・把本文件并入宿主机 nginx → 把 resolver 换成宿主机 DNS(或删掉 resolver 与各 upstream 的 resolve 参数)
|
||||||
|
resolver 127.0.0.11 valid=10s ipv6=off;
|
||||||
|
|
||||||
upstream iotlcm_admin_api {
|
upstream iotlcm_admin_api {
|
||||||
server admin-svr:8008;
|
zone iotlcm_admin_api 64k;
|
||||||
|
server admin-svr:8008 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream iotlcm_admin_ui {
|
upstream iotlcm_admin_ui {
|
||||||
server admin-ui:80;
|
zone iotlcm_admin_ui 64k;
|
||||||
|
server admin-ui:80 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream iotlcm_openapi_api {
|
upstream iotlcm_openapi_api {
|
||||||
server openapi:8000;
|
zone iotlcm_openapi_api 64k;
|
||||||
|
server openapi:8000 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream iotlcm_docs {
|
upstream iotlcm_docs {
|
||||||
server docs:80;
|
zone iotlcm_docs 64k;
|
||||||
|
server docs:80 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream iotlcm_app_web {
|
upstream iotlcm_app_web {
|
||||||
server app-web:80;
|
zone iotlcm_app_web 64k;
|
||||||
|
server app-web:80 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream iotlcm_app_server {
|
upstream iotlcm_app_server {
|
||||||
server app-server:8010;
|
zone iotlcm_app_server 64k;
|
||||||
|
server app-server:8010 resolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream iotlcm_website {
|
||||||
|
zone iotlcm_website 64k;
|
||||||
|
server website:80 resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------- OpenAPI 对外域名 ----------
|
# ---------- OpenAPI 对外域名 ----------
|
||||||
@@ -103,6 +122,26 @@ server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------- 官网 ----------
|
||||||
|
# 独立域名形态:把 server_name 换成实际官网域名,
|
||||||
|
# 并让 DNS 指到这台机器。官网容器以 SITE_BASE=/ 构建(资源引用为 /assets/...),
|
||||||
|
# 所以这里按根路径转发。
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name www.your-domain.example.com;
|
||||||
|
|
||||||
|
client_max_body_size 200m;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://iotlcm_website;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ---------- 小程序 / H5 ----------
|
# ---------- 小程序 / H5 ----------
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|||||||
@@ -175,6 +175,14 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
# 就绪探针:nginx 类容器只在启动时解析一次后端 IP,
|
||||||
|
# 没有它就无法用 depends_on 的 service_healthy 保证启动顺序(见 gateway)
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1:8008/api.json"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
admin-ui:
|
admin-ui:
|
||||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4'
|
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4'
|
||||||
@@ -191,7 +199,14 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- iotlcm-network
|
- iotlcm-network
|
||||||
depends_on:
|
depends_on:
|
||||||
- admin-svr
|
admin-svr:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1/"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
openapi:
|
openapi:
|
||||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-openapi-v1.0.4'
|
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-openapi-v1.0.4'
|
||||||
@@ -213,6 +228,12 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1:8000/api.json"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
upstream-chan:
|
upstream-chan:
|
||||||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4'
|
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4'
|
||||||
@@ -370,6 +391,43 @@ services:
|
|||||||
- "127.0.0.1:8019:80"
|
- "127.0.0.1:8019:80"
|
||||||
networks:
|
networks:
|
||||||
- iotlcm-network
|
- iotlcm-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1/docs/"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
# ---------------- 官网(开源版门户站) ----------------
|
||||||
|
# 项目介绍、功能矩阵、快速开始、教程入口的门户站。
|
||||||
|
# 过渡形态(没有独立域名):单独占用一个宿主机端口,用 http://<主机>:8020/ 访问;
|
||||||
|
# 独立域名形态:把 DNS 指到这台机器,用 config/nginx/iotlcm.conf 的 website 段接管根路径。
|
||||||
|
# 镜像与 docs 同构(构建上下文 website/,Dockerfile website/Dockerfile)。
|
||||||
|
website:
|
||||||
|
# 官方镜像发布前先本地构建:docker compose --profile with-website up -d --build website
|
||||||
|
# 发布后删掉 build 段,直接用 ACR 镜像。
|
||||||
|
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-website-v1.0.4'
|
||||||
|
build:
|
||||||
|
context: ../website
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
SITE_BASE: '${WEBSITE_SITE_BASE:-/www/}'
|
||||||
|
container_name: iotlcm-website
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8020:80"
|
||||||
|
networks:
|
||||||
|
- iotlcm-network
|
||||||
|
# 探针路径与官网形态一致:默认以 SITE_BASE=/www/ 构建,官网在容器的 /www/ 下。
|
||||||
|
# 若改成独立域名形态(SITE_BASE=/),把这里的 /www/ 改成 /。
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1/www/"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
profiles:
|
||||||
|
- with-website
|
||||||
|
|
||||||
# ---------------- 可选:运营商接口挡板 ----------------
|
# ---------------- 可选:运营商接口挡板 ----------------
|
||||||
# 模拟中国移动 OneLink 接口,用于在没有真实运营商环境时联调整条链路:
|
# 模拟中国移动 OneLink 接口,用于在没有真实运营商环境时联调整条链路:
|
||||||
@@ -410,7 +468,7 @@ services:
|
|||||||
container_name: iotlcm-nginx
|
container_name: iotlcm-nginx
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "${NGINX_HTTP_PORT:-80}:80"
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/nginx:/etc/nginx/conf.d:ro
|
- ./config/nginx:/etc/nginx/conf.d:ro
|
||||||
- ./data/logs/nginx:/var/log/nginx
|
- ./data/logs/nginx:/var/log/nginx
|
||||||
@@ -418,13 +476,42 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- iotlcm-network
|
- iotlcm-network
|
||||||
depends_on:
|
depends_on:
|
||||||
- admin-ui
|
admin-ui:
|
||||||
- openapi
|
condition: service_healthy
|
||||||
- app-web
|
openapi:
|
||||||
- docs
|
condition: service_healthy
|
||||||
|
docs:
|
||||||
|
condition: service_healthy
|
||||||
|
app-web:
|
||||||
|
condition: service_started
|
||||||
profiles:
|
profiles:
|
||||||
- with-nginx
|
- with-nginx
|
||||||
|
|
||||||
|
# 单端口入口:管理端 + 文档站 + OpenAPI 收在一个端口(默认 5051)对外
|
||||||
|
gateway:
|
||||||
|
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:nginx-1.30'
|
||||||
|
container_name: iotlcm-gateway
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "${GATEWAY_PORT:-5051}:80"
|
||||||
|
volumes:
|
||||||
|
- ./config/gateway:/etc/nginx/conf.d:ro
|
||||||
|
- ./data/logs/gateway:/var/log/nginx
|
||||||
|
networks:
|
||||||
|
- iotlcm-network
|
||||||
|
# 后端必须"健康"后才起网关:否则 nginx 会在后端拿到 IP 之前把 upstream
|
||||||
|
# 解析结果缓存下来,容器重启换 IP 后所有请求变成 502(2026-11-03 踩过)。
|
||||||
|
# 配置里另有 resolver + resolve,可在运行期自动跟随 IP 变化。
|
||||||
|
depends_on:
|
||||||
|
admin-ui:
|
||||||
|
condition: service_healthy
|
||||||
|
openapi:
|
||||||
|
condition: service_healthy
|
||||||
|
docs:
|
||||||
|
condition: service_healthy
|
||||||
|
profiles:
|
||||||
|
- with-gateway
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
iotlcm-network:
|
iotlcm-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -5000,6 +5000,10 @@ INSERT INTO `sys_dict_data` (`dict_type`,`dict_value`,`dict_label`,`dict_sort`,`
|
|||||||
-- 注意 is_normal:0=正常、1=异常(见 chan 侧 model.SimChannelConfigItemCache.CanCreateInstance,
|
-- 注意 is_normal:0=正常、1=异常(见 chan 侧 model.SimChannelConfigItemCache.CanCreateInstance,
|
||||||
-- 只有 *IsNormal == 0 才会创建通道实例)。写成 1 会导致「通道未实例化」。
|
-- 只有 *IsNormal == 0 才会创建通道实例)。写成 1 会导致「通道未实例化」。
|
||||||
-- 这里的取值与内网演示环境种子不同(那边是 1),属开源版修正。
|
-- 这里的取值与内网演示环境种子不同(那边是 1),属开源版修正。
|
||||||
|
--
|
||||||
|
-- app_key / app_secret 是挡板(onelink-mock)的凭据,chan 侧用它们向挡板换 Token
|
||||||
|
-- (appid=app_key,password=app_secret)。取值必须与挡板默认凭据一致,
|
||||||
|
-- 见 onelink-mock/internal/service/store.go 的 defaultStore()。
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
|
|
||||||
INSERT INTO `t_sim_channels` (
|
INSERT INTO `t_sim_channels` (
|
||||||
@@ -5012,7 +5016,7 @@ INSERT INTO `t_sim_channels` (
|
|||||||
`card_info_count`,`stock_card_count`,`cancellation_card_count`
|
`card_info_count`,`stock_card_count`,`cancellation_card_count`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
34,'sim_yd_mock_v5','channel_yd_mock','移动模拟通道','{}',0,0,
|
34,'sim_yd_mock_v5','channel_yd_mock','移动模拟通道','{}',0,0,
|
||||||
'中国移动00',NULL,'100059999270000006','password123',NULL,
|
'中国移动00',NULL,'demo_appid','demo_password',NULL,
|
||||||
NULL,NULL,'',
|
NULL,NULL,'',
|
||||||
NULL,NULL,'http://onelink-mock:8080/',NULL,'000000',
|
NULL,NULL,'http://onelink-mock:8080/',NULL,'000000',
|
||||||
1,1,'2026-10-19 15:35:03',NULL,NOW(),
|
1,1,'2026-10-19 15:35:03',NULL,NOW(),
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ docker build --build-arg GOPROXY=https://goproxy.cn,direct -t ... .
|
|||||||
| admin-svr | `iotlcm-admin-svr-<TAG>` | `.../iotlcm/iotlcm:iotlcm-admin-svr-v1.0.4` |
|
| admin-svr | `iotlcm-admin-svr-<TAG>` | `.../iotlcm/iotlcm:iotlcm-admin-svr-v1.0.4` |
|
||||||
| admin-ui | `iotlcm-admin-ui-<TAG>` | `.../iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4` |
|
| admin-ui | `iotlcm-admin-ui-<TAG>` | `.../iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4` |
|
||||||
| openapi | `iotlcm-openapi-<TAG>` | `.../iotlcm/iotlcm:iotlcm-openapi-v1.0.4` |
|
| openapi | `iotlcm-openapi-<TAG>` | `.../iotlcm/iotlcm:iotlcm-openapi-v1.0.4` |
|
||||||
| app-server | `iotlcm-app-server-<TAG>` | `.../iotlcm/iotlcm:iotlcm-app-server-v1.0.4` |
|
| app-server | `iotlcm-app-server-<TAG>` | `.../iotlcm/iotlcm:iotlcm-app-server-v1.0.2` |
|
||||||
| app-web | `iotlcm-app-web-<TAG>` | `.../iotlcm/iotlcm:iotlcm-app-web-v1.0.4` |
|
| app-web | `iotlcm-app-web-<TAG>` | `.../iotlcm/iotlcm:iotlcm-app-web-v1.0.2` |
|
||||||
| upstream-chan | `iotlcm-upstream-chan-<TAG>` | `.../iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4` |
|
| upstream-chan | `iotlcm-upstream-chan-<TAG>` | `.../iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4` |
|
||||||
| upstream-proxy | `iotlcm-upstream-proxy-<TAG>` | `.../iotlcm/iotlcm:iotlcm-upstream-proxy-v1.0.4` |
|
| upstream-proxy | `iotlcm-upstream-proxy-<TAG>` | `.../iotlcm/iotlcm:iotlcm-upstream-proxy-v1.0.4` |
|
||||||
| worker-svr | `iotlcm-worker-svr-<TAG>` | `.../iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4` |
|
| worker-svr | `iotlcm-worker-svr-<TAG>` | `.../iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4` |
|
||||||
@@ -151,6 +151,11 @@ docker build --build-arg GOPROXY=https://goproxy.cn,direct -t ... .
|
|||||||
|
|
||||||
基础组件(`mysql`、`redis`、`rabbitmq`、`consul`、`nginx`)不需要构建,从上游同步到同一仓库即可,tag 为 `<组件>-<版本>`,见下节。
|
基础组件(`mysql`、`redis`、`rabbitmq`、`consul`、`nginx`)不需要构建,从上游同步到同一仓库即可,tag 为 `<组件>-<版本>`,见下节。
|
||||||
|
|
||||||
|
::: tip app 线是独立版本
|
||||||
|
`iotlcm-app-server` 与 `iotlcm-app-web` 属于**小程序线**,版本号与平台 tag 解耦:平台发 v1.0.4 时它们仍是 `v1.0.2`。
|
||||||
|
自建镜像时按 `iotlcm-app-<x>-v1.0.2` 命名,不要跟着平台版本走。
|
||||||
|
:::
|
||||||
|
|
||||||
::: warning tag 必须带上服务名
|
::: warning tag 必须带上服务名
|
||||||
同一个仓库里 tag 不能重复。只用版本号(如 `v1.0.4`)会让 12 个服务互相覆盖,因此 tag 固定为 `<服务名>-<版本>`。
|
同一个仓库里 tag 不能重复。只用版本号(如 `v1.0.4`)会让 12 个服务互相覆盖,因此 tag 固定为 `<服务名>-<版本>`。
|
||||||
:::
|
:::
|
||||||
|
|||||||
@@ -16,18 +16,23 @@ cd iotlcm/deploy
|
|||||||
```text
|
```text
|
||||||
deploy/
|
deploy/
|
||||||
├── docker-compose.yml # 服务编排(含默认口令与端口)
|
├── docker-compose.yml # 服务编排(含默认口令与端口)
|
||||||
├── config/ # 各服务配置,10 份,已带可用默认值
|
├── config/ # 各服务配置 + gateway / nginx 两种入口配置
|
||||||
└── schema/ # 数据库初始化脚本,13 个,首次启动自动执行
|
├── schema/init.sql # MySQL 初始化(单文件,95 表 + 种子数据)
|
||||||
|
├── tdengine-init/ # 时序库建库建表(首次启动自动执行)
|
||||||
|
└── data/ # 运行数据,首次启动自动创建
|
||||||
```
|
```
|
||||||
|
|
||||||
## 部署内容
|
## 部署内容
|
||||||
|
|
||||||
| 类别 | 服务 |
|
| 类别 | 服务 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 基础组件 | MySQL、Redis、RabbitMQ、Consul |
|
| 基础组件 | MySQL、Redis、RabbitMQ、Consul、TDengine(流量历史) |
|
||||||
| 管理端 | admin-svr(后端)、admin-ui(前端) |
|
| 管理端 | admin-svr(后端 8008)、admin-ui(前端 8009) |
|
||||||
| 对外接口 | openapi |
|
| 对外接口 | openapi(8000) |
|
||||||
| 小程序 / H5 | app-server(后端)、app-web(前端) |
|
| 小程序 / H5 | app-server(8010)、app-web(8018) |
|
||||||
|
| 通道 | upstream-chan(8110 / 8310)、upstream-proxy(8510) |
|
||||||
|
| 异步与配套 | worker-svr、sms(11190)、docs(8019) |
|
||||||
|
| 可选 | onelink-mock(接口挡板)、bot(飞书通知)、nginx(多域名入口)、gateway(单端口入口 5051) |
|
||||||
| 运营商对接 | upstream-chan(协议适配)、upstream-proxy(缓存转发) |
|
| 运营商对接 | upstream-chan(协议适配)、upstream-proxy(缓存转发) |
|
||||||
| 异步任务 | worker-svr(批次执行、全量同步) |
|
| 异步任务 | worker-svr(批次执行、全量同步) |
|
||||||
| 配套 | sms(短信)、docs(本文档站) |
|
| 配套 | sms(短信)、docs(本文档站) |
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:11190/healthz
|
|||||||
|
|
||||||
### 7. 浏览器登录
|
### 7. 浏览器登录
|
||||||
|
|
||||||
访问 `http://<宿主机IP>:8009`:
|
访问 `http://127.0.0.1:8009`(编排默认把业务端口绑定在 `127.0.0.1`;需要从其他机器访问时,用 `--profile with-nginx` 起反向代理,或改绑定地址):
|
||||||
|
|
||||||
| 项 | 值 |
|
| 项 | 值 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
|||||||
@@ -88,6 +88,36 @@ docker compose --profile with-bot up -d
|
|||||||
|
|
||||||
bot 读取 `worker-svr` 生成的全量同步归档(`./data/logs/worker-svr/full-sync`),该目录有数据后才会产生通知。
|
bot 读取 `worker-svr` 生成的全量同步归档(`./data/logs/worker-svr/full-sync`),该目录有数据后才会产生通知。
|
||||||
|
|
||||||
|
## 单端口入口
|
||||||
|
|
||||||
|
### 用途
|
||||||
|
|
||||||
|
只对外暴露**一个端口**(默认 5051),把管理端、文档站、OpenAPI 收在一起。适合外面还有一层网关 / DNS,
|
||||||
|
或者只想开放一个端口的环境。
|
||||||
|
|
||||||
|
### 路由
|
||||||
|
|
||||||
|
| 路径 | 去向 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/` | 管理端(admin-ui,内部已代理 `/api/` 到 admin-svr) |
|
||||||
|
| `/docs/` | 文档站 |
|
||||||
|
| `/openapi/` | 对外 API |
|
||||||
|
| `/route/open/` | 运营商能力代理(白名单 / 共享 Token) |
|
||||||
|
|
||||||
|
### 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile with-gateway up -d
|
||||||
|
# 换端口
|
||||||
|
GATEWAY_PORT=8088 docker compose --profile with-gateway up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
配置见 `config/gateway/nginx.conf`。
|
||||||
|
|
||||||
|
::: tip 小程序 / H5 端不在单端口内
|
||||||
|
`app-web` 的静态资源是根路径部署的,挂到子路径会白屏。小程序端需要单独域名或端口,用下面的反向代理方式。
|
||||||
|
:::
|
||||||
|
|
||||||
## 反向代理
|
## 反向代理
|
||||||
|
|
||||||
### 用途
|
### 用途
|
||||||
@@ -110,7 +140,7 @@ bot 读取 `worker-svr` 生成的全量同步归档(`./data/logs/worker-svr/fu
|
|||||||
docker compose --profile with-nginx up -d
|
docker compose --profile with-nginx up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
默认监听 80,改 `docker-compose.yml` 的 `NGINX_HTTP_PORT` 可调整。
|
默认监听 80,对外端口由 `NGINX_HTTP_PORT` 控制:`NGINX_HTTP_PORT=8080 docker compose --profile with-nginx up -d`。
|
||||||
|
|
||||||
### 使用宿主机 nginx
|
### 使用宿主机 nginx
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
.vitepress/cache
|
||||||
|
.vitepress/dist
|
||||||
|
.vitepress/.temp
|
||||||
|
dist
|
||||||
|
*.log
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
registry=https://registry.npmmirror.com/
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官网(开源版门户站)构建配置
|
||||||
|
*
|
||||||
|
* SITE_BASE 由构建参数注入:
|
||||||
|
* - /www/ 过渡形态:挂在统一网关的 /www/ 路径下(没有独立域名时用)
|
||||||
|
* - / 独立域名形态:站点独占域名根路径
|
||||||
|
* 两者内容完全同源,差别只有资源前缀与路由前缀,所以用构建参数而不是改代码。
|
||||||
|
*/
|
||||||
|
const SITE_BASE = process.env.SITE_BASE ?? '/www/'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库地址。开源版代码只发 git.5iot.com/iotlcm-public,
|
||||||
|
* 若后续确认了公开镜像站,改这一处即可(页面里统一引用常量,不重复硬编码)。
|
||||||
|
*/
|
||||||
|
const REPO_URL = process.env.REPO_URL ?? 'https://git.5iot.com/iotlcm-public/iotlcm'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文档站地址。文档站与官网是两个容器,由网关按路径分流:
|
||||||
|
* - 官网在 /www/ 下,文档站在 /docs/ 下,两者同级
|
||||||
|
*
|
||||||
|
* 注意:VitePress 会给所有站内链接自动加上 base 前缀,'/docs/' 会被拼成
|
||||||
|
* '/www/docs/'——而网关并没有这个路径,点击「文档中心」会 404。
|
||||||
|
* 因此默认值必须是完整 URL(VitePress 判定为外链,不做前缀拼接)。
|
||||||
|
* 独立部署时用 DOCS_URL 覆盖成实际地址。
|
||||||
|
*/
|
||||||
|
const DOCS_URL = process.env.DOCS_URL ?? 'http://open.5iot.com:5051/docs/'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
srcDir: './pages',
|
||||||
|
base: SITE_BASE,
|
||||||
|
title: 'iotLCM',
|
||||||
|
description: 'iotLCM 物联网卡全生命周期管理平台(开源版)',
|
||||||
|
lang: 'zh-CN',
|
||||||
|
cleanUrls: true,
|
||||||
|
lastUpdated: false,
|
||||||
|
head: [
|
||||||
|
['link', { rel: 'icon', type: 'image/svg+xml', href: `${SITE_BASE}favicon.svg` }],
|
||||||
|
],
|
||||||
|
themeConfig: {
|
||||||
|
nav: [
|
||||||
|
{ text: '首页', link: '/' },
|
||||||
|
{ text: '功能', link: '/features' },
|
||||||
|
{ text: '方案对比', link: '/compare' },
|
||||||
|
{ text: '快速开始', link: '/guide/quickstart' },
|
||||||
|
{ text: '教程', link: '/guide/tutorial' },
|
||||||
|
{ text: '社区', link: '/community' },
|
||||||
|
{ text: '文档中心', link: DOCS_URL },
|
||||||
|
],
|
||||||
|
sidebar: {
|
||||||
|
'/guide/': [
|
||||||
|
{
|
||||||
|
text: '指南',
|
||||||
|
collapsed: false,
|
||||||
|
items: [
|
||||||
|
{ text: '快速开始', link: '/guide/quickstart' },
|
||||||
|
{ text: '部署与运维', link: '/guide/deploy' },
|
||||||
|
{ text: '教程视频', link: '/guide/tutorial' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: REPO_URL },
|
||||||
|
],
|
||||||
|
footer: {
|
||||||
|
message: 'iotLCM 开源版 · Apache-2.0',
|
||||||
|
copyright: 'Copyright © iotLCM',
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
provider: 'local',
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
level: [2, 3],
|
||||||
|
label: '本页目录',
|
||||||
|
},
|
||||||
|
docFooter: {
|
||||||
|
prev: '上一页',
|
||||||
|
next: '下一页',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import type { Theme } from 'vitepress'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
extends: DefaultTheme,
|
||||||
|
} satisfies Theme
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# 官网(开源版门户站)构建镜像
|
||||||
|
#
|
||||||
|
# 与 docs/ 同一套构建思路:Node 构建 VitePress 产物,Nginx 托管静态文件。
|
||||||
|
#
|
||||||
|
# 构建参数:
|
||||||
|
# SITE_BASE —— 站点资源前缀,同时决定容器内 nginx 的形态:
|
||||||
|
# /www/ 过渡形态:挂在统一网关的 /www/ 路径下(没有独立域名时用)
|
||||||
|
# / 独立域名形态:站点独占域名根路径
|
||||||
|
#
|
||||||
|
# 前缀与 nginx 形态必须配套:VitePress 产物里的资源引用是绝对路径
|
||||||
|
# (<base>assets/xxx),base=/www/ 时只能由带 alias 的 location 提供服务;
|
||||||
|
# base=/ 时只能由根路径 location 提供服务。混用会出现「页面 200 但 JS/CSS 全 404」。
|
||||||
|
#
|
||||||
|
# 用法(仓库根目录):
|
||||||
|
# docker build -f website/Dockerfile -t iotlcm-website:dev \
|
||||||
|
# --build-arg SITE_BASE=/www/ website/
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
|
||||||
|
ARG SITE_BASE=/www/
|
||||||
|
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
|
||||||
|
&& apk add --no-cache git
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json .npmrc ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN SITE_BASE=${SITE_BASE} npm run build
|
||||||
|
|
||||||
|
FROM nginx:1.27-alpine
|
||||||
|
|
||||||
|
ARG SITE_BASE=/www/
|
||||||
|
|
||||||
|
COPY --from=builder /app/.vitepress/dist /usr/share/nginx/html
|
||||||
|
COPY docker/nginx.root.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY docker/nginx.prefix.conf /tmp/nginx.prefix.conf
|
||||||
|
RUN set -eu; \
|
||||||
|
base="${SITE_BASE%/}"; \
|
||||||
|
if [ "$base" = "" ]; then \
|
||||||
|
echo "官网形态:独立域名(根路径)"; \
|
||||||
|
else \
|
||||||
|
sed -e "s|__SITE_BASE__|${SITE_BASE}|g" -e "s|__SITE_BASE_NO_SLASH__|${base}|g" \
|
||||||
|
/tmp/nginx.prefix.conf > /etc/nginx/conf.d/default.conf; \
|
||||||
|
echo "官网形态:子路径 ${SITE_BASE}"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 过渡形态:站点挂在统一网关的子路径下(没有独立域名时用)。
|
||||||
|
#
|
||||||
|
# VitePress 产物里的资源引用是绝对路径(<base>assets/xxx),
|
||||||
|
# 而 dist 目录是平铺的(index.html、assets/ 直接在根)。
|
||||||
|
# 因此必须在子路径下用 alias 把前缀剥掉再落到产物目录,
|
||||||
|
# 否则页面能返回 200 但 JS/CSS 全部 404 → 白屏。
|
||||||
|
# 网关侧对应 location ^~ <prefix> { proxy_pass http://gw_website; }(不剥前缀)。
|
||||||
|
location __SITE_BASE__ {
|
||||||
|
alias /usr/share/nginx/html/;
|
||||||
|
try_files $uri $uri.html $uri/ $uri/index.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 访问不带尾斜杠的前缀时补斜杠,否则相对资源路径会解析错
|
||||||
|
location = __SITE_BASE_NO_SLASH__ {
|
||||||
|
return 301 __SITE_BASE__;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 独立域名形态:站点独占域名根路径,产物平铺在根目录。
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri.html $uri/ =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+2534
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "iotlcm-website",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vitepress dev . --host 127.0.0.1",
|
||||||
|
"build": "vitepress build .",
|
||||||
|
"preview": "vitepress preview . --host 127.0.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitepress": "^1.6.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
title: 社区
|
||||||
|
description: 如何参与 iotLCM 开源版
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 社区
|
||||||
|
|
||||||
|
## 源码仓库
|
||||||
|
|
||||||
|
```
|
||||||
|
https://git.5iot.com/iotlcm-public/iotlcm
|
||||||
|
```
|
||||||
|
|
||||||
|
单仓多服务:全部后端服务、前端应用、文档站与部署编排都在同一个仓库里。分支与标签规范见仓库内的 `README.md`。
|
||||||
|
|
||||||
|
## 许可
|
||||||
|
|
||||||
|
Apache-2.0。可自由使用、修改、商用与分发;分发时保留版权声明与许可证原文,并对修改部分注明变更。
|
||||||
|
|
||||||
|
各子目录的上游依赖保留其原始许可(前端模板基于 Vben Admin / MIT,用户端基于 unibest / MIT)。
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
|
||||||
|
1. 从 `main` 切出特性分支,命名 `feat/xxx`、`fix/xxx`
|
||||||
|
2. 改动保持单一职责,提交信息用中文说明「做了什么」与「为什么」
|
||||||
|
3. Go 服务改动补单元测试;前端改动说明验证方式
|
||||||
|
4. 文档改动同步更新 `docs/`(文档站源码)与本官网
|
||||||
|
5. 提交合入请求前自检:能否编译、测试是否通过、部署编排是否需要同步变更
|
||||||
|
|
||||||
|
## 提问与反馈
|
||||||
|
|
||||||
|
- 使用问题与缺陷:仓库 issue
|
||||||
|
- 功能建议:仓库 issue,描述清楚场景与期望
|
||||||
|
- 部署排错:先看[部署与运维](/guide/deploy)的常见问题表,再开 issue 附上 `docker compose ps` 与相关日志
|
||||||
|
|
||||||
|
## 运维自用组件的边界
|
||||||
|
|
||||||
|
飞书通知机器人(`with-bot` profile)是给运维方自用的工具,需要自建应用的凭据才能启动,**不是平台功能**,未配置时不影响平台运行。
|
||||||
|
|
||||||
|
运营商通道的生产凭据不随仓发布,需自行向运营商申请。
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
title: 方案对比
|
||||||
|
description: iotLCM 开源版与同类开源方案的能力对比
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 方案对比
|
||||||
|
|
||||||
|
::: warning 本页待补
|
||||||
|
本页需要「与同行的对比」素材,而该素材依赖产品侧梳理各家官网后给出的结论
|
||||||
|
(周会任务 261102-002 的前置依赖)。骨架已就位,等对比结论到位后填表即可,
|
||||||
|
框架与其它页面一致,不需要再改代码。
|
||||||
|
|
||||||
|
对比口径建议按「能不能装起来 / 能不能接运营商 / 能不能管住卡 / 二次开发成本」四条线走,
|
||||||
|
每条线只写能公开验证的事实(官网文档、许可证、仓库结构),不写主观评价。
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 对比维度(待填)
|
||||||
|
|
||||||
|
| 维度 | 说明 | 可验证依据 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 部署门槛 | 是否单机一条命令起、依赖多少中间件 | 官方部署文档 |
|
||||||
|
| 运营商接入 | 支持哪些运营商协议、是否需要逐家申请凭据 | 官方接口文档 |
|
||||||
|
| 卡生命周期 | 入库、划拨、激活、续费、停机、销户覆盖到哪一步 | 官方功能手册 |
|
||||||
|
| 流量与用量 | 实时用量、月累计、达量断网 | 官方功能手册 |
|
||||||
|
| 对外接口 | OpenAPI 版本、鉴权方式、兼容策略 | 官方接口合同 |
|
||||||
|
| 账号与权限 | 多租户、角色、API 凭证 | 官方功能手册 |
|
||||||
|
| 许可证 | 商用与再分发限制 | 仓库 LICENSE |
|
||||||
|
| 二次开发 | 技术栈、语言、代码规模、模块边界 | 仓库结构 |
|
||||||
|
| 文档与教程 | 有无完整手册、部署文档、录屏教程 | 官网与仓库 |
|
||||||
|
|
||||||
|
## 本方案的已知事实
|
||||||
|
|
||||||
|
写这张表时,下面这些是本方案自身已经确定、可直接引用的:
|
||||||
|
|
||||||
|
- 单仓多服务,一次 clone 拿到全部后端服务、前端应用、文档站与部署编排
|
||||||
|
- 一条命令部署:`cd deploy && docker compose up -d`,实测约 30 秒 ~ 1 分钟完成初始化
|
||||||
|
- 运营商协议内置:中国移动 OneLink、中国电信 5G CMP、中国联通 10646,另有共享 Token 接入多家三方渠道商
|
||||||
|
- 卡生命周期覆盖入库 → 划拨 → 激活/续费/停机 → 流量与状态同步 → 销户
|
||||||
|
- 对外接口:OpenAPI V3 + 旧版兼容接口 + 运营商能力代理
|
||||||
|
- 双端界面:Web 管理平台与小程序端(H5)
|
||||||
|
- 许可证:Apache-2.0
|
||||||
|
- 文档站随仓发布,含使用手册、OpenAPI 合同与部署手册
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
title: 功能
|
||||||
|
description: iotLCM 开源版覆盖的业务能力
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 功能
|
||||||
|
|
||||||
|
## 卡与库存
|
||||||
|
|
||||||
|
- 卡信息查询:按 ICCID / MSISDN / IMSI 三码检索,查看激活状态、套餐、有效期、流量用量、绑定关系
|
||||||
|
- 库存与划拨:渠道入库后按代理商维度划拨,支持批量操作
|
||||||
|
- 通信管理:卡的生命周期状态在库内集中管理
|
||||||
|
- 批量 IMEI 查询:一次提交批量查询终端号
|
||||||
|
- 智能诊断:结合卡状态、通道与用量给出诊断结论与处置建议
|
||||||
|
|
||||||
|
## 资费与计费
|
||||||
|
|
||||||
|
- 套餐与定价管理:套餐定义、有效期规则、达量断网阈值
|
||||||
|
- 用量与流量查询:实时用量、月度累计,覆盖多维筛选
|
||||||
|
- 业务受理:开通、续费、停复机、变更套餐
|
||||||
|
|
||||||
|
## 通道与上游
|
||||||
|
|
||||||
|
- 通道管理:统一维护上游通道配置与凭据
|
||||||
|
- 协议适配:内置中国移动 OneLink、中国电信 5G CMP、中国联通 10646 适配
|
||||||
|
- 共享 Token 接入:多家三方渠道商共用一套调用链
|
||||||
|
- 缓存转发:通道层前置缓存,降低对运营商接口的直接压力
|
||||||
|
- 接口挡板:onelink-mock 可在无真实运营商环境时联调整条链路
|
||||||
|
|
||||||
|
## 组织与账号
|
||||||
|
|
||||||
|
- 企业、用户与角色:多租户下的企业与账号治理、角色权限分配
|
||||||
|
- API 凭证:对外调用凭证的申请与轮换
|
||||||
|
- 执行日志:批量任务与接口调用的执行记录
|
||||||
|
|
||||||
|
## 运维支撑
|
||||||
|
|
||||||
|
- 全量同步:卡状态、IMEI、流量等数据的周期对齐
|
||||||
|
- 批次执行:批量开停复机、续费、变更套餐,异步执行并有进度查询
|
||||||
|
- 工单管理:告警与异常的工单化处理
|
||||||
|
- 告警与预警:关键状态变化的主动提醒
|
||||||
|
- 飞书通知:把运维事件推送到飞书群(可选组件)
|
||||||
|
- 指标与日志:Consul 注册与健康探针、Prometheus 指标入口
|
||||||
|
|
||||||
|
## 文档与接口
|
||||||
|
|
||||||
|
- [使用手册](/guide/deploy) — Web 端与小程序端的分场景说明
|
||||||
|
- [OpenAPI 接口合同](/guide/deploy#对外接口) — 鉴权、请求参数、响应结构与调用示例
|
||||||
|
- [部署手册](/guide/deploy) — 环境要求、配置项、离线部署、排错
|
||||||
|
|
||||||
|
## 边界
|
||||||
|
|
||||||
|
开源版发布的是微服务家族,不含老平台的私有定制模块。运营商通道的生产凭据不随仓发布,需自行申请与配置。
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
title: 部署与运维
|
||||||
|
description: 生产部署前的必改项、可选组件、离线部署与常见问题
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 部署与运维
|
||||||
|
|
||||||
|
## 一键启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.5iot.com/iotlcm-public/iotlcm.git
|
||||||
|
cd iotlcm/deploy
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
部署编排与数据库初始化脚本都在仓库的 `deploy/` 目录:
|
||||||
|
|
||||||
|
```text
|
||||||
|
deploy/
|
||||||
|
├── docker-compose.yml # 服务编排(含默认口令与端口)
|
||||||
|
├── compose.memlimit.yml # 容器内存上限(按机器规格叠加使用)
|
||||||
|
├── config/ # 各服务配置 + gateway / nginx 两种入口配置
|
||||||
|
├── schema/init.sql # MySQL 初始化(95 表 + 种子数据)
|
||||||
|
├── tdengine-init/ # 时序库建库建表(首次启动自动执行)
|
||||||
|
└── data/ # 运行数据,首次启动自动创建
|
||||||
|
```
|
||||||
|
|
||||||
|
## 可选组件
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile with-mock up -d # 运营商接口挡板
|
||||||
|
docker compose --profile with-bot up -d # 飞书通知(运维自用)
|
||||||
|
docker compose --profile with-nginx up -d # 自带反向代理(多域名入口)
|
||||||
|
docker compose --profile with-gateway up -d # 单端口入口(默认对外 5051)
|
||||||
|
```
|
||||||
|
|
||||||
|
多个 profile 可组合。
|
||||||
|
|
||||||
|
### 单端口入口(with-gateway)
|
||||||
|
|
||||||
|
只暴露一个端口时用它。容器内监听 80,宿主机端口由 `GATEWAY_PORT` 控制(默认 5051):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile with-gateway up -d
|
||||||
|
GATEWAY_PORT=8088 docker compose --profile with-gateway up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
路由:
|
||||||
|
|
||||||
|
| 路径 | 目标 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/` | 管理端 |
|
||||||
|
| `/docs/` | 文档站 |
|
||||||
|
| `/openapi/` | 对外 API |
|
||||||
|
| `/route/open/` | 运营商能力代理 |
|
||||||
|
|
||||||
|
小程序 / H5 端的静态资源是根路径部署的,不能挂在同一域名的子路径下,需要单独域名或单独端口。
|
||||||
|
|
||||||
|
### 多域名入口(with-nginx)
|
||||||
|
|
||||||
|
宿主机已有 nginx 或面板时不启动这个容器,把 `deploy/config/nginx/iotlcm.conf` 里的 `location` 段落并入宿主机配置即可。
|
||||||
|
|
||||||
|
## 线上暴露到公网
|
||||||
|
|
||||||
|
80 / 443 入站在多数办公宽带上被运营商封禁,评估过三种可行形态:
|
||||||
|
|
||||||
|
| 形态 | 适用 | 代价 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 高位端口 NAT | 内部验收、演示 | 地址带端口,不适合对外正式发布 |
|
||||||
|
| 独立子域 + 反代 | 有公网 IP 的服务器 | 需要域名解析与证书 |
|
||||||
|
| 云主机统一入口 | 正式对外发布 | 需要域名(以及国内服务器的备案) |
|
||||||
|
|
||||||
|
## 上线前必改
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 数据库口令 | MySQL 的 root 与应用账号口令 |
|
||||||
|
| Redis 口令 | 缓存层口令 |
|
||||||
|
| RabbitMQ 口令 | 队列层口令 |
|
||||||
|
| admin 口令 | 种子账号初始口令统一重置过,必须改 |
|
||||||
|
| JWT 密钥 | 管理端与用户端签发令牌用 |
|
||||||
|
| 运营商通道凭据 | 通道配置的 appKey / appSecret / 账号,按运营商要求申请 |
|
||||||
|
| 对象存储 | 图片与附件的存放位置 |
|
||||||
|
|
||||||
|
## 离线部署
|
||||||
|
|
||||||
|
目标机器不能出网时:
|
||||||
|
|
||||||
|
1. 在有网机器上拉全部镜像并导出:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull
|
||||||
|
docker save -o iotlcm-images.tar $(docker compose config --images)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 拷贝 `iotlcm-images.tar` 与仓库的 `deploy/` 目录到目标机器;
|
||||||
|
3. `docker load -i iotlcm-images.tar` 后再 `docker compose up -d`。
|
||||||
|
|
||||||
|
细节见文档站的部署章节。
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
| 现象 | 原因与处置 |
|
||||||
|
| --- | --- |
|
||||||
|
| MySQL 初始化中途失败 | schema 只在数据卷为空时执行,改完脚本必须清空卷才会重跑:`docker compose down && sudo rm -rf ./data/mysql && docker compose up -d` |
|
||||||
|
| 访问 8019 端口白屏 | 文档站必须带 `/docs/` 路径,裸端口会白屏 |
|
||||||
|
| 偶发 502 | 容器重建后 upstream IP 变化,nginx 未重新解析;配置已带 `resolver` + `resolve`,若仍出现,重启网关容器即可 |
|
||||||
|
| 通道调用报 IP 鉴权失败 | 运营商侧需要报备出口 IP,未报备则拒绝调用 |
|
||||||
|
| 端口被占用 | 编排里业务端口默认绑 `127.0.0.1`,改端口映射即可避开冲突 |
|
||||||
|
|
||||||
|
## 监控
|
||||||
|
|
||||||
|
Consul 提供服务注册与健康探针,Prometheus 指标入口在编排内已开。日志按服务落在 `deploy/data/logs/` 下,配合 logrotate 生效。
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
title: 快速开始
|
||||||
|
description: 三步把 iotLCM 开源版跑起来
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 快速开始
|
||||||
|
|
||||||
|
## 前置条件
|
||||||
|
|
||||||
|
| 项 | 要求 |
|
||||||
|
| --- | --- |
|
||||||
|
| 操作系统 | Linux(x86_64 / arm64) |
|
||||||
|
| Docker | 20.10 以上,含 Compose V2(`docker compose version` 可用) |
|
||||||
|
| 内存 | 建议 4 GB 以上 |
|
||||||
|
| 磁盘 | 建议 40 GB 以上(含镜像与数据库) |
|
||||||
|
| 端口 | 3306 / 6379 / 5672 / 6041 / 6030 / 8500 默认占用,起步前先确认空闲 |
|
||||||
|
|
||||||
|
## 第一步:取代码
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.5iot.com/iotlcm-public/iotlcm.git
|
||||||
|
cd iotlcm
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第二步:起栈
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
不需要复制或修改任何文件,编排里已带可用的默认配置。首次启动会自动:
|
||||||
|
|
||||||
|
1. MySQL 建库并导入 schema(13 个脚本按序执行:建表 → 结构补齐 → 创建应用账号 → 重置种子账号口令 → 导入通道模板、字典、菜单等种子数据),约 30 秒 ~ 1 分钟
|
||||||
|
2. TDengine 自动建库建表(流量历史库)
|
||||||
|
3. 其余服务依次启动并向 Consul 注册
|
||||||
|
|
||||||
|
观察进度:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
看到 `[initdb] 应用账号 u_iotlcm 已创建` 与 `[initdb] 种子账号口令已统一重置` 表示初始化完成。
|
||||||
|
|
||||||
|
## 第三步:登录
|
||||||
|
|
||||||
|
部署完成后访问 `http://127.0.0.1:8009`,账号 `admin`,初始口令见 `deploy/README.md`。
|
||||||
|
|
||||||
|
> **正式使用前必须修改默认口令**:数据库、Redis、RabbitMQ、admin 账号口令与 JWT 密钥。清单见部署手册的「上线前必改」。
|
||||||
|
|
||||||
|
## 端口对照
|
||||||
|
|
||||||
|
| 服务 | 宿主机端口 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 管理端 | 8009 | Web 管理平台 |
|
||||||
|
| 对外接口 | 8000 | OpenAPI V3 与兼容接口 |
|
||||||
|
| 用户端 | 8018 | 小程序 / H5 |
|
||||||
|
| 文档站 | 8019 | 使用手册与接口文档,必须带 `/docs/` 路径 |
|
||||||
|
| 运营商对接 | 8110 / 8310 | 通道协议适配 |
|
||||||
|
| 通道缓存 | 8510 | 缓存转发 |
|
||||||
|
| MySQL | 3306 | 库名 `db_iotlcm` |
|
||||||
|
| Redis | 6379 | 缓存与运行状态 |
|
||||||
|
| RabbitMQ | 5672 / 15672 | 队列与管理界面 |
|
||||||
|
| TDengine | 6041 / 6030 | 时序库 |
|
||||||
|
| Consul | 8500 | 服务注册 |
|
||||||
|
|
||||||
|
编排默认把业务端口绑定在 `127.0.0.1`,需要局域网或公网访问时,改用反向代理编排或并入宿主机已有的 nginx。
|
||||||
|
|
||||||
|
## 停止与清理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down # 停止,数据保留
|
||||||
|
docker compose down -v # 停止并删除数据卷(不可恢复)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 下一步
|
||||||
|
|
||||||
|
- [部署与运维](/guide/deploy) — 生产部署前的必改项、可选组件、离线部署与排错
|
||||||
|
- [教程视频](/guide/tutorial) — 跟着录屏走一遍
|
||||||
|
- [功能](/features) — 平台能做什么
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
title: 教程视频
|
||||||
|
description: 部署与使用的录屏教程
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# 教程视频
|
||||||
|
|
||||||
|
开源版的上手路径只有两条:**把平台跑起来**(部署)与**把平台用起来**(使用)。两条路径各一支录屏视频,文字文档只作配套说明,不替代视频。
|
||||||
|
|
||||||
|
## 部署教程
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 标题 | iotLCM 开源版部署教程:从零到可用 |
|
||||||
|
| 目标观众 | 第一次接触本项目、具备 Linux 与 Docker 基础的开发者与实施工程师 |
|
||||||
|
| 时长 | 12 ~ 15 分钟 |
|
||||||
|
| 发布位置 | 官网本页 + 源码仓库 README 顶部 + B 站 |
|
||||||
|
| 关联文档 | [快速开始](/guide/quickstart)、[部署与运维](/guide/deploy) |
|
||||||
|
| 关联仓库路径 | `deploy/`、`website/`、`docs/` |
|
||||||
|
|
||||||
|
视频覆盖:
|
||||||
|
|
||||||
|
1. 环境准备:Docker 与 Compose 版本检查、端口占用确认、机器规格建议
|
||||||
|
2. 取代码:`git clone` 公开仓库,确认目录结构
|
||||||
|
3. 启动:`docker compose up -d`,观察 MySQL 初始化日志直到种子数据导入完成
|
||||||
|
4. 验证:登录管理端、打开文档站与 OpenAPI 文档、跑一次状态查询
|
||||||
|
5. 收尾:改默认口令、停栈与清理数据卷
|
||||||
|
|
||||||
|
## 使用教程
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 标题 | iotLCM 开源版使用教程:核心功能实操 |
|
||||||
|
| 目标观众 | 已完成部署、准备给业务方上手的管理员与运营人员 |
|
||||||
|
| 时长 | 15 ~ 20 分钟 |
|
||||||
|
| 发布位置 | 官网本页 + 源码仓库 README 顶部 + B 站 |
|
||||||
|
| 关联文档 | [功能](/features)、文档站的使用手册 |
|
||||||
|
| 关联仓库路径 | `admin-svr/`、`admin-ui/`、`openapi/`、`worker-svr/` |
|
||||||
|
|
||||||
|
视频覆盖:
|
||||||
|
|
||||||
|
1. 卡信息:列表检索、按三码查卡、卡详情与用量查看
|
||||||
|
2. 库存与划拨:入库后的代理商维度划拨
|
||||||
|
3. 资费与业务受理:套餐配置、开通/续费/停复机、达量断网
|
||||||
|
4. 通道与批次:通道配置查看、批量操作与异步进度
|
||||||
|
5. 对外接口:申请 API 凭证并完成一次真实调用
|
||||||
|
6. 账号与工单:企业用户与角色、告警工单处理
|
||||||
|
|
||||||
|
## 视频文件放置约定
|
||||||
|
|
||||||
|
成片放在仓库的 `website/public/videos/` 下,文件名用小写连字符加版本号(如 `deploy-tutorial-v1.mp4`),页面里以相对路径引用:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<video controls src="/videos/deploy-tutorial-v1.mp4"></video>
|
||||||
|
```
|
||||||
|
|
||||||
|
若改投 B 站等外部托管,页面保留外链入口即可,视频文件不进仓库(避免仓库体积膨胀)。
|
||||||
|
|
||||||
|
## 录制备忘
|
||||||
|
|
||||||
|
- 录屏环境用与观众一致的环境:干净的 Ubuntu + Docker Compose V2,不要在已有业务实例上录
|
||||||
|
- 涉及口令的片段一律打码,示例口令用编排里的默认值
|
||||||
|
- 步骤与 [快速开始](/guide/quickstart) 严格一致,视频里出现的每条命令都必须能原样复制执行
|
||||||
|
- 每个视频产出配套字幕或要点说明(Markdown),随视频一起发布
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: iotLCM
|
||||||
|
text: 物联网卡全生命周期管理平台
|
||||||
|
tagline: 开源版 · 单仓多服务 · 一条命令部署上线
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: 快速开始
|
||||||
|
link: /guide/quickstart
|
||||||
|
- theme: alt
|
||||||
|
text: 使用手册
|
||||||
|
link: /guide/deploy
|
||||||
|
- theme: alt
|
||||||
|
text: 源码仓库
|
||||||
|
link: https://git.5iot.com/iotlcm-public/iotlcm
|
||||||
|
|
||||||
|
features:
|
||||||
|
- title: 一条命令部署
|
||||||
|
details: git clone 后 docker compose up -d,自动建库导入种子数据、初始化时序库,实测约 30 秒 ~ 1 分钟跑起来。
|
||||||
|
- title: 卡片全生命周期
|
||||||
|
details: 入库 → 划拨 → 激活/续费/停机 → 流量与状态同步 → 销户,一个平台覆盖 SIM 卡管理全程。
|
||||||
|
- title: 三家运营商直连
|
||||||
|
details: 内置中国移动 OneLink、中国电信 5G CMP、中国联通 10646 协议适配,并支持多家三方渠道商共享 Token 接入。
|
||||||
|
- title: 开放接口
|
||||||
|
details: OpenAPI V3 对外接口 + 旧版兼容接口 + 运营商能力代理,带完整鉴权说明与调用示例。
|
||||||
|
- title: 双端界面
|
||||||
|
details: Web 管理平台与小程序端(H5)都开源,覆盖查卡、诊断、业务受理、账号治理与工单。
|
||||||
|
- title: Apache-2.0 许可
|
||||||
|
details: 全部服务端与前端代码以 Apache-2.0 发布,可自由修改、商用与二次分发。
|
||||||
|
---
|
||||||
|
|
||||||
|
## 它是什么
|
||||||
|
|
||||||
|
iotLCM 是一套物联网 SIM 卡管理平台。运营商渠道的卡进来之后,从入库、划拨给代理商,到激活、续费、停机,再到流量与状态同步、最终销户,全部在同一个平台里完成。
|
||||||
|
|
||||||
|
开源版采用**单仓多服务**结构:全部后端服务、前端应用、文档站与部署编排都在同一个仓库里,clone 一次即拿到完整源码与部署编排。
|
||||||
|
|
||||||
|
## 现在能拿到什么
|
||||||
|
|
||||||
|
| 组件 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 管理端 | GoFrame 后端 + Vue 3 前端,卡信息、通道、资费、告警工单、账号治理 |
|
||||||
|
| 对外接口 | OpenAPI 网关、运营商能力代理 |
|
||||||
|
| 异步执行 | RabbitMQ 消费者、全量同步、批量任务 |
|
||||||
|
| 渠道对接 | OneLink / 5G CMP / 10646 适配层 + 通道缓存转发层 |
|
||||||
|
| 用户端 | 用户端服务与小程序端(H5) |
|
||||||
|
| 文档站 | 使用手册、OpenAPI 接口合同、部署手册 |
|
||||||
|
| 部署编排 | Docker Compose 编排与数据库初始化脚本 |
|
||||||
|
|
||||||
|
## 下一步
|
||||||
|
|
||||||
|
- [快速开始](/guide/quickstart) — 三十秒把整套跑起来
|
||||||
|
- [部署与运维](/guide/deploy) — 生产部署前的必改项与常见问题
|
||||||
|
- [教程视频](/guide/tutorial) — 部署与使用的录屏教程
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||||
|
<rect width="64" height="64" rx="12" fill="#0f766e"/>
|
||||||
|
<path d="M20 18h24a4 4 0 0 1 4 4v20a4 4 0 0 1-4 4H20a4 4 0 0 1-4-4V22a4 4 0 0 1 4-4z" fill="none" stroke="#fff" stroke-width="3"/>
|
||||||
|
<path d="M24 28h16M24 36h10" stroke="#fff" stroke-width="3" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 344 B |
Reference in New Issue
Block a user