e98f8561f7
mirror-to-gitee / mirror (push) Successful in 9s
问题:容器重建换 IP 后,网关与 admin-ui 仍往旧 IP 打,/openapi 与 /api 整片 502,必须手动重启 nginx 容器才恢复(2026-11-03 实机踩到)。 编排 - admin-svr / openapi / admin-ui / docs 增加 healthcheck - admin-ui、gateway、nginx 改 depends_on: condition: service_healthy, 保证 nginx 启动时后端已就绪 - 新增 deploy/compose.memlimit.yml(原来只存在于某台演示机上): 全套上限 8.5G、实测常驻 2G,留给同机其它服务 20G+; MySQL buffer pool 128M→768M、max_connections 151→300 nginx - gateway / admin-ui / iotlcm.conf 示例 统一改 resolver 127.0.0.11 valid=10s + upstream zone/resolve:运行期跟随 IP 变化,不必重启(实测 6s 内自愈)
488 lines
14 KiB
YAML
488 lines
14 KiB
YAML
name: iotlcm
|
||
|
||
# ============================================================
|
||
# IotLCM 单机部署编排
|
||
#
|
||
# 快速开始:
|
||
# 1. docker compose up -d
|
||
# 配置文件和初始口令均已内置;正式部署前按 README.md 修改默认口令。
|
||
#
|
||
# 首次启动会自动建库并导入 schema(见 schema/README.md)。
|
||
#
|
||
# 可选服务(默认不启动):
|
||
# docker compose --profile with-mock up -d # 运营商接口挡板
|
||
# docker compose --profile with-nginx up -d # 自带反向代理
|
||
# ============================================================
|
||
|
||
services:
|
||
# ---------------- 基础组件 ----------------
|
||
mysql:
|
||
# 基础组件统走同一镜像仓库(`<REGISTRY>/iotlcm/`),版本在此固定
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:mysql-8.0'
|
||
container_name: iotlcm-mysql
|
||
restart: always
|
||
ports:
|
||
- "3306:3306"
|
||
environment:
|
||
MYSQL_ROOT_PASSWORD: 'Iotlcm2026Default'
|
||
MYSQL_DATABASE: 'db_iotlcm'
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./data/mysql:/var/lib/mysql
|
||
# 仅在 data/mysql 为空(首次启动)时执行 schema/init.sql
|
||
- ./schema:/docker-entrypoint-initdb.d:ro
|
||
command:
|
||
- --character-set-server=utf8mb4
|
||
- --collation-server=utf8mb4_general_ci
|
||
- --default-time-zone=+08:00
|
||
networks:
|
||
- iotlcm-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "MYSQL_PWD=\"$$MYSQL_ROOT_PASSWORD\" mysqladmin ping -h 127.0.0.1 -u root --silent"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 10
|
||
start_period: 40s
|
||
|
||
redis:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:redis-7.2'
|
||
container_name: iotlcm-redis
|
||
restart: always
|
||
ports:
|
||
- "6379:6379"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
command:
|
||
- redis-server
|
||
- --requirepass
|
||
- 'Iotlcm2026Default'
|
||
- --appendonly
|
||
- "yes"
|
||
volumes:
|
||
- ./data/redis:/data
|
||
networks:
|
||
- iotlcm-network
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "-a", "Iotlcm2026Default", "ping"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 5
|
||
|
||
rabbitmq:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:rabbitmq-4.3.5-management'
|
||
container_name: iotlcm-rabbitmq
|
||
hostname: rabbitmq
|
||
restart: always
|
||
ports:
|
||
- "5672:5672"
|
||
- "15672:15672"
|
||
environment:
|
||
RABBITMQ_DEFAULT_USER: 'iotlcm'
|
||
RABBITMQ_DEFAULT_PASS: 'Iotlcm2026Default'
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./data/rabbitmq:/var/lib/rabbitmq
|
||
networks:
|
||
- iotlcm-network
|
||
healthcheck:
|
||
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 5
|
||
start_period: 30s
|
||
|
||
# 时序数据库:存流量历史(daily / monthly),worker-svr 全量同步写这里
|
||
tdengine:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:tdengine-3.3.6.13'
|
||
container_name: iotlcm-tdengine
|
||
restart: always
|
||
ports:
|
||
- "${TDENGINE_PORT:-6041}:6041" # taosAdapter(WebSocket,应用用这个)
|
||
- "${TDENGINE_NATIVE_PORT:-6030}:6030"
|
||
environment:
|
||
TZ: '${TZ:-Asia/Shanghai}'
|
||
volumes:
|
||
- ./data/tdengine/data:/var/lib/taos
|
||
- ./data/tdengine/log:/var/log/taos
|
||
networks:
|
||
- iotlcm-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -sf http://127.0.0.1:6041/-/ping || exit 1"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 10
|
||
start_period: 30s
|
||
|
||
# 建库建表:业务代码不负责建 TDengine 库表,由本服务在 tdengine 健康后执行一次
|
||
tdengine-init:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:tdengine-3.3.6.13'
|
||
container_name: iotlcm-tdengine-init
|
||
restart: "no"
|
||
entrypoint: ["sh", "/init/run.sh"]
|
||
volumes:
|
||
- ./tdengine-init:/init:ro
|
||
depends_on:
|
||
tdengine:
|
||
condition: service_healthy
|
||
networks:
|
||
- iotlcm-network
|
||
|
||
consul:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:consul-1.22'
|
||
container_name: iotlcm-consul
|
||
restart: always
|
||
ports:
|
||
- "8500:8500"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
CONSUL_LOCAL_CONFIG: |
|
||
{
|
||
"node_name": "iotlcm-node",
|
||
"bind_addr": "0.0.0.0",
|
||
"client_addr": "0.0.0.0",
|
||
"datacenter": "dc1",
|
||
"data_dir": "/consul/data",
|
||
"server": true,
|
||
"bootstrap_expect": 1,
|
||
"ui": true,
|
||
"connect": { "enabled": true }
|
||
}
|
||
volumes:
|
||
- ./data/consul:/consul/data
|
||
networks:
|
||
- iotlcm-network
|
||
|
||
# ---------------- 业务服务 ----------------
|
||
admin-svr:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-admin-svr-v1.0.4'
|
||
container_name: iotlcm-admin-svr
|
||
restart: always
|
||
ports:
|
||
- "127.0.0.1:8008:8008"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/admin-svr:/app/config:ro
|
||
- ./data/logs/admin-svr:/app/logs
|
||
- ./data/upload:/app/upload
|
||
- ./data/upload:/app/resource/upload
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
rabbitmq:
|
||
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:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4'
|
||
container_name: iotlcm-admin-ui
|
||
restart: always
|
||
ports:
|
||
- "127.0.0.1:8009:80"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/admin-ui/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||
- ./data/logs/admin-ui:/var/log/nginx
|
||
- ./data/upload:/app/upload
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
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:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-openapi-v1.0.4'
|
||
container_name: iotlcm-openapi
|
||
restart: always
|
||
ports:
|
||
- "127.0.0.1:8000:8000"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/openapi:/app/config:ro
|
||
- ./data/logs/openapi:/app/logs
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
rabbitmq:
|
||
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:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4'
|
||
container_name: iotlcm-upstream-chan
|
||
restart: always
|
||
ports:
|
||
- "8110:8110"
|
||
- "8310:8310"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/upstream-chan:/app/config:ro
|
||
- ./data/logs/upstream-chan:/app/logs
|
||
- ./data/upload:/app/upload
|
||
- ./data/upload:/app/resource/upload
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
consul:
|
||
condition: service_started
|
||
|
||
upstream-proxy:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-upstream-proxy-v1.0.4'
|
||
container_name: iotlcm-upstream-proxy
|
||
restart: always
|
||
ports:
|
||
- "8510:8510"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/upstream-proxy:/app/config:ro
|
||
- ./data/logs/upstream-proxy:/app/logs
|
||
- ./data/upload:/app/upload
|
||
- ./data/upload:/app/resource/upload
|
||
- ./data/tmp:/app/tmp
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
consul:
|
||
condition: service_started
|
||
|
||
worker-svr:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4'
|
||
container_name: iotlcm-worker-svr
|
||
restart: always
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./config/worker-svr:/app/config:ro
|
||
- ./data/logs/worker-svr:/app/logs
|
||
- ./data/logs/worker-svr/full-sync:/app/logs/full-sync
|
||
- ./data/upload:/app/upload
|
||
- ./data/upload:/app/resource/upload
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
rabbitmq:
|
||
condition: service_healthy
|
||
|
||
app-server:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-app-server-v1.0.2'
|
||
container_name: iotlcm-app-server
|
||
restart: always
|
||
ports:
|
||
- "127.0.0.1:8010:8010"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
APP_UPLOAD_DIR: /app/resource/upload
|
||
volumes:
|
||
- ./config/app-server:/app/config:ro
|
||
- ./data/upload:/app/resource/upload
|
||
- ./data/logs/app-server:/app/resource/log/server
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
mysql:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
|
||
app-web:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-app-web-v1.0.2'
|
||
container_name: iotlcm-app-web
|
||
restart: always
|
||
ports:
|
||
- "127.0.0.1:8018:80"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
volumes:
|
||
- ./data/logs/app-web:/var/log/nginx
|
||
networks:
|
||
- iotlcm-network
|
||
|
||
sms:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-sms-v1.0.4'
|
||
container_name: iotlcm-sms
|
||
hostname: iotlcm-sms
|
||
restart: always
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
HTTP_ADDR: ':11190'
|
||
GRPC_ADDR: ':11200'
|
||
ports:
|
||
- "11190:11190"
|
||
- "11200:11200"
|
||
volumes:
|
||
- ./config/sms:/app/config:ro
|
||
- ./data/logs/sms:/app/logs
|
||
tmpfs:
|
||
- /tmp
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
healthcheck:
|
||
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1:11190/healthz"]
|
||
interval: 10s
|
||
timeout: 3s
|
||
retries: 3
|
||
start_period: 5s
|
||
networks:
|
||
- iotlcm-network
|
||
|
||
bot:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-bot-v1.0.4'
|
||
container_name: iotlcm-bot
|
||
restart: unless-stopped
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
command: ["watch", "--config", "/app/config/config.yaml"]
|
||
volumes:
|
||
- ./config/bot/config.yaml:/app/config/config.yaml:ro
|
||
- ./data/logs/worker-svr/full-sync:/data/full-sync:ro
|
||
- ./data/bot-state:/data/state
|
||
networks:
|
||
- iotlcm-network
|
||
profiles:
|
||
- with-bot
|
||
|
||
docs:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-docs-v1.0.4'
|
||
container_name: iotlcm-docs
|
||
restart: unless-stopped
|
||
ports:
|
||
- "127.0.0.1:8019:80"
|
||
networks:
|
||
- 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
|
||
|
||
# ---------------- 可选:运营商接口挡板 ----------------
|
||
# 模拟中国移动 OneLink 接口,用于在没有真实运营商环境时联调整条链路:
|
||
# admin-svr → worker-svr → upstream-chan → onelink-mock
|
||
#
|
||
# 启用:docker compose --profile with-mock up -d
|
||
# 启用后 upstream-chan 的 sim_yd_mock_v5.url 指向 http://onelink-mock:8080/v5/
|
||
# (config/upstream-chan 已预置该地址)
|
||
onelink-mock:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:iotlcm-onelink-mock-v1.0.4'
|
||
container_name: iotlcm-onelink-mock
|
||
restart: unless-stopped
|
||
ports:
|
||
- "127.0.0.1:8080:8080"
|
||
environment:
|
||
TZ: 'Asia/Shanghai'
|
||
BAFFLE_ADDR: ':8080'
|
||
BAFFLE_SQLITE_PATH: /app/data/onelink_mock.db
|
||
volumes:
|
||
- ./data/mock:/app/data
|
||
- ./data/logs/mock:/app/logs
|
||
networks:
|
||
- iotlcm-network
|
||
healthcheck:
|
||
test: ["CMD", "wget", "--quiet", "--output-document=/dev/null", "http://127.0.0.1:8080/api.json"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
retries: 3
|
||
start_period: 10s
|
||
profiles:
|
||
- with-mock
|
||
|
||
# ---------------- 可选:反向代理 ----------------
|
||
# 若宿主机已有 nginx / 面板,可不启动本容器,
|
||
# 参考 config/nginx/iotlcm.conf 把 location 段落到宿主机配置。
|
||
nginx:
|
||
image: 'crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com/iotlcm/iotlcm:nginx-1.30'
|
||
container_name: iotlcm-nginx
|
||
restart: always
|
||
ports:
|
||
- "${NGINX_HTTP_PORT:-80}:80"
|
||
volumes:
|
||
- ./config/nginx:/etc/nginx/conf.d:ro
|
||
- ./data/logs/nginx:/var/log/nginx
|
||
- ./data/upload:/app/upload
|
||
networks:
|
||
- iotlcm-network
|
||
depends_on:
|
||
admin-ui:
|
||
condition: service_healthy
|
||
openapi:
|
||
condition: service_healthy
|
||
docs:
|
||
condition: service_healthy
|
||
app-web:
|
||
condition: service_started
|
||
profiles:
|
||
- 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:
|
||
iotlcm-network:
|
||
driver: bridge
|
||
name: iotlcm-network
|