Files
iotlcm/docker-compose.yml
T
MiFaZhan bc2c7bcc6b init: IotLCM 开源版部署仓
内容:
- docker-compose.yml:14 个基础/业务服务 + 3 个可选 profile(with-mock 挡板、with-bot、with-nginx)
- .env.example:集中管理镜像仓库、口令、端口;必填项缺失时 compose 直接报错退出
- config.example/:10 份配置模板,全部为占位值与注释说明
- schema/:12 个初始化脚本,按文件名顺序由 MySQL initdb 自动执行

脱敏处理:
- 生产/内网 IP、镜像仓库地址、公司名、真实域名全部清除
- 演示账号保留 18 个(出库与划拨依赖账号与部门树的关联),
  昵称/邮箱/手机号/登录IP/头像改为占位或编造值
- 数据库账号与 admin 口令改为初始化时按 .env 注入计算
- 通道模板与 Mock 通道的上游密钥置空
- Mock 通道地址指向 compose 内 onelink-mock 服务

部署时用 --profile with-mock 启动运营商接口挡板,即可在无真实运营商环境时跑通全链路。
2026-10-28 13:40:12 +08:00

398 lines
11 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: iotlcm
# ============================================================
# IotLCM 单机部署编排
#
# 快速开始:
# 1. cp .env.example .env # 填写镜像仓库与各项口令
# 2. cp -r config.example config # 逐份填写配置(见各文件内注释)
# 3. docker compose up -d
#
# 首次启动会自动建库并导入 schema(见 schema/README.md)。
#
# 可选服务(默认不启动):
# docker compose --profile with-mock up -d # 运营商接口挡板
# docker compose --profile with-nginx up -d # 自带反向代理
# ============================================================
services:
# ---------------- 基础组件 ----------------
mysql:
image: '${REGISTRY:-your-registry}/library/mysql:8.0'
container_name: iotlcm-mysql
restart: always
ports:
- "${MYSQL_PORT:-3306}:3306"
environment:
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD:?必须在 .env 中设置}'
MYSQL_DATABASE: '${MYSQL_DATABASE:-db_iotlcm}'
MYSQL_APP_PASSWORD: '${MYSQL_APP_PASSWORD:?必须在 .env 中设置}'
MYSQL_ADMIN_PASSWORD: '${MYSQL_ADMIN_PASSWORD:?必须在 .env 中设置}'
TZ: '${TZ:-Asia/Shanghai}'
volumes:
- ./data/mysql:/var/lib/mysql
# 仅在 data/mysql 为空(首次启动)时执行,按文件名顺序
- ./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", "mysqladmin", "ping", "-h", "127.0.0.1", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 10
start_period: 40s
redis:
image: '${REGISTRY:-your-registry}/library/redis:7.2'
container_name: iotlcm-redis
restart: always
ports:
- "${REDIS_PORT:-6379}:6379"
environment:
TZ: '${TZ:-Asia/Shanghai}'
command:
- redis-server
- --requirepass
- '${REDIS_PASSWORD:?必须在 .env 中设置}'
- --appendonly
- "yes"
volumes:
- ./data/redis:/data
networks:
- iotlcm-network
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
rabbitmq:
image: '${REGISTRY:-your-registry}/library/rabbitmq:4.3.5-management'
container_name: iotlcm-rabbitmq
hostname: rabbitmq
restart: always
ports:
- "${RABBITMQ_PORT:-5672}:5672"
- "${RABBITMQ_MGMT_PORT:-15672}:15672"
environment:
RABBITMQ_DEFAULT_USER: '${RABBITMQ_USER:-iotlcm}'
RABBITMQ_DEFAULT_PASS: '${RABBITMQ_PASSWORD:?必须在 .env 中设置}'
TZ: '${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
consul:
image: '${REGISTRY:-your-registry}/library/consul:1.22'
container_name: iotlcm-consul
restart: always
ports:
- "${CONSUL_PORT:-8500}:8500"
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-admin-svr:${TAG:-latest}'
container_name: iotlcm-admin-svr
restart: always
ports:
- "127.0.0.1:${ADMIN_SVR_PORT:-8008}:8008"
environment:
TZ: '${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
admin-ui:
image: '${REGISTRY:-your-registry}/iotlcm/iotlcm-admin-ui:${TAG:-latest}'
container_name: iotlcm-admin-ui
restart: always
ports:
- "127.0.0.1:${ADMIN_UI_PORT:-8009}:80"
environment:
TZ: '${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
openapi:
image: '${REGISTRY:-your-registry}/iotlcm/iotlcm-openapi:${TAG:-latest}'
container_name: iotlcm-openapi
restart: always
ports:
- "127.0.0.1:${OPENAPI_PORT:-8000}:8000"
environment:
TZ: '${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
upstream-chan:
image: '${REGISTRY:-your-registry}/iotlcm/iotlcm-upstream-chan:${TAG:-latest}'
container_name: iotlcm-upstream-chan
restart: always
ports:
- "${CHAN_HTTP_PORT:-8110}:8110"
- "${CHAN_GRPC_PORT:-8310}:8310"
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-upstream-proxy:${TAG:-latest}'
container_name: iotlcm-upstream-proxy
restart: always
ports:
- "${PROXY_PORT:-8510}:8510"
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-worker-svr:${TAG:-latest}'
container_name: iotlcm-worker-svr
restart: always
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-app-server:${TAG:-latest}'
container_name: iotlcm-app-server
restart: always
ports:
- "127.0.0.1:${APP_SERVER_PORT:-8010}:8010"
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-app-web:${TAG:-latest}'
container_name: iotlcm-app-web
restart: always
ports:
- "127.0.0.1:${APP_WEB_PORT:-8018}:80"
environment:
TZ: '${TZ:-Asia/Shanghai}'
volumes:
- ./data/logs/app-web:/var/log/nginx
networks:
- iotlcm-network
sms:
image: '${REGISTRY:-your-registry}/iotlcm/iotlcm-sms:${TAG:-latest}'
container_name: iotlcm-sms
hostname: iotlcm-sms
restart: always
environment:
TZ: '${TZ:-Asia/Shanghai}'
HTTP_ADDR: ':11190'
GRPC_ADDR: ':11200'
ports:
- "${SMS_HTTP_PORT:-11190}:11190"
- "${SMS_GRPC_PORT:-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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-bot:${TAG:-latest}'
container_name: iotlcm-bot
restart: unless-stopped
environment:
TZ: '${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: '${REGISTRY:-your-registry}/iotlcm/iotlcm-docs:${TAG:-latest}'
container_name: iotlcm-docs
restart: unless-stopped
ports:
- "127.0.0.1:${DOCS_PORT:-8019}:80"
networks:
- iotlcm-network
# ---------------- 可选:运营商接口挡板 ----------------
# 模拟中国移动 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.example/upstream-chan 已预置该地址)
onelink-mock:
image: '${REGISTRY:-your-registry}/iotlcm/iotlcm-onelink-mock:${TAG:-latest}'
container_name: iotlcm-onelink-mock
restart: unless-stopped
ports:
- "127.0.0.1:${MOCK_PORT:-8080}:8080"
environment:
TZ: '${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.example/nginx/iotlcm.conf 把 location 段落到宿主机配置。
nginx:
image: '${REGISTRY:-your-registry}/library/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
- openapi
- app-web
- docs
profiles:
- with-nginx
networks:
iotlcm-network:
driver: bridge
name: iotlcm-network