diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index e7a116f12..46dd39d9a 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -125,9 +125,9 @@ services: FILE_DB_PASSWORD: ${FILE_DB_PASSWORD} FILE_STORAGE_ROOT: /data/files JAVA_TOOL_OPTIONS: "-Xms1g -Xmx2g -XX:+ExitOnOutOfMemoryError -Dfile.encoding=UTF-8" - ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER} - # 必须显式设置:测试填 test-,生产填空字符串;使用 ? 而不是 :?,允许生产空值。 - MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX?MQ_TOPIC_PREFIX must be set; use test- for test and an empty value for production} + # Compose 会插值整份文件,即使只部署 auth 等其他服务;File 的必填校验由 deploy-services.sh 按服务执行。 + ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER-} + MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX-} FILE_EXPORT_CONSUMER_ENABLED: ${FILE_EXPORT_CONSUMER_ENABLED:-false} FILE_EXPORT_CONSUMER_CONCURRENCY: ${FILE_EXPORT_CONSUMER_CONCURRENCY:-4} FILE_EXPORT_PUBLISHER_ENABLED: ${FILE_EXPORT_PUBLISHER_ENABLED:-false} diff --git a/deploy/scripts/deploy-services.sh b/deploy/scripts/deploy-services.sh index 4271e1434..9ab70dcf2 100644 --- a/deploy/scripts/deploy-services.sh +++ b/deploy/scripts/deploy-services.sh @@ -19,6 +19,48 @@ fi SERVICES=$(printf '%s' "$SERVICE_CSV" | tr ',' ' ') +env_file_has_key() { + grep -q "^$1=" "$ENV_FILE" +} + +env_file_value() { + sed -n "s/^$1=//p" "$ENV_FILE" | tail -n 1 | tr -d '\r' +} + +case " $SERVICES " in + *" file "*) + if ! env_file_has_key ROCKETMQ_NAME_SERVER || [ -z "$(env_file_value ROCKETMQ_NAME_SERVER)" ]; then + echo "部署 file 服务时,环境文件必须包含非空 ROCKETMQ_NAME_SERVER" >&2 + exit 2 + fi + if ! env_file_has_key MQ_TOPIC_PREFIX; then + echo "部署 file 服务时,环境文件必须显式包含 MQ_TOPIC_PREFIX:测试填 test-,生产填空字符串" >&2 + exit 2 + fi + MQ_PREFIX=$(env_file_value MQ_TOPIC_PREFIX) + case "$DEPLOY_ENV" in + test) + if [ "$MQ_PREFIX" != "test-" ]; then + echo "测试环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为 test-" >&2 + exit 2 + fi + ;; + production) + if [ -n "$MQ_PREFIX" ]; then + echo "生产环境部署 file 服务时 MQ_TOPIC_PREFIX 必须显式为空字符串" >&2 + exit 2 + fi + ;; + *) + if [ -z "$MQ_PREFIX" ] || [ "$MQ_PREFIX" = "test-" ]; then + echo "预发布环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为非空且不能使用 test-" >&2 + exit 2 + fi + ;; + esac + ;; +esac + export DEPLOY_ENV IMAGE_REPOSITORY IMAGE_TAG PULL_POLICY_ARGS="" diff --git a/docs/公共导出与下载中心接入说明.md b/docs/公共导出与下载中心接入说明.md index 23b135cac..ba2bb0510 100644 --- a/docs/公共导出与下载中心接入说明.md +++ b/docs/公共导出与下载中心接入说明.md @@ -100,7 +100,7 @@ FILE_EXPORT_RETENTION_DAYS FILE_STORAGE_ROOT ``` -`MQ_TOPIC_PREFIX` 是部署必填项但允许空值:测试环境显式填 `test-`,生产环境显式填空字符串。不能使用 `:-test-` 作为 Compose 默认值,否则生产空值会被重新替换成测试前缀。 +`MQ_TOPIC_PREFIX` 是 File 部署必填项但允许生产空值:测试环境显式填 `test-`,生产环境显式填空字符串。Compose 单服务部署会插值整份文件,因此 File 服务块本身使用空默认值,避免 Auth/IAM 等无关服务被 MQ 配置阻断;`deploy-services.sh` 只在部署 File 时按环境强校验该变量与 `ROCKETMQ_NAME_SERVER`。 当前 RocketMQ Compose 不映射 Broker 宿主机端口,File 与 Broker 必须同在 `infra-network`,因此 `ROCKETMQ_BROKER_IP` 填 `rocketmq-broker`。Topic 初始化会等待 `BaiyueCluster` 真正注册,任一幂等初始化命令失败后自动重试。 diff --git a/docs/公共导出中心RocketMQ架构设计.md b/docs/公共导出中心RocketMQ架构设计.md index 1bf2181b5..9d2476996 100644 --- a/docs/公共导出中心RocketMQ架构设计.md +++ b/docs/公共导出中心RocketMQ架构设计.md @@ -1258,7 +1258,7 @@ RocketMQ NameServer/Broker 就绪 -> Admin 验收 ``` -环境变量需在 `deploy/docker-compose.yml` 与 Jenkins 中透传:`ROCKETMQ_NAME_SERVER`、`MQ_TOPIC_PREFIX`、`ROCKETMQ_BROKER_IP`、`FILE_EXPORT_CONSUMER_ENABLED`、`FILE_EXPORT_CONSUMER_CONCURRENCY`、`FILE_EXPORT_PUBLISHER_ENABLED`、`FILE_EXPORT_RECONCILER_ENABLED`。`MQ_TOPIC_PREFIX` 不得省略:测试显式设为 `test-`,生产显式设为空字符串。测试与生产的 `FILE_EXPORT_CONSUMER_CONCURRENCY` 初始值均显式设为 `4`,不只依赖应用默认值;三个启用开关首次上线均显式设为 `false`,再按本节顺序逐项改为 `true`。File 容器需要 `HOSTNAME` 可用(Docker 默认提供)。 +环境变量需在 `deploy/docker-compose.yml` 与 Jenkins 中透传:`ROCKETMQ_NAME_SERVER`、`MQ_TOPIC_PREFIX`、`ROCKETMQ_BROKER_IP`、`FILE_EXPORT_CONSUMER_ENABLED`、`FILE_EXPORT_CONSUMER_CONCURRENCY`、`FILE_EXPORT_PUBLISHER_ENABLED`、`FILE_EXPORT_RECONCILER_ENABLED`。Compose 会在单服务部署前插值整份文件,因此不能在 File 服务块使用 `${MQ_TOPIC_PREFIX?...}` 阻断 Auth/IAM 等无关服务;`deploy/scripts/deploy-services.sh` 只在部署 File 时执行环境级强校验。`MQ_TOPIC_PREFIX` 对 File 不得省略:测试必须显式设为 `test-`,生产必须显式设为空字符串。测试与生产的 `FILE_EXPORT_CONSUMER_CONCURRENCY` 初始值均显式设为 `4`,不只依赖应用默认值;三个启用开关首次上线均显式设为 `false`,再按本节顺序逐项改为 `true`。File 容器需要 `HOSTNAME` 可用(Docker 默认提供)。 ## 19. 测试与验收门槛 diff --git a/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java b/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java index fb408ae0a..333f3e4ca 100644 --- a/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java +++ b/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java @@ -16,8 +16,12 @@ class ExportInfrastructureContractTest { assertTrue(compose.contains("FILE_EXPORT_PUBLISHER_ENABLED: ${FILE_EXPORT_PUBLISHER_ENABLED:-false}")); assertTrue(compose.contains("FILE_EXPORT_RECONCILER_ENABLED: ${FILE_EXPORT_RECONCILER_ENABLED:-false}")); assertTrue(compose.contains("-Xms1g -Xmx2g")); - assertTrue(compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX?")); - assertTrue(!compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX:-test-}")); + assertTrue(compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX-}")); + assertTrue(compose.contains("ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER-}")); + String deployScript=read("..","deploy","scripts","deploy-services.sh"); + assertTrue(deployScript.contains("部署 file 服务时,环境文件必须显式包含 MQ_TOPIC_PREFIX")); + assertTrue(deployScript.contains("测试环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为 test-")); + assertTrue(deployScript.contains("环境文件必须包含非空 ROCKETMQ_NAME_SERVER")); } @Test void rocketMqBootstrapCreatesBothGroupsAndAReadableWorkerDlq() throws Exception {