diff --git a/DockerComposeShells/adminapi/conf/appsettings.Development_服务订阅模式.json b/DockerComposeShells/adminapi/conf/appsettings.Development_服务订阅模式.json new file mode 100644 index 0000000..3cbc749 --- /dev/null +++ b/DockerComposeShells/adminapi/conf/appsettings.Development_服务订阅模式.json @@ -0,0 +1,108 @@ +{ + "App": { + "SelfUrl": "http://localhost:44315", + "CorsOrigins": "https://*.IoT.com,http://localhost:4200,http://localhost:3100,http://localhost:80,http://10.10.70.11:4200,http://47.110.53.196:30711,http://192.168.111.174:30711" + }, + "ConnectionStrings": { + "Default": "Data Source=mysql;Port=3306;Database=JiSheIoTProDB;uid=root;pwd=JiShe!aqG#5kGgh&0;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true;" + }, + "Hangfire": { + "Redis": { + "Host": "redis:6379,password=1q3J@BGf!yhTaD46nS#", + "DB": "2" + } + }, + "Redis": { + "Configuration": "redis:6379,defaultdatabase=5,password=1q3J@BGf!yhTaD46nS#" + }, + "Kafka": { + "BootstrapServers": "47.110.62.104:9094,47.110.53.196:9094,47.110.60.222:9094", + "EnableFilter": true, + "EnableAuthorization": false, + "SaslUserName": "lixiao", + "SaslPassword": "lixiao@1980", + "KafkaReplicationFactor": 3, + "NumPartitions": 30, + "TaskThreadCount": -1 + }, + "Pulsar": { + "ServiceUrl": "pulsar+ssl://iot-north-mq.heclouds.com:6651", + "WebUrl": "http://pulsar-broker:9094", + "UserName": "admin", + "TenantName": "1YMVZZkAkRArjxSD8457", + "Namespace": "OneNET", + "MessageTTL": 3600, + "PulsarSecretKey": "0fd7afb8b0d04e6abc4fdfdac2190a79", + "PulsarSubscriptionCustomName": "sub", + "EnableTls": false, + "ValidateServerCertificate": false, + "ConnectionTimeout": 30, + "OperationTimeout": 30, + "KeepAliveInterval": 30, + "TaskThreadCount": 1, + "IsSubscriber": true, + "DefaultPartitions": 16, + "DefaultBundles": 16, + "EnableAutoCreation": false, //开启自动创建Topic + "TopicMode": "Dynamic", //Dynamic 主题模式 + "EnableTopicTypeFilter": true, //允许Topic类型过滤 + "AllowedTopicTypes": [ "Dynamic" ], //允许的Topic类型 + "AllowedClusters": [ "pulsar-cluster-1" ], //允许的集群 + "AdminRoles": [ "admin" ], + "EnableConsumerIdleCleanup": true, + "ConsumerIdleCleanupMinutes": 120, + "EnableProducerIdleCleanup": true, + "ProducerIdleCleanupMinutes": 60 + }, + "IoTDBOptions": { + "UserName": "root", + "Password": "Lixiao@1980", + "TreeModelClusterList": [ "iotdb-standalone:6667" ], + "TableModelClusterList": [ "iotdb-standalone:6667" ], + "PoolSize": 32, + "DataBaseName": "jisheiotdata", + "OpenDebugMode": true, + "BatchInsertSize": 1000, + "UseTableSessionPoolByDefault": false + }, + "ServerApplicationOptions": { + "ServerTagName": "JiSheCollectBus12", + "FirstCollectionTime": "2025-04-28 15:07:00", + "AutomaticVerificationTime": "16:07:00", + "AutomaticTerminalVersionTime": "17:07:00", + "AutomaticTelematicsModuleTime": "17:30:00", + "AutomaticDayFreezeTime": "02:30:00", + "AutomaticMonthFreezeTime": "03:30:00", + "DefaultProtocolPlugin": "T37612012ProtocolPlugin", + "SignatureToken": "SIcPQnpMgaFDmNlIjNmzq5smshz7cKrh", + "AesSecurityKey": "RPTEIGCA1KvDEXS1", + "IsAesEncrypted": false, + "DistributedMessage": 2, + "SnowflakeWorkerId": 1 + }, + "Jwt": { + "Audience": "JiShe.IoT", + "SecurityKey": "dzehzRz9a8asdfaf43ghVD@d#fasdfaf567sdadfasdf=", + "Issuer": "JiShe.IoT", + "ExpirationTime": 2 + }, + "FreeRedisOptions": { + "ConnectionString": "redis:6379,password=1q3J@BGf!yhTaD46nS#,abortConnect=false,connectTimeout=30000,allowAdmin=true,maxPoolSize=500,defaultdatabase=14", + "UseDistributedCache": true + }, + "FreeSqlProviderOptions": { + "UsePrepayDB": false, + "UseEnergyDB": false, + "PrintLog": false + }, + "OneNETSecureReceiveOptions": { + "OneNETVerifySignatureToken": "SIcPQnpMgaFDmNlIjNmzq5smshz7cKrh", + "OneNETAesKey": "RPTEIGCA1KvDEXS1" + }, + "DataChannelOptions": { + "DefaultBatchSize": 10000, + "TelemetryBatchSize": 10000, + "EmptyWaitmilliseconds": 500, + "TimeoutMilliseconds": 500 + } +} \ No newline at end of file diff --git a/DockerComposeShells/docker-compose_service_sub.yml b/DockerComposeShells/docker-compose_service_sub.yml new file mode 100644 index 0000000..2638706 --- /dev/null +++ b/DockerComposeShells/docker-compose_service_sub.yml @@ -0,0 +1,138 @@ +services: + iotdb-standalone-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/iotdb:2.0.5-standalone + hostname: iotdb-standalone + container_name: iotdb-standalone + restart: always + deploy: + resources: + limits: + cpus: "8" + memory: 16g + ports: + - "${IOTDB_PORT}:6667" + environment: + - cn_internal_address=iotdb-standalone + - cn_internal_port=10710 + - cn_consensus_port=10720 + - cn_seed_config_node=iotdb-standalone:10710 + - dn_rpc_address=iotdb-standalone + - dn_internal_address=iotdb-standalone + - dn_rpc_port=6667 + - dn_internal_port=10730 + - dn_mpp_data_exchange_port=10740 + - dn_schema_region_consensus_port=10750 + - dn_data_region_consensus_port=10760 + - dn_seed_config_node=iotdb-standalone:10710 + privileged: true + volumes: + - ./iotdb/conf:/iotdb/conf + - ./iotdb/data:/iotdb/data + - ./iotdb/logs:/iotdb/logs + networks: + - pulsar-net + + redis-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/redis:8.0.2-alpine3.21 + container_name: redis + restart: always + hostname: redis + deploy: + resources: + limits: + cpus: "1.0" + memory: 1g + ports: + - "${REDIS_PORT}:6379" + volumes: + - ./redis/outdata:/data + - ./redis/conf:/etc/redis/conf + command: redis-server /etc/redis/conf/redis.conf + stdin_open: true + tty: true + networks: + - pulsar-net + + mysql-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/mysql:8.4.6 + container_name: mysql + hostname: mysql + restart: always + privileged: true + user: "1000:1000" # 使用宿主机用户ID + ports: + - "${MYSQL_PORT}:3306" + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + TZ: Asia/Shanghai + volumes: + - ./mysql/log:/var/log/mysql + - ./mysql/data:/var/lib/mysql + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --binlog-expire-logs-seconds=604800 # 设置binlog保留7天(7*24*60*60=604800秒) + deploy: + resources: + limits: + cpus: "2.0" + memory: 2g + stdin_open: true + tty: true + networks: + - pulsar-net + + admin-api-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.admin:2025.1119.1155 + container_name: admin-api + hostname: admin-api + restart: always + deploy: + resources: + limits: + memory: 8g + ports: + - "${ADMIN_API_PORT}:10500" + volumes: + - ./adminapi/conf:/app/configs + - ./adminapi/logs:/app/logs + stdin_open: true + tty: true + depends_on: + mysql-service: + condition: service_started + redis-service: + condition: service_started + iotdb-standalone-service: + condition: service_started + networks: + - pulsar-net + + admin-web-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.ui:2025.1030.0949 + container_name: admin-web + hostname: admin-web + restart: always + deploy: + resources: + limits: + cpus: "1.0" + memory: 200mb + ports: + - "${ADMIN_WEB_PORT}:8080" + stdin_open: true + tty: true + depends_on: + admin-api-service: + condition: service_started + networks: + - pulsar-net + +networks: + pulsar-net: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.23.0.0/16 + gateway: 172.23.0.1 \ No newline at end of file diff --git a/DockerComposeShells/docker-compose_service_sub_init.yml b/DockerComposeShells/docker-compose_service_sub_init.yml new file mode 100644 index 0000000..5a6f94b --- /dev/null +++ b/DockerComposeShells/docker-compose_service_sub_init.yml @@ -0,0 +1,145 @@ +services: + iotdb-standalone-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/iotdb:2.0.5-standalone + hostname: iotdb-standalone + container_name: iotdb-standalone + restart: always + deploy: + resources: + limits: + cpus: "8" + memory: 16g + ports: + - "${IOTDB_PORT}:6667" + environment: + - cn_internal_address=iotdb-standalone + - cn_internal_port=10710 + - cn_consensus_port=10720 + - cn_seed_config_node=iotdb-standalone:10710 + - dn_rpc_address=iotdb-standalone + - dn_internal_address=iotdb-standalone + - dn_rpc_port=6667 + - dn_internal_port=10730 + - dn_mpp_data_exchange_port=10740 + - dn_schema_region_consensus_port=10750 + - dn_data_region_consensus_port=10760 + - dn_seed_config_node=iotdb-standalone:10710 + privileged: true + volumes: + - ./iotdb/conf:/iotdb/conf + - ./iotdb/data:/iotdb/data + - ./iotdb/logs:/iotdb/logs + networks: + - pulsar-net + + redis-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/redis:8.0.2-alpine3.21 + container_name: redis + restart: always + hostname: redis + deploy: + resources: + limits: + cpus: "1.0" + memory: 1g + ports: + - "${REDIS_PORT}:6379" + volumes: + - ./redis/outdata:/data + - ./redis/conf:/etc/redis/conf + command: redis-server /etc/redis/conf/redis.conf + stdin_open: true + tty: true + networks: + - pulsar-net + + mysql-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/mysql:8.4.6 + container_name: mysql + hostname: mysql + restart: always + privileged: true + user: "1000:1000" # 使用宿主机用户ID + ports: + - "${MYSQL_PORT}:3306" + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + TZ: Asia/Shanghai + volumes: + - ./mysql/log:/var/log/mysql + - ./mysql/data:/var/lib/mysql + - ./mysql/init:/docker-entrypoint-initdb.d + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --user=mysql # 确保MySQL以mysql用户运行 + - --binlog-expire-logs-seconds=604800 # 设置binlog保留7天(7*24*60*60=604800秒) + deploy: + resources: + limits: + cpus: "2.0" + memory: 2g + stdin_open: true + tty: true + networks: + - pulsar-net + + admin-api-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.admin:2025.1119.1155 + container_name: admin-api + hostname: admin-api + restart: always + deploy: + resources: + limits: + cpus: "2.0" + memory: 4g + ports: + - "${ADMIN_API_PORT}:10500" + volumes: + - ./adminapi/conf:/app/configs + - ./adminapi/logs:/app/logs + stdin_open: true + tty: true + depends_on: + mysql-service: + condition: service_started + redis-service: + condition: service_started + iotdb-standalone-service: + condition: service_started + zookeeper: + condition: service_healthy + broker: + condition: service_healthy + networks: + - pulsar-net + + admin-web-service: + image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.ui:2025.1030.0949 + container_name: admin-web + hostname: admin-web + restart: always + deploy: + resources: + limits: + cpus: "1.0" + memory: 200mb + ports: + - "${ADMIN_WEB_PORT}:8080" + stdin_open: true + tty: true + depends_on: + admin-api-service: + condition: service_started + networks: + - pulsar-net + +networks: + pulsar-net: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.23.0.0/16 + gateway: 172.23.0.1 \ No newline at end of file diff --git a/DockerComposeShells/start-service-sub.sh b/DockerComposeShells/start-service-sub.sh new file mode 100644 index 0000000..2c6ee89 --- /dev/null +++ b/DockerComposeShells/start-service-sub.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +# ========================= +# 服务订阅模式一键启动脚本 +# ========================= + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$ROOT_DIR" + +# 1. 校验 .env +if [ ! -f "./.env" ]; then + echo "❌ 配置文件 .env 不存在,请先创建(可复制 .env.example)。" + exit 1 +fi + +echo "📁 检查 .env 并规范换行符..." +if command -v dos2unix >/dev/null 2>&1; then + dos2unix -q ./.env || true +else + sed -i 's/\r$//' ./.env 2>/dev/null || perl -pi -e 's/\r$//' ./.env 2>/dev/null || true +fi + +# 2. 加载环境变量 +set -a +. ./.env +set +a + +# 3. 校验关键变量 +required_vars=( + IOTDB_PORT + IOTDB_ROOT_PASSWORD + REDIS_PORT + MYSQL_PORT + MYSQL_ROOT_PASSWORD + ADMIN_API_PORT + ADMIN_WEB_PORT +) +missing_vars=() +for var in "${required_vars[@]}"; do + if [ -z "${!var:-}" ]; then + missing_vars+=("$var") + fi +done + +if [ ${#missing_vars[@]} -ne 0 ]; then + echo "❌ 以下环境变量未设置: ${missing_vars[*]}" + echo "💡 请在 .env 中补充这些变量后重试。" + exit 1 +fi + +# 4. 登录镜像仓库(如已登录可忽略错误) +echo "=== Docker 镜像仓库登录(若已登录可忽略提示) ===" +docker login --username=yunjichaobiao --password hub.jishe.com registry.cn-qingdao.aliyuncs.com || true + +# 5. 创建宿主机数据目录 +echo "📁 创建数据目录..." +sudo mkdir -p /mnt/dockerdata/appservice/{redis/{outdata,conf},mysql/{conf,log,data},iotdb/{conf,data,logs},adminapi/{conf,logs}} +sudo chown -R 10000:0 /mnt/dockerdata/appservice/iotdb || true + +echo "🔗 创建本地目录链接..." +mkdir -p ./redis/{outdata,conf} +mkdir -p ./mysql/{conf,log,data} +mkdir -p ./iotdb/{conf,data,logs} +mkdir -p ./adminapi/{conf,logs} + +# 6. 修复权限 +echo "🔧 修复 MySQL / Admin 日志目录权限..." +sudo chown -R 1000:1000 ./mysql/data ./mysql/log || true +sudo chmod -R 755 ./mysql/data ./mysql/log +sudo chmod -R 755 ./adminapi/logs || true + +# 7. 启动订阅模式初始化栈 +echo "🚀 第一步:启动服务订阅初始化栈 (docker-compose-service_sub_init.yml)" +docker compose -f docker-compose-service_sub_init.yml up -d + +echo "⏳ 等待 IoTDB 容器启动..." +sleep 15 + +# 8. 拷贝 IoTDB 配置 +echo "📁 拷贝 IoTDB 配置目录..." +docker cp iotdb-standalone:/iotdb/conf ./iotdb + +# 9. 设置时间戳精度 +CONFIG_FILE=./iotdb/conf/iotdb-system.properties +echo "⚙️ 配置 IoTDB 时间戳精度..." +if [ -f "$CONFIG_FILE" ]; then + if ! grep -q "timestamp_precision=ns" "$CONFIG_FILE"; then + { + echo "" + echo "# ms 毫秒 / us 微秒 / ns 纳秒" + echo "timestamp_precision=ns" + } >> "$CONFIG_FILE" + echo "✅ 已追加 timestamp_precision=ns" + else + echo "ℹ️ timestamp_precision=ns 已存在" + fi +else + echo "⚠️ 未找到 $CONFIG_FILE,请确认 IoTDB 配置是否拷贝成功。" +fi + +# 10. 清理 IoTDB 数据文件(保留 conf) +echo "🧹 清理 IoTDB 本地数据/日志目录..." +sudo rm -rf ./iotdb/data/* ./iotdb/logs/* || true + +# 11. 设置 IoTDB root 密码 +echo "🔐 设置 IoTDB root 密码..." +docker exec -i iotdb-standalone /bin/bash << EOF +echo "等待 IoTDB 完全就绪..." +sleep 10 +echo "ALTER USER root SET PASSWORD '${IOTDB_ROOT_PASSWORD}';" | ./start-cli.sh -h iotdb-standalone +EOF +echo "✅ IoTDB 密码设置完成" + +# 12. 关闭初始化栈 +echo "🛑 停止初始化栈..." +docker compose -f docker-compose-service_sub_init.yml down + +echo "⏳ 等待 30 秒..." +sleep 30 + +# 13. 启动服务订阅模式正式栈 +echo "🚀 最终启动:docker-compose_service_sub.yml" +docker compose -f docker-compose_service_sub.yml up -d + +echo "" +echo "🎉 服务订阅模式环境启动完成!" +echo "📋 关键连接信息:" +echo " IoTDB RPC: localhost:${IOTDB_PORT} (root/${IOTDB_ROOT_PASSWORD})" +echo " Redis: localhost:${REDIS_PORT}" +echo " MySQL: localhost:${MYSQL_PORT}" +echo " Admin API: http://localhost:${ADMIN_API_PORT}" +echo " Admin UI : http://localhost:${ADMIN_WEB_PORT}" +echo "" +echo "🔧 常用命令:" +echo " 查看状态 : docker compose -f docker-compose_service_sub.yml ps" +echo " 查看日志 : docker compose -f docker-compose_service_sub.yml logs -f" +echo " 停止服务 : docker compose -f docker-compose_service_sub.yml down" +echo "" + diff --git a/JiShe.IoT.Admin.sln b/JiShe.IoT.Admin.sln index f1b635f..8acee0c 100644 --- a/JiShe.IoT.Admin.sln +++ b/JiShe.IoT.Admin.sln @@ -1,6 +1,7 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31410.414 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11217.181 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.IoT.Domain", "src\JiShe.IoT.Domain\JiShe.IoT.Domain.csproj", "{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}" EndProject @@ -275,15 +276,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DockerComposeShells", "Dock ProjectSection(SolutionItems) = preProject DockerComposeShells\.env = DockerComposeShells\.env DockerComposeShells\adminapi\conf\appsettings.Development.json = DockerComposeShells\adminapi\conf\appsettings.Development.json + DockerComposeShells\adminapi\conf\appsettings.Development_服务订阅模式.json = DockerComposeShells\adminapi\conf\appsettings.Development_服务订阅模式.json DockerComposeShells\adminapi\conf\appsettings.json = DockerComposeShells\adminapi\conf\appsettings.json DockerComposeShells\docker-compose-init.yml = DockerComposeShells\docker-compose-init.yml DockerComposeShells\docker-compose-iotdb-standalone.yml = DockerComposeShells\docker-compose-iotdb-standalone.yml DockerComposeShells\docker-compose.yml = DockerComposeShells\docker-compose.yml + DockerComposeShells\docker-compose_service_sub.yml = DockerComposeShells\docker-compose_service_sub.yml + DockerComposeShells\docker-compose_service_sub_init.yml = DockerComposeShells\docker-compose_service_sub_init.yml DockerComposeShells\mysql\init\init-db.sql = DockerComposeShells\mysql\init\init-db.sql DockerComposeShells\iotdb\init\init-iot-db.sql = DockerComposeShells\iotdb\init\init-iot-db.sql DockerComposeShells\prometheus\prometheus.yml = DockerComposeShells\prometheus\prometheus.yml DockerComposeShells\redis\conf\redis.conf = DockerComposeShells\redis\conf\redis.conf DockerComposeShells\start-pulsar.sh = DockerComposeShells\start-pulsar.sh + DockerComposeShells\start-service-sub.sh = DockerComposeShells\start-service-sub.sh EndProjectSection EndProject Global diff --git a/host/JiShe.IoT.HttpApi.Host/configs/appsettings.Development.json b/host/JiShe.IoT.HttpApi.Host/configs/appsettings.Development.json index a474e71..6ff0927 100644 --- a/host/JiShe.IoT.HttpApi.Host/configs/appsettings.Development.json +++ b/host/JiShe.IoT.HttpApi.Host/configs/appsettings.Development.json @@ -26,14 +26,14 @@ "TaskThreadCount": -1 }, "Pulsar": { - "ServiceUrl": "pulsar://192.168.111.174:26974", + "ServiceUrl": "pulsar+ssl://iot-north-mq.heclouds.com:6651", //pulsar+ssl://iot-north-mq.heclouds.com:6651 ,pulsar://192.168.111.174:26974 "WebUrl": "http://192.168.111.174:9094", "UserName": "admin", "TenantName": "1YMVZZkAkRArjxSD8457", "Namespace": "OneNET", "MessageTTL": 3600, "PulsarSecretKey": "0fd7afb8b0d04e6abc4fdfdac2190a79", - "PulsarSubscriptionCustomName": "sub4", + "PulsarSubscriptionCustomName": "sub", "EnableTls": false, "ValidateServerCertificate": false, "ConnectionTimeout": 30, @@ -43,10 +43,10 @@ "IsSubscriber": true, "DefaultPartitions": 16, "DefaultBundles": 16, - "EnableAutoCreation": true, //开启自动创建Topic - "TopicMode": "Static", //Dynamic 主题模式 + "EnableAutoCreation": false, //开启自动创建Topic + "TopicMode": "Dynamic", //Dynamic 主题模式 "EnableTopicTypeFilter": true, //允许Topic类型过滤 - "AllowedTopicTypes": [ "Static" ], //允许的Topic类型 + "AllowedTopicTypes": [ "Dynamic" ], //允许的Topic类型 "AllowedClusters": [ "pulsar-cluster-1" ], //允许的集群 "AdminRoles": [ "admin" ], "EnableConsumerIdleCleanup": true,