Spring Boot 应用配置参数化实践:通过 Docker Run 参数传递配置

Spring Boot 应用配置参数化实践:通过 Docker Run 参数传递配置

概述

在现代微服务架构中,应用的配置管理是一个关键问题。硬编码配置会导致应用在不同环境(开发、测试、生产)中部署时需要重新构建镜像,这违背了"一次构建,到处运行"的原则。本文将介绍如何通过 Spring Boot 的配置参数化机制,结合 Docker 环境变量传递,实现应用的灵活配置管理。

为什么需要配置参数化?

传统方式的痛点

  1. 环境差异:不同环境(开发、测试、生产)的数据库、Redis、ZooKeeper 等中间件地址不同
  2. 安全性:敏感信息(如密码)不应该硬编码在配置文件中
  3. 灵活性:每次环境变更都需要重新构建镜像,效率低下
  4. 可维护性:多个配置文件难以统一管理

参数化的优势

  • 一次构建,多处部署:同一个镜像可以在不同环境使用
  • 安全性提升:敏感信息通过环境变量传递,不进入镜像
  • 运维友好:无需重新构建镜像即可调整配置
  • 符合 12-Factor App 原则:配置与代码分离

Spring Boot 配置参数化实现

1. 配置文件中的参数化语法

Spring Boot 支持使用 ${变量名:默认值} 的语法来引用环境变量,如果环境变量不存在则使用默认值。

以下是一个实际的 application-prod.properties 配置示例:

properties 复制代码
# 应用端口配置
server.port=8097

# Dubbo 注册中心配置
dubbo.registry.protocol=zookeeper
dubbo.registry.address=zookeeper://${ZOOKEEPER_ADDRESSES:dubbo1.mysteel.local:2181?backup=dubbo2.mysteel.local:2182,dubbo3.mysteel.local:2183,dubbo4.mysteel.local:2184,dubbo5.mysteel.local:2185}

dubbo.consumer.group=standard-ebc
dubbo.provider.group=standard-ebc
dubbo.provider.version=1.0.0
dubbo.consumer.timeout=300000
dubbo.consumer.version=1.0.0
dubbo.consumer.check=false
dubbo.registry.timeout=300000
dubbo.consumer.loadbalance=roundrobin

# 数据库配置(参数化)
spring.datasource.multi.type=DM
spring.datasource.multi.url=jdbc:dm://${DB_HOST:192.168.173.8}:${DB_PORT:5236}/${DB_NAME:YANGCAI_INIT}?schema=${DB_SCHEMA:YANGCAI_INIT}
spring.datasource.multi.username=${DB_USERNAME:SYSDBA}
spring.datasource.multi.password=${DB_PASSWORD:SYSDBA}

# Redis 配置(参数化)
spring.redis.host=${REDIS_HOST:192.168.0.4}
spring.redis.port=${REDIS_PORT:6379}
spring.redis.password=${REDIS_PASSWORD:nm@eloL!FFmmY5}

# 日志配置
logging.level.root=INFO

# 生产环境设置(关闭接口文档)
knife4j.production=true

# 业务配置
workTypeId=3
callbackUrl=http://172.18.10.13:8097/database/apply/callback

# Elasticsearch 配置(参数化)
spring.elasticsearch.rest.uris=${ES_URIS:172.18.10.30:9200}
spring.elasticsearch.rest.connection-timeout=60s
spring.elasticsearch.rest.username=${ES_USERNAME:elastic}
spring.elasticsearch.rest.password=${ES_PASSWORD:hO8eJ3mS5b}

# 关闭 SSL 证书校验(用于华为云 CSS)
spring.elasticsearch.rest.ssl.verification-mode=none

# 文件路径配置
excelUrl=/fastdfs/group1/M00/B1/83/rBL64GYSky6ATl7hBtCdnfhx_Hc798.exe
index.relation.calculate.path=http://172.18.10.17:8080/calculate_correlation
push.frame.pathUrl=http://ebc.mysteel.local/api/database/pushFrame/getPushFrameFilePathList
autoPull.frame.pathUrl=http://ebc.mysteel.local/api/database/pushFrame/autoPull

