From db91e9503ecf38a792047e34a4104fce63baa27e Mon Sep 17 00:00:00 2001 From: lzh Date: Tue, 28 Apr 2026 17:00:24 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ci):=20release=20=E8=B5=B0=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=20compose=20=E6=96=87=E4=BB=B6=EF=BC=8Cprod=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=9B=9E=E6=BB=9A=E6=88=90=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E5=8E=9F=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前的参数化(docker-compose.core.yml 用 \${VAR:-default} + .env 注入)让运维要在 两台部署机分别维护 .env,体验跟 prod 现状不一致。改回与 prod 同款:每个环境一个 独立的 compose 文件,配置直接硬编码在 yml 里。 改动: - 新增 docker-compose.release.yml(release 专用:MySQL aiot-platform-release 库、 Nacos namespace e635b215-...、TDengine database aiot_platform_release、 XXL-Job executor IP=.7、appname 加 -release 后缀、RocketMQ 内网 .7:9876) - docker-compose.core.yml 完全恢复到 master 版本(prod 文件未做任何改动) - 删除 env/ 目录(prod.env.example / release.env.example / .gitignore 都不需要了) - Jenkinsfile: - Initialize 阶段按分支选 COMPOSE_FILE:master→core.yml、release/next→release.yml - 所有 docker compose 命令统一用 -f \${env.COMPOSE_FILE} - Pre-deploy 移除 .env 文件存在性检查 - 删除 checkRemoteEnvFileOrFail helper(不再使用) application.yaml 里的 \${XXL_JOB_EXECUTOR_APPNAME_SUFFIX:} 与 application-prod.yaml 里的 \${TDENGINE_DATABASE:aiot_platform} 保留——默认值与历史一致,prod 行为零变化, 但给 release.yml 注入这两个变量留了入口。 --- Jenkinsfile | 50 ++------ docker-compose.core.yml | 206 +++++++++++++++++++------------- docker-compose.release.yml | 236 +++++++++++++++++++++++++++++++++++++ env/.gitignore | 3 - env/prod.env.example | 61 ---------- env/release.env.example | 69 ----------- 6 files changed, 376 insertions(+), 249 deletions(-) create mode 100644 docker-compose.release.yml delete mode 100644 env/.gitignore delete mode 100644 env/prod.env.example delete mode 100644 env/release.env.example diff --git a/Jenkinsfile b/Jenkinsfile index 6e61c905..07cf18b8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -80,12 +80,11 @@ pipeline { if (env.BRANCH_NAME == 'release/next') { env.DEPLOY_HOST = env.RELEASE_DEPLOY_HOST env.DEPLOY_PATH = env.RELEASE_DEPLOY_PATH - // release 环境强制 .env 注入;prod 沿用 docker-compose 内嵌默认值不破坏现有部署 - env.COMPOSE_ENV_FILE_ARG = '--env-file .env' - echo "📦 Deploy target: RELEASE (${env.DEPLOY_HOST})" + env.COMPOSE_FILE = 'docker-compose.release.yml' + echo "📦 Deploy target: RELEASE (${env.DEPLOY_HOST}) using ${env.COMPOSE_FILE}" } else { - env.COMPOSE_ENV_FILE_ARG = '' - echo "📦 Deploy target: PRODUCTION (${env.DEPLOY_HOST})" + env.COMPOSE_FILE = 'docker-compose.core.yml' + echo "📦 Deploy target: PRODUCTION (${env.DEPLOY_HOST}) using ${env.COMPOSE_FILE}" } // 【优化2】动态检测系统资源 @@ -301,11 +300,6 @@ pipeline { checkRemoteDiskOrFail(env.DEPLOY_HOST, 'Deploy') checkRemoteDiskOrFail(env.REGISTRY_HOST, 'Registry') - // .env 检查只对 release/next 生效(prod 仍用 docker-compose 内嵌默认值) - if (env.BRANCH_NAME == 'release/next') { - checkRemoteEnvFileOrFail(env.DEPLOY_HOST, env.DEPLOY_PATH) - } - recordStageMetrics('Pre-deploy Check', stageStartTime) } } @@ -338,9 +332,9 @@ pipeline { backupCurrentDeployment(sortedServices) } - // 【新增】同步最新的 docker-compose.core.yml 到部署服务器 - echo "📂 Syncing docker-compose.core.yml to deploy host..." - sh "scp -o StrictHostKeyChecking=no -i ${env.SSH_KEY} docker-compose.core.yml root@${env.DEPLOY_HOST}:${env.DEPLOY_PATH}/" + // 同步当前分支对应的 compose 文件到部署服务器(master→core、release/next→release) + echo "📂 Syncing ${env.COMPOSE_FILE} to deploy host..." + sh "scp -o StrictHostKeyChecking=no -i ${env.SSH_KEY} ${env.COMPOSE_FILE} root@${env.DEPLOY_HOST}:${env.DEPLOY_PATH}/" try { // 串行部署(保证依赖关系) @@ -738,7 +732,7 @@ def getPreviousImageTag() { script: """ ssh ${sshOpts} root@${env.DEPLOY_HOST} ' cd ${env.DEPLOY_PATH} - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml images --format json | \ + docker compose -f ${env.COMPOSE_FILE} images --format json | \ jq -r ".[0].Tag" | head -1 ' 2>/dev/null || echo "latest" """, @@ -767,7 +761,7 @@ def backupCurrentDeployment(def services) { cp docker-compose.core.yml docker-compose.core.yml.backup-${env.BUILD_NUMBER} # 记录当前运行的镜像 - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml images > deployment-state-${env.BUILD_NUMBER}.txt + docker compose -f ${env.COMPOSE_FILE} images > deployment-state-${env.BUILD_NUMBER}.txt echo "✅ Backup completed: deployment-state-${env.BUILD_NUMBER}.txt" ' @@ -804,10 +798,10 @@ def rollbackDeployment(def services) { export IMAGE_TAG=${env.PREVIOUS_IMAGE_TAG} # 拉取旧版本镜像 - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml pull ${service} + docker compose -f ${env.COMPOSE_FILE} pull ${service} # 重启服务 - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml up -d ${service} + docker compose -f ${env.COMPOSE_FILE} up -d ${service} echo "✅ ${service} rolled back to ${env.PREVIOUS_IMAGE_TAG}" ' @@ -942,10 +936,10 @@ def deployService(String service) { cd ${env.DEPLOY_PATH} echo "📥 Pulling ${service}..." - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml pull ${service} + docker compose -f ${env.COMPOSE_FILE} pull ${service} echo "🔄 Restarting ${service}..." - docker compose ${env.COMPOSE_ENV_FILE_ARG} -f docker-compose.core.yml up -d ${service} + docker compose -f ${env.COMPOSE_FILE} up -d ${service} echo "⏳ Waiting for container to start..." sleep 5 @@ -1170,24 +1164,6 @@ def checkRemoteDiskOrFail(String host, String role) { } } -// 检查部署机上 .env 文件是否存在(多环境配置必须由运维手工放置,缺失时拒绝部署避免连错中间件) -def checkRemoteEnvFileOrFail(String host, String deployPath) { - def sshOpts = "-o StrictHostKeyChecking=no -o ConnectTimeout=10 -i ${env.SSH_KEY}" - def envExists = sh( - script: "ssh ${sshOpts} root@${host} 'test -f ${deployPath}/.env && echo yes || echo no'", - returnStdout: true - ).trim() - - if (envExists != 'yes') { - error("""❌ ${host}:${deployPath}/.env 不存在! -请先在部署机上手工放置环境变量文件(敏感凭据不进 git): - - prod 模板:env/prod.env.example - - release 模板:env/release.env.example -拷贝模板到 ${deployPath}/.env 并填好密码、CTSDB 凭据等占位符后再触发部署。""") - } - echo " ✅ ${host}:${deployPath}/.env 存在" -} - // Prod/Release 本地清理:调用仓库内的 cleanup.sh def cleanupDeployHost(String host, String keep) { def sshOpts = "-o StrictHostKeyChecking=no -o ConnectTimeout=10 -i ${env.SSH_KEY}" diff --git a/docker-compose.core.yml b/docker-compose.core.yml index 155e8f95..5abe4cda 100644 --- a/docker-compose.core.yml +++ b/docker-compose.core.yml @@ -1,11 +1,3 @@ -# ============================================ -# 后端核心服务 - 多环境通用 Compose -# ============================================ -# 部署机调用: -# docker compose --env-file .env -f docker-compose.core.yml up -d -# 不传 --env-file 时,所有 ${VAR:-default} 落到 prod 默认值,行为与历史一致。 -# 部署机的 .env 由运维手工维护,不进 git(敏感凭据)。 -# ============================================ version: '3.8' networks: @@ -16,42 +8,6 @@ networks: volumes: app-logs: -# ============================================ -# 公共环境变量片段(YAML anchor) -# ============================================ -x-common-env: &common-env - TZ: Asia/Shanghai - SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod} - - # ===== Nacos ===== - NACOS_USERNAME: ${NACOS_USERNAME:-nacos} - NACOS_PASSWORD: ${NACOS_PASSWORD:-9oDxX~}e7DeP} - NACOS_ADDR: ${NACOS_ADDR:-172.17.16.7:8848} - NACOS_DISCOVERY_NAMESPACE: ${NACOS_DISCOVERY_NAMESPACE:-8efd6d96-de7f-4664-b28e-c2788ffa1395} - NACOS_CONFIG_NAMESPACE: ${NACOS_CONFIG_NAMESPACE:-8efd6d96-de7f-4664-b28e-c2788ffa1395} - - # ===== MySQL ===== - SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: ${MYSQL_URL:-jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true} - SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: ${MYSQL_USERNAME:-root} - SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: ${MYSQL_PASSWORD:-tKi8rfUJjVrf@} - - # ===== Redis ===== - SPRING_DATA_REDIS_HOST: ${REDIS_HOST:-172.17.16.13} - SPRING_DATA_REDIS_PORT: ${REDIS_PORT:-6379} - SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD:-HkVZkVnn1} - - # ===== RocketMQ ===== - ROCKETMQ_NAMESRV_ADDR: ${ROCKETMQ_NAMESRV_ADDR:-rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080} - ROCKETMQ_ACCESS_KEY: ${ROCKETMQ_ACCESS_KEY:-ak4wd73bxpv55331e7c5b80} - ROCKETMQ_SECRET_KEY: ${ROCKETMQ_SECRET_KEY:-sk82108944bc0997f7} - - # ===== XXL-Job ===== - # 注意:XXL_JOB_EXECUTOR_APPNAME 用来区分 prod/release 在同一 admin 下的执行器组 - # (后端 application.yaml 需要支持 ${XXL_JOB_EXECUTOR_APPNAME:${spring.application.name}}) - XXL_JOB_ADMIN_ADDRESSES: ${XXL_JOB_ADMIN_ADDRESSES:-http://172.17.16.7:19090/xxl-job-admin} - XXL_JOB_EXECUTOR_IP: ${XXL_JOB_EXECUTOR_IP:-172.17.16.14} - XXL_JOB_EXECUTOR_APPNAME_SUFFIX: ${XXL_JOB_EXECUTOR_APPNAME_SUFFIX:-} - services: viewsh-gateway: image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-gateway:${IMAGE_TAG:-latest} @@ -60,8 +16,25 @@ services: ports: - "48080:48080" environment: - <<: *common-env + # ===== 基础配置 ===== + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod + + # ===== JVM 配置 ===== JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + # ===== Nacos 配置 ===== + NACOS_USERNAME: nacos + NACOS_PASSWORD: 9oDxX~}e7DeP + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + NACOS_CONFIG_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + + # ===== Redis 配置 ===== + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PORT: 6379 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + volumes: - app-logs:/app/logs deploy: @@ -84,16 +57,37 @@ services: - "48081:48081" - "9901:9901" environment: - <<: *common-env + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" - - # 微信配置(system-server 独有) - WX_MP_APP_ID: ${WX_MP_APP_ID:-wx5b23ba7a5589ecbb} - WX_MP_SECRET: ${WX_MP_SECRET:-2a7b3b20c537e52e74afd395eb85f61f} - WX_MINIAPP_APPID: ${WX_MINIAPP_APPID:-wxc4598c446f8a9cb3} - WX_MINIAPP_SECRET: ${WX_MINIAPP_SECRET:-4a1a04e07f6a4a0751b39c3064a92c8b} - + + # ===== Nacos 配置 ===== + NACOS_USERNAME: nacos + NACOS_PASSWORD: 9oDxX~}e7DeP + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + NACOS_CONFIG_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + + # 数据库 + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root # TODO: 填入数据库用户名 + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: "tKi8rfUJjVrf@" # TODO: 填入数据库密码 + + # Redis + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" # TODO: 填入 Redis 密码 + + # 微信配置 (解决 appid 不能为 null) + WX_MP_APP_ID: "wx5b23ba7a5589ecbb" + WX_MP_SECRET: "2a7b3b20c537e52e74afd395eb85f61f" + WX_MINIAPP_APPID: "wxc4598c446f8a9cb3" + WX_MINIAPP_SECRET: "4a1a04e07f6a4a0751b39c3064a92c8b" + + # XXL-Job 调度中心地址 + XXL_JOB_ADMIN_ADDRESSES: http://172.17.16.7:19090/xxl-job-admin + XXL_JOB_EXECUTOR_IP: 172.17.16.14 XXL_JOB_EXECUTOR_PORT: 9901 + volumes: - app-logs:/app/logs deploy: @@ -119,9 +113,28 @@ services: - "48082:48082" - "9902:9902" environment: - <<: *common-env + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + NACOS_USERNAME: nacos + NACOS_PASSWORD: 9oDxX~}e7DeP + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + NACOS_CONFIG_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: "tKi8rfUJjVrf@" + + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + # XXL-Job 调度中心地址 + XXL_JOB_ADMIN_ADDRESSES: http://172.17.16.7:19090/xxl-job-admin + XXL_JOB_EXECUTOR_IP: 172.17.16.14 XXL_JOB_EXECUTOR_PORT: 9902 + volumes: - app-logs:/app/logs healthcheck: @@ -142,24 +155,38 @@ services: - "48091:48091" - "9903:9903" environment: - <<: *common-env + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod JAVA_OPTS: "-Xms1024m -Xmx2048m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" - # ===== 时序库(iot-server 独有)===== - # prod 用 TDengine(172.17.16.7:6041),release 用腾讯云 CTSDB(InfluxDB 兼容) - # 通过 TSDB_TYPE 切换:tdengine | ctsdb - TSDB_TYPE: ${TSDB_TYPE:-tdengine} - TDENGINE_HOST: ${TDENGINE_HOST:-172.17.16.7} - TDENGINE_PORT: ${TDENGINE_PORT:-6041} - TDENGINE_USERNAME: ${TDENGINE_USERNAME:-root} - TDENGINE_PASSWORD: ${TDENGINE_PASSWORD:-taosdata} - TDENGINE_DATABASE: ${TDENGINE_DATABASE:-aiot_platform} - CTSDB_URL: ${CTSDB_URL:-} - CTSDB_USERNAME: ${CTSDB_USERNAME:-} - CTSDB_PASSWORD: ${CTSDB_PASSWORD:-} - CTSDB_DATABASE: ${CTSDB_DATABASE:-} + NACOS_USERNAME: nacos + NACOS_PASSWORD: 9oDxX~}e7DeP + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + NACOS_CONFIG_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: "tKi8rfUJjVrf@" + + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + ROCKETMQ_NAMESRV_ADDR: rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080 + ROCKETMQ_ACCESS_KEY: ak4wd73bxpv55331e7c5b80 + ROCKETMQ_SECRET_KEY: sk82108944bc0997f7 + # TDengine + TDENGINE_HOST: 172.17.16.7 + TDENGINE_PORT: 6041 + TDENGINE_USERNAME: root + TDENGINE_PASSWORD: taosdata + + # XXL-Job 调度中心地址 + XXL_JOB_ADMIN_ADDRESSES: http://172.17.16.7:19090/xxl-job-admin + XXL_JOB_EXECUTOR_IP: 172.17.16.14 XXL_JOB_EXECUTOR_PORT: 9903 + volumes: - app-logs:/app/logs deploy: @@ -188,17 +215,15 @@ services: environment: IOT_TCP_ENABLED: "true" TZ: Asia/Shanghai - SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod} + SPRING_PROFILES_ACTIVE: prod JAVA_OPTS: "-Xms1024m -Xmx2048m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" - - SPRING_DATA_REDIS_HOST: ${REDIS_HOST:-172.17.16.13} - SPRING_DATA_REDIS_PORT: ${REDIS_PORT:-6379} - SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD:-HkVZkVnn1} - - ROCKETMQ_NAMESRV_ADDR: ${ROCKETMQ_NAMESRV_ADDR:-rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080} - ROCKETMQ_ACCESS_KEY: ${ROCKETMQ_ACCESS_KEY:-ak4wd73bxpv55331e7c5b80} - ROCKETMQ_SECRET_KEY: ${ROCKETMQ_SECRET_KEY:-sk82108944bc0997f7} - + + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + ROCKETMQ_NAMESRV_ADDR: rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080 + ROCKETMQ_ACCESS_KEY: ak4wd73bxpv55331e7c5b80 + ROCKETMQ_SECRET_KEY: sk82108944bc0997f7 VIEWSH_IOT_GATEWAY_RPC_URL: "http://aiot-iot-server:48091" volumes: - app-logs:/app/logs @@ -218,9 +243,32 @@ services: - "48092:48092" - "9904:9904" environment: - <<: *common-env + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + NACOS_USERNAME: nacos + NACOS_PASSWORD: 9oDxX~}e7DeP + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + NACOS_CONFIG_NAMESPACE: "8efd6d96-de7f-4664-b28e-c2788ffa1395" + + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: "tKi8rfUJjVrf@" + + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + ROCKETMQ_NAMESRV_ADDR: rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080 + ROCKETMQ_ACCESS_KEY: ak4wd73bxpv55331e7c5b80 + ROCKETMQ_SECRET_KEY: sk82108944bc0997f7 + + # XXL-Job 调度中心地址 + XXL_JOB_ADMIN_ADDRESSES: http://172.17.16.7:19090/xxl-job-admin + XXL_JOB_EXECUTOR_IP: 172.17.16.14 XXL_JOB_EXECUTOR_PORT: 9904 + volumes: - app-logs:/app/logs healthcheck: diff --git a/docker-compose.release.yml b/docker-compose.release.yml new file mode 100644 index 00000000..ce64e2b5 --- /dev/null +++ b/docker-compose.release.yml @@ -0,0 +1,236 @@ +# ============================================ +# 后端核心服务 - RELEASE 环境(172.17.16.7) +# ============================================ +# 由 Jenkins release/next 分支自动同步到部署机后用: +# docker compose -f docker-compose.release.yml up -d +# 与 docker-compose.core.yml 区别: +# - MySQL 库:aiot-platform-test → aiot-platform-release +# - Nacos namespace:8efd6d96-... → e635b215-... +# - TDengine database:aiot_platform → aiot_platform_release +# - XXL-Job executor IP:.14 → .7、appname 加 -release 后缀 +# - RocketMQ:腾讯云外网 → staging 服务器内网 172.17.16.7:9876(无 ACL) +# 其余密码/凭据沿用 prod(同 docker-compose.core.yml) +# ============================================ +version: '3.8' + +networks: + default: + name: 1panel-network + external: true + +volumes: + app-logs: + +# ============================================ +# 公共环境变量片段(YAML anchor) +# ============================================ +x-common-env: &common-env + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod + + # ===== Nacos(独立 namespace) ===== + NACOS_USERNAME: nacos + NACOS_PASSWORD: "9oDxX~}e7DeP" + NACOS_ADDR: 172.17.16.7:8848 + NACOS_DISCOVERY_NAMESPACE: "e635b215-913e-4bc8-8867-2fbf7d5134aa" + NACOS_CONFIG_NAMESPACE: "e635b215-913e-4bc8-8867-2fbf7d5134aa" + + # ===== MySQL(同实例独立库 aiot-platform-release) ===== + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://172.17.16.8:3306/aiot-platform-release?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root + SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: "tKi8rfUJjVrf@" + + # ===== Redis(同 prod 实例) ===== + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PORT: 6379 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + # ===== RocketMQ(release 服务器本地实例,内网,无 ACL) ===== + ROCKETMQ_NAMESRV_ADDR: 172.17.16.7:9876 + ROCKETMQ_ACCESS_KEY: "" + ROCKETMQ_SECRET_KEY: "" + + # ===== XXL-Job(同 admin,executor IP=.7、appname 加 -release 后缀) ===== + XXL_JOB_ADMIN_ADDRESSES: http://172.17.16.7:19090/xxl-job-admin + XXL_JOB_EXECUTOR_IP: 172.17.16.7 + XXL_JOB_EXECUTOR_APPNAME_SUFFIX: "-release" + +services: + viewsh-gateway: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-gateway:${IMAGE_TAG:-latest} + container_name: aiot-gateway + restart: on-failure:5 + ports: + - "48080:48080" + environment: + <<: *common-env + JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + volumes: + - app-logs:/app/logs + deploy: + resources: + limits: + memory: 1536m + cpus: '1.0' + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:48080/actuator/health"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 120s + + viewsh-module-system-server: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-module-system-server:${IMAGE_TAG:-latest} + container_name: aiot-system-server + restart: on-failure:5 + ports: + - "48081:48081" + - "9901:9901" + environment: + <<: *common-env + JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + # 微信配置(system-server 独有,沿用 prod) + WX_MP_APP_ID: "wx5b23ba7a5589ecbb" + WX_MP_SECRET: "2a7b3b20c537e52e74afd395eb85f61f" + WX_MINIAPP_APPID: "wxc4598c446f8a9cb3" + WX_MINIAPP_SECRET: "4a1a04e07f6a4a0751b39c3064a92c8b" + + XXL_JOB_EXECUTOR_PORT: 9901 + volumes: + - app-logs:/app/logs + deploy: + resources: + limits: + memory: 1536m + cpus: '1.0' + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:48081/actuator/health"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 120s + depends_on: + viewsh-gateway: + condition: service_healthy + + viewsh-module-infra-server: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-module-infra-server:${IMAGE_TAG:-latest} + container_name: aiot-infra-server + restart: on-failure:5 + ports: + - "48082:48082" + - "9902:9902" + environment: + <<: *common-env + JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + XXL_JOB_EXECUTOR_PORT: 9902 + volumes: + - app-logs:/app/logs + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:48082/actuator/health"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 120s + depends_on: + viewsh-module-system-server: + condition: service_healthy + + viewsh-module-iot-server: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-module-iot-server:${IMAGE_TAG:-latest} + container_name: aiot-iot-server + restart: on-failure:5 + ports: + - "48091:48091" + - "9903:9903" + environment: + <<: *common-env + JAVA_OPTS: "-Xms1024m -Xmx2048m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + # ===== 时序库(共享 prod TDengine 实例,独立 database aiot_platform_release) ===== + TSDB_TYPE: tdengine + TDENGINE_HOST: 172.17.16.7 + TDENGINE_PORT: 6041 + TDENGINE_USERNAME: root + TDENGINE_PASSWORD: taosdata + TDENGINE_DATABASE: aiot_platform_release + # CTSDB 切换 follow-up(暂留空) + CTSDB_URL: "" + CTSDB_USERNAME: "" + CTSDB_PASSWORD: "" + CTSDB_DATABASE: "" + + XXL_JOB_EXECUTOR_PORT: 9903 + volumes: + - app-logs:/app/logs + deploy: + resources: + limits: + memory: 2560m + cpus: '1.5' + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:48091/actuator/health"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 120s + depends_on: + viewsh-module-infra-server: + condition: service_healthy + + viewsh-module-iot-gateway: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-module-iot-gateway:${IMAGE_TAG:-latest} + container_name: aiot-iot-gateway + restart: on-failure:5 + ports: + - "1883:1883" + - "8092:8092" + - "8091:8091" + environment: + IOT_TCP_ENABLED: "true" + TZ: Asia/Shanghai + SPRING_PROFILES_ACTIVE: prod + JAVA_OPTS: "-Xms1024m -Xmx2048m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + + SPRING_DATA_REDIS_HOST: 172.17.16.13 + SPRING_DATA_REDIS_PORT: 6379 + SPRING_DATA_REDIS_PASSWORD: "HkVZkVnn1" + + ROCKETMQ_NAMESRV_ADDR: 172.17.16.7:9876 + ROCKETMQ_ACCESS_KEY: "" + ROCKETMQ_SECRET_KEY: "" + + VIEWSH_IOT_GATEWAY_RPC_URL: "http://aiot-iot-server:48091" + volumes: + - app-logs:/app/logs + deploy: + resources: + limits: + memory: 2560m + cpus: '1.5' + depends_on: + - viewsh-module-iot-server + + viewsh-module-ops-server: + image: ${REGISTRY_HOST:-172.17.16.7:5000}/viewsh-module-ops-server:${IMAGE_TAG:-latest} + container_name: aiot-ops-server + restart: on-failure:5 + ports: + - "48092:48092" + - "9904:9904" + environment: + <<: *common-env + JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs" + XXL_JOB_EXECUTOR_PORT: 9904 + volumes: + - app-logs:/app/logs + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:48092/actuator/health"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 120s + depends_on: + viewsh-module-iot-server: + condition: service_healthy diff --git a/env/.gitignore b/env/.gitignore deleted file mode 100644 index 40028a6b..00000000 --- a/env/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# env 目录里只允许 .example 模板进 git,真实 .env 一律忽略 -*.env -!*.env.example diff --git a/env/prod.env.example b/env/prod.env.example deleted file mode 100644 index b1270a0f..00000000 --- a/env/prod.env.example +++ /dev/null @@ -1,61 +0,0 @@ -# ============================================ -# 生产环境(PROD)环境变量模板 -# ============================================ -# 部署机使用方式: -# 1) 拷贝到 /opt/aiot-platform-cloud/.env -# 2) 把 等占位符填成真实值(千万别 commit) -# 3) Jenkins/手工部署:docker compose --env-file .env -f docker-compose.core.yml up -d -# ============================================ - -# ===== Spring ===== -SPRING_PROFILES_ACTIVE=prod - -# ===== Nacos ===== -NACOS_USERNAME=nacos -NACOS_PASSWORD= -NACOS_ADDR=172.17.16.7:8848 -NACOS_DISCOVERY_NAMESPACE=8efd6d96-de7f-4664-b28e-c2788ffa1395 -NACOS_CONFIG_NAMESPACE=8efd6d96-de7f-4664-b28e-c2788ffa1395 - -# ===== MySQL ===== -MYSQL_URL=jdbc:mysql://172.17.16.8:3306/aiot-platform-test?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true -MYSQL_USERNAME=root -MYSQL_PASSWORD= - -# ===== Redis ===== -REDIS_HOST=172.17.16.13 -REDIS_PORT=6379 -REDIS_PASSWORD= - -# ===== RocketMQ(腾讯云外网 endpoint)===== -ROCKETMQ_NAMESRV_ADDR=rmq-4wd73bxpv.rocketmq.sh.qcloud.tencenttdmq.com:8080 -ROCKETMQ_ACCESS_KEY= -ROCKETMQ_SECRET_KEY= - -# ===== 时序库(prod 用 TDengine)===== -TSDB_TYPE=tdengine -TDENGINE_HOST=172.17.16.7 -TDENGINE_PORT=6041 -TDENGINE_USERNAME=root -TDENGINE_PASSWORD= -# CTSDB 不用,留空 -CTSDB_URL= -CTSDB_USERNAME= -CTSDB_PASSWORD= -CTSDB_DATABASE= - -# ===== XXL-Job ===== -XXL_JOB_ADMIN_ADDRESSES=http://172.17.16.7:19090/xxl-job-admin -XXL_JOB_EXECUTOR_IP=172.17.16.14 -# prod 不加后缀(保持现有 admin 上的执行器组名不变) -XXL_JOB_EXECUTOR_APPNAME_SUFFIX= - -# ===== 微信(生产 AppId/Secret)===== -WX_MP_APP_ID=wx5b23ba7a5589ecbb -WX_MP_SECRET= -WX_MINIAPP_APPID=wxc4598c446f8a9cb3 -WX_MINIAPP_SECRET= - -# ===== 镜像 ===== -REGISTRY_HOST=172.17.16.7:5000 -# IMAGE_TAG 由 CI 在 docker compose 命令前 export,无需在 .env 里固定 diff --git a/env/release.env.example b/env/release.env.example deleted file mode 100644 index 697b8945..00000000 --- a/env/release.env.example +++ /dev/null @@ -1,69 +0,0 @@ -# ============================================ -# 预发布环境(RELEASE)环境变量模板 -# ============================================ -# 部署机使用方式: -# 1) 拷贝到 172.17.16.7 的 /opt/aiot-platform-cloud/.env -# 2) 把 等占位符填成真实值(千万别 commit) -# 3) Jenkins/手工部署:docker compose --env-file .env -f docker-compose.core.yml up -d -# ============================================ - -# ===== Spring ===== -SPRING_PROFILES_ACTIVE=prod - -# ===== Nacos(独立 namespace,与 prod 隔离)===== -NACOS_USERNAME=nacos -NACOS_PASSWORD= -NACOS_ADDR=172.17.16.7:8848 -NACOS_DISCOVERY_NAMESPACE=e635b215-913e-4bc8-8867-2fbf7d5134aa -NACOS_CONFIG_NAMESPACE=e635b215-913e-4bc8-8867-2fbf7d5134aa - -# ===== MySQL(同实例,独立库)===== -# 库名从 aiot-platform-test 改为 aiot-platform-release -MYSQL_URL=jdbc:mysql://172.17.16.8:3306/aiot-platform-release?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true -MYSQL_USERNAME=root -MYSQL_PASSWORD= - -# ===== Redis(同 prod 实例,注意 key 前缀靠应用层隔离)===== -REDIS_HOST=172.17.16.13 -REDIS_PORT=6379 -REDIS_PASSWORD= - -# ===== RocketMQ(用 release 服务器本地部署的 1Panel-rocketmq-ZQQi 实例,内网地址)===== -# 1Panel 上 namesrv 容器对外端口(请按实际 1Panel 暴露端口校正,默认 9876) -ROCKETMQ_NAMESRV_ADDR=172.17.16.7:9876 -# 自部署 RocketMQ 通常无 ACL,留空即可;如启用了 ACL 再填 -ROCKETMQ_ACCESS_KEY= -ROCKETMQ_SECRET_KEY= - -# ===== 时序库 ===== -# TODO: release 计划用腾讯云 CTSDB(InfluxDB 兼容),但当前后端 application-prod.yaml 仍写死 -# TDengine 的 jdbc:TAOS-RS 协议;切到 CTSDB 需要后端代码层改造(双引擎抽象在 -# framework/tsdb/ 已有但 yaml 未启用切换)。短期方案:release 共享 prod 的 TDengine -# 实例(172.17.16.7:6041),通过独立 database 名隔离。 -TSDB_TYPE=tdengine -TDENGINE_HOST=172.17.16.7 -TDENGINE_PORT=6041 -TDENGINE_USERNAME=root -TDENGINE_PASSWORD= -TDENGINE_DATABASE=aiot_platform_release -# CTSDB 切换 follow-up(暂留空) -CTSDB_URL= -CTSDB_USERNAME= -CTSDB_PASSWORD= -CTSDB_DATABASE= - -# ===== XXL-Job ===== -# 共用 prod 的 admin(http://172.17.16.7:19090),但用 -release 后缀区分执行器组 -# 否则 admin 调度任务会同时打到 prod 和 release(同 appname 串台) -XXL_JOB_ADMIN_ADDRESSES=http://172.17.16.7:19090/xxl-job-admin -XXL_JOB_EXECUTOR_IP=172.17.16.7 -XXL_JOB_EXECUTOR_APPNAME_SUFFIX=-release - -# ===== 微信(建议 release 用沙箱号;先沿用 prod)===== -WX_MP_APP_ID=wx5b23ba7a5589ecbb -WX_MP_SECRET= -WX_MINIAPP_APPID=wxc4598c446f8a9cb3 -WX_MINIAPP_SECRET= - -# ===== 镜像 ===== -REGISTRY_HOST=172.17.16.7:5000