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 原则

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

参考资料

相关推荐
苦逼IT运维1 小时前
从 0 到 1 理解 Kubernetes:一次“破坏式”学习实践(一)
linux·学习·docker·容器·kubernetes
萧曵 丶1 小时前
Docker 面试题
运维·docker·容器
Charlie_lll2 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode
qq_12498707532 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
Chasmれ2 小时前
Spring Boot 1.x(基于Spring 4)中使用Java 8实现Token
java·spring boot·spring
汤姆yu2 小时前
2026基于springboot的在线招聘系统
java·spring boot·后端
为什么不问问神奇的海螺呢丶2 小时前
n9e categraf docker 监控配置
运维·docker·容器
青树寒鸦2 小时前
wsl的docker备份mongo和迁移
运维·mongodb·docker·容器
计算机学姐2 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法