# XXL-Job 配置(参数化)
xxl.job.admin.addresses=${XXL_JOB_ADMIN_ADDRESSES:http://172.18.10.13:8080/xxl-job-admin}

# 部署模式
mysteel.global.deployment-mode=2

2. 关键配置项说明

从上述配置可以看出,以下配置项被参数化:

配置项 环境变量 默认值 说明
ZooKeeper 地址 ZOOKEEPER_ADDRESSES dubbo1.mysteel.local:2181?... Dubbo 注册中心地址
数据库主机 DB_HOST 192.168.173.8 数据库服务器地址
数据库端口 DB_PORT 5236 数据库端口
数据库名 DB_NAME YANGCAI_INIT 数据库名称
数据库 Schema DB_SCHEMA YANGCAI_INIT 数据库 Schema
数据库用户名 DB_USERNAME SYSDBA 数据库用户名
数据库密码 DB_PASSWORD SYSDBA 数据库密码
Redis 主机 REDIS_HOST 192.168.0.4 Redis 服务器地址
Redis 端口 REDIS_PORT 6379 Redis 端口
Redis 密码 REDIS_PASSWORD nm@eloL!FFmmY5 Redis 密码
ES 地址 ES_URIS 172.18.10.30:9200 Elasticsearch 地址
ES 用户名 ES_USERNAME elastic Elasticsearch 用户名
ES 密码 ES_PASSWORD hO8eJ3mS5b Elasticsearch 密码
XXL-Job 地址 XXL_JOB_ADMIN_ADDRESSES http://172.18.10.13:8080/xxl-job-admin XXL-Job 管理地址

Docker 环境变量传递

1. Dockerfile 示例

dockerfile 复制代码
from cr.kylinos.cn/basekylin/java-openjdk-8-aarch64:1.8.0-v10sp1

LABEL maintainer="your-email@example.com"
LABEL description="SpringBoot App with JDK 8 on CentOS 7"

# 验证 Java 安装
RUN java -version && javac -version

WORKDIR /app

# 应用名称全局变量(方便修改)
ENV APP_NAME=mysteel-standard-database-web.jar

# 复制应用 jar 包
COPY ${APP_NAME} /app/${APP_NAME}

# 设置容器时区
ENV TZ=Asia/Shanghai

ENTRYPOINT java -jar /app/${APP_NAME}

注意 :Dockerfile 中不需要设置应用配置相关的环境变量,这些变量在运行时通过 docker run 命令传递。

2. Docker Run 命令传递环境变量

方式一:直接使用 -e 参数
bash 复制代码
docker run -d \
    --name data-prod \
    -p 8097:8097 \
    -e DB_HOST=192.168.173.9 \
    -e DB_PORT=5236 \
    -e DB_NAME=YANGCAI_PROD \
    -e DB_SCHEMA=YANGCAI_PROD \
    -e DB_USERNAME=prod_user \
    -e DB_PASSWORD=prod_password \
    -e REDIS_HOST=192.168.0.5 \
    -e REDIS_PORT=6379 \
    -e REDIS_PASSWORD=redis_prod_password \
    -e ES_URIS=172.18.10.31:9200 \
    -e ES_USERNAME=elastic \
    -e ES_PASSWORD=es_prod_password \
    -e ZOOKEEPER_ADDRESSES=zk1.prod.local:2181,zk2.prod.local:2181 \
    -e XXL_JOB_ADMIN_ADDRESSES=http://172.18.10.14:8080/xxl-job-admin \
    your-image:tag
方式二:使用环境变量文件 --env-file

创建环境变量文件 prod.env

bash 复制代码
# prod.env
DB_HOST=192.168.173.9
DB_PORT=5236
DB_NAME=YANGCAI_PROD
DB_SCHEMA=YANGCAI_PROD
DB_USERNAME=prod_user
DB_PASSWORD=prod_password
REDIS_HOST=192.168.0.5
REDIS_PORT=6379
REDIS_PASSWORD=redis_prod_password
ES_URIS=172.18.10.31:9200
ES_USERNAME=elastic
ES_PASSWORD=es_prod_password
ZOOKEEPER_ADDRESSES=zk1.prod.local:2181,zk2.prod.local:2181
XXL_JOB_ADMIN_ADDRESSES=http://172.18.10.14:8080/xxl-job-admin

使用环境变量文件启动:

bash 复制代码
docker run -d \
    --name data-prod \
    -p 8097:8097 \
    --env-file prod.env \
    your-image:tag
方式三:使用启动脚本

创建一个启动脚本 start-docker.sh

bash 复制代码
#!/bin/bash
# ============================================
# Spring Boot Docker 容器启动脚本
# ============================================

echo "======================================"
echo "  Docker 容器启动脚本"
echo "======================================"
echo ""

# 提示输入镜像名称
read -p "请输入镜像名称或ID: " IMAGE_NAME

# 设置默认值
if [ -z "$IMAGE_NAME" ]; then
    IMAGE_NAME="springboot-app:prod"
    echo "使用默认镜像: $IMAGE_NAME"
fi

# 固定容器名称
CONTAINER_NAME="data-prod"

# 数据库配置(可修改默认值)
DB_HOST=${DB_HOST:-"192.168.173.8"}
DB_PORT=${DB_PORT:-"5236"}
DB_NAME=${DB_NAME:-"YANGCAI_INIT"}
DB_SCHEMA=${DB_SCHEMA:-"YANGCAI_INIT"}
DB_USERNAME=${DB_USERNAME:-"SYSDBA"}
DB_PASSWORD=${DB_PASSWORD:-"SYSDBA"}

# Redis 配置
REDIS_HOST=${REDIS_HOST:-"192.168.0.4"}
REDIS_PORT=${REDIS_PORT:-"6379"}
REDIS_PASSWORD=${REDIS_PASSWORD:-"nm@eloL!FFmmY5"}

# Elasticsearch 配置
ES_URIS=${ES_URIS:-"172.18.10.30:9200"}
ES_USERNAME=${ES_USERNAME:-"elastic"}
ES_PASSWORD=${ES_PASSWORD:-"hO8eJ3mS5b"}

# ZooKeeper 配置
ZOOKEEPER_ADDRESSES=${ZOOKEEPER_ADDRESSES:-"dubbo1.mysteel.local:2181?backup=dubbo2.mysteel.local:2182,dubbo3.mysteel.local:2183,dubbo4.mysteel.local:2184,dubbo5.mysteel.local:2185"}

# XXL-Job 配置
XXL_JOB_ADMIN_ADDRESSES=${XXL_JOB_ADMIN_ADDRESSES:-"http://172.18.10.13:8080/xxl-job-admin"}

# 应用端口
APP_PORT=${APP_PORT:-"8097"}

echo ""
echo "======================================"
echo "  配置信息"
echo "======================================"
echo "  镜像: $IMAGE_NAME"
echo "  容器名: $CONTAINER_NAME"
echo "  应用端口: $APP_PORT"
echo "  数据库: $DB_HOST:$DB_PORT/$DB_NAME"
echo "  用户名: $DB_USERNAME"
echo "  Redis: $REDIS_HOST:$REDIS_PORT"
echo "  Elasticsearch: $ES_URIS"
echo ""

# 确认是否继续
read -p "是否启动容器? (y/n): " CONFIRM

if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
    echo "已取消操作"
    exit 0
fi

echo ""
echo "清理旧容器..."
docker stop $CONTAINER_NAME 2>/dev/null
docker rm $CONTAINER_NAME 2>/dev/null

echo "启动容器中..."
docker run -d \
    --name $CONTAINER_NAME \
    -p ${APP_PORT}:8097 \
    --add-host=localhost:host-gateway \
    -e DB_HOST=$DB_HOST \
    -e DB_PORT=$DB_PORT \
    -e DB_NAME=$DB_NAME \
    -e DB_SCHEMA=$DB_SCHEMA \
    -e DB_USERNAME=$DB_USERNAME \
    -e DB_PASSWORD=$DB_PASSWORD \
    -e REDIS_HOST=$REDIS_HOST \
    -e REDIS_PORT=$REDIS_PORT \
    -e REDIS_PASSWORD=$REDIS_PASSWORD \
    -e ES_URIS=$ES_URIS \
    -e ES_USERNAME=$ES_USERNAME \
    -e ES_PASSWORD=$ES_PASSWORD \
    -e ZOOKEEPER_ADDRESSES=$ZOOKEEPER_ADDRESSES \
    -e XXL_JOB_ADMIN_ADDRESSES=$XXL_JOB_ADMIN_ADDRESSES \
    $IMAGE_NAME

if [ $? -eq 0 ]; then
    echo ""
    echo "======================================"
    echo "  容器启动成功!"
    echo "======================================"
    echo ""
    echo "访问地址: http://localhost:$APP_PORT"
    echo ""
    echo "常用命令:"
    echo "  查看日志: docker logs -f $CONTAINER_NAME"
    echo "  进入容器: docker exec -it $CONTAINER_NAME bash"
    echo "  停止容器: docker stop $CONTAINER_NAME"
    echo "  删除容器: docker rm $CONTAINER_NAME"
else
    echo ""
    echo "错误: 容器启动失败!"
    echo "请检查镜像名称是否正确"
fi

echo ""

使用脚本启动:

bash 复制代码
# 方式1:使用默认值
./start-docker.sh

# 方式2:通过环境变量覆盖默认值
DB_HOST=192.168.173.9 DB_PASSWORD=prod_password ./start-docker.sh

最佳实践

1. 配置分类

  • 必须参数化:数据库连接、Redis、消息队列、注册中心等中间件配置
  • 建议参数化:日志级别、功能开关、超时时间等可调优参数
  • 可以硬编码:应用内部业务逻辑配置、固定路径等

2. 安全性建议

  • 敏感信息必须参数化:密码、密钥等不应出现在配置文件中
  • 使用默认值:为环境变量提供合理的默认值,方便本地开发
  • 环境变量文件权限.env 文件应设置适当的文件权限(如 chmod 600
  • 不要提交敏感信息.env 文件应加入 .gitignore

3. 命名规范

  • 使用大写字母和下划线:DB_HOSTREDIS_PASSWORD
  • 使用有意义的名称:避免使用 VAR1VAR2 等无意义名称
  • 保持一致性:同一类型的配置使用统一的前缀,如 DB_*REDIS_*

4. 文档化

为每个环境变量编写文档说明:

properties 复制代码
# 数据库配置
# DB_HOST: 数据库服务器地址(默认: 192.168.173.8)
# DB_PORT: 数据库端口(默认: 5236)
# DB_NAME: 数据库名称(默认: YANGCAI_INIT)
spring.datasource.multi.url=jdbc:dm://${DB_HOST:192.168.173.8}:${DB_PORT:5236}/${DB_NAME:YANGCAI_INIT}?schema=${DB_SCHEMA:YANGCAI_INIT}

验证配置

1. 查看容器环境变量

bash 复制代码
# 查看容器的所有环境变量
docker exec data-prod env

# 查看特定环境变量
docker exec data-prod env | grep DB_HOST

2. 查看应用日志

bash 复制代码
# 实时查看日志
docker logs -f data-prod

# 查看最近的日志
docker logs --tail 100 data-prod

3. 进入容器检查

bash 复制代码
# 进入容器
docker exec -it data-prod bash

# 查看环境变量
echo $DB_HOST
echo $REDIS_HOST

常见问题

Q1: 环境变量没有生效?

A: 检查以下几点:

  1. 环境变量名称是否正确(区分大小写)
  2. docker run 命令中是否正确使用 -e 参数
  3. Spring Boot 配置文件中语法是否正确:${VAR_NAME:default_value}
  4. 应用是否重启以加载新配置

Q2: 如何为不同环境设置不同的配置?

A: 可以创建多个环境变量文件:

  • dev.env - 开发环境
  • test.env - 测试环境
  • prod.env - 生产环境

启动时指定对应的文件:

bash 复制代码
docker run -d --env-file prod.env your-image:tag

Q3: 配置项太多,命令太长怎么办?

A : 使用 --env-file 参数,将所有环境变量放在文件中管理。

Q4: 如何在 Docker Compose 中使用?

A : 在 docker-compose.yml 中使用 environmentenv_file

yaml 复制代码
version: '3.8'
services:
  app:
    image: your-image:tag
    ports:
      - "8097:8097"
    environment:
      - DB_HOST=192.168.173.9
      - DB_PORT=5236
      - DB_NAME=YANGCAI_PROD
    # 或者使用 env_file
    env_file:
      - prod.env

总结

通过 Spring Boot 的配置参数化机制结合 Docker 环境变量传递,我们可以实现:

  1. 配置与代码分离:配置不进入镜像,提高安全性
  2. 一次构建,多处部署:同一个镜像可以在不同环境使用
  3. 运维友好:无需重新构建即可调整配置
  4. 符合最佳实践:遵循 12-Factor App 原则

这种方式特别适合微服务架构和容器化部署场景,能够显著提高应用的灵活性和可维护性。

参考资料

相关推荐
杨杨杨大侠2 小时前
DeepAgents 框架深度解析:从理论到实践的智能代理架构
后端·python·llm
雪人.2 小时前
Spring常见面试题(2026版30道面试题)
java·后端·spring
林鸿风采2 小时前
在Alpine Linux上部署docker,并配置开机自启
linux·docker·eureka·alpine
阿祖zu2 小时前
2025 AI 总结:技术研发的技能升维与职业路径系统重构的思考
前端·后端·ai编程
江湖有缘2 小时前
Docker快速部署NeonLink:打造你的私人书签管理平台
运维·docker·容器
IT_陈寒2 小时前
Vite 5分钟性能优化实战:从3秒到300ms的冷启动提速技巧(附可复用配置)
前端·人工智能·后端
心在飞扬2 小时前
langchain学习总结-Embedding 学习总结
后端
羊小猪~~2 小时前
【QT】-- QT基础类
开发语言·c++·后端·stm32·单片机·qt
间彧2 小时前
docker中如何使用Arthas诊断工具
docker