18 KiB
生产环境配置管理方案 - 纯环境变量方案
日期: 2025-01-10 版本: v1.0 适用场景: Docker部署环境下修改API接口配置,无需重新打包jar
📋 需求背景
当前生产环境使用Docker部署方式,每次修改 application-prod.yml 都需要重新打包jar包,流程繁琐。
期望: 只修改配置文件,重启应用即可生效,无需重新打包。
🎯 解决方案:纯环境变量方案
方案特点
| 特性 | 说明 |
|---|---|
| ✅ 无需重新打包 | 只修改 .env 文件 |
| ✅ 修改简单 | 纯文本编辑 |
| ✅ 回滚容易 | 备份 .env 文件即可 |
| ✅ 版本控制 | 可保存多个环境的 .env |
| ✅ 安全性 | 敏感信息不打包到jar |
| ✅ 环境隔离 | 开发/测试/生产用不同 .env |
工作原理
Spring Boot 支持使用环境变量覆盖配置文件中的值:
# application-prod.yml 中定义
data:
collector:
airport-api:
base-url: ${AIRPORT_API_BASE_URL:http://localhost:8090}
# ↑环境变量名 ↑默认值(环境变量不存在时使用)
当启动应用时,如果环境变量 AIRPORT_API_BASE_URL 存在,则使用环境变量的值;否则使用默认值。
🔧 实施步骤
Step 1: 修改 application-prod.yml(一次性修改)
文件位置: qaup-admin/src/main/resources/application-prod.yml
修改内容:
# 数据采集配置
data:
collector:
# 数据采集间隔(可选配置)
interval: ${DATA_COLLECTOR_INTERVAL:250}
detection:
# 检测间隔(可选配置)
interval: ${DATA_DETECTION_INTERVAL:1000}
# 机场数据源配置
airport-api:
# API基础URL(环境变量覆盖)
base-url: ${AIRPORT_API_BASE_URL:http://localhost:8090}
endpoints:
login: /login
refresh: /userInfoController/refreshToken
aircraft: /openApi/getCurrentFlightPositions
vehicle: /openApi/getCurrentVehiclePositions
arrival-route: /runwayPathPlanningController/findArrTaxiwayByRunwayAndContactCrossAndSeat
departure-route: /runwayPathPlanningController/findDepTaxiwayByRunwayAndContactCrossAndSeat
aircraft-status: /aircraftStatusController/getAircraftStatus
flight-notification: /openApi/getInboundAndOutboundFlightsNotification
# 认证信息(环境变量覆盖)
auth:
username: ${AIRPORT_API_USERNAME:dianxin}
password: ${AIRPORT_API_PASSWORD:dianxin@123}
# 无人车厂商数据源配置
vehicle-api:
# API基础URL(环境变量覆盖)
base-url: ${VEHICLE_API_BASE_URL:http://localhost:8091}
endpoints:
vehicle-command: /api/VehicleCommandInfo
universal-status: /api/v1/vehicles/{vehicleId}/status
# 超时和重试配置(可选)
timeout: ${VEHICLE_API_TIMEOUT:1000}
retry-attempts: ${VEHICLE_API_RETRY:3}
# 无人车数据持久化配置
unmanned-vehicle:
persistence:
enabled: true
batch-size: 50
location-retention-days: 90
command-retention-days: 365
command:
timeout: 1000
retry-attempts: 3
validation:
enabled: true
strict-mode: false
retention:
redis-expire-seconds: 60
postgresql-days: 30
修改完成后: 重新打包一次jar包(这是最后一次打包)
cd qaup-admin
mvn clean package -DskipTests
Step 2: 修改启动脚本 qaup.sh
文件位置: 项目根目录 qaup.sh
完整内容:
#!/bin/sh
# ./qaup.sh start 启动 stop 停止 restart 重启 status 状态
AppName=qaup-admin.jar
# JVM参数
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
APP_HOME=`pwd`
LOG_PATH=$APP_HOME/logs/$AppName.log
ENV_FILE=$APP_HOME/.env
if [ "$1" = "" ];
then
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
exit 1
fi
if [ "$AppName" = "" ];
then
echo -e "\033[0;31m 未输入应用名 \033[0m"
exit 1
fi
function start()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
if [ x"$PID" != x"" ]; then
echo "$AppName is running..."
else
# ========== 新增:加载环境变量 ==========
if [ -f "$ENV_FILE" ]; then
echo "Loading environment variables from $ENV_FILE"
# 导出环境变量,忽略注释和空行
export $(cat $ENV_FILE | grep -v '^#' | grep -v '^$' | xargs)
echo "Environment variables loaded successfully"
else
echo "Warning: $ENV_FILE not found, using default configuration"
fi
# ========================================
nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &
echo "Start $AppName success..."
fi
}
function stop()
{
echo "Stop $AppName"
PID=""
query(){
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
}
query
if [ x"$PID" != x"" ]; then
kill -TERM $PID
echo "$AppName (pid:$PID) exiting..."
while [ x"$PID" != x"" ]
do
sleep 1
query
done
echo "$AppName exited."
else
echo "$AppName already stopped."
fi
}
function restart()
{
stop
sleep 2
start
}
function status()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
if [ $PID != 0 ];then
echo "$AppName is running..."
else
echo "$AppName is not running..."
fi
}
case $1 in
start)
start;;
stop)
stop;;
restart)
restart;;
status)
status;;
*)
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
esac
主要改动:
- 新增
ENV_FILE变量指向.env文件 - 在
start()函数中加载环境变量 - 添加了提示信息
Step 3: 创建环境变量配置文件 .env
文件位置: jar包所在目录(与 qaup.sh 同级)
文件内容:
# ============================================================
# QAUP 生产环境配置
# 环境变量配置文件
# 修改此文件后,执行 ./qaup.sh restart 即可生效
# ============================================================
# ========== 机场数据API配置 ==========
# 机场数据接口基础URL
AIRPORT_API_BASE_URL=http://192.168.1.100:8090
# 机场API认证信息
AIRPORT_API_USERNAME=dianxin
AIRPORT_API_PASSWORD=dianxin@123
# ========== 无人车厂商API配置 ==========
# 无人车厂商接口基础URL
VEHICLE_API_BASE_URL=http://192.168.1.101:8091
# 无人车API超时和重试配置(可选,单位:毫秒)
VEHICLE_API_TIMEOUT=1000
VEHICLE_API_RETRY=3
# ========== 数据采集配置(可选)==========
# 数据采集间隔(单位:毫秒)
DATA_COLLECTOR_INTERVAL=250
# 检测和推送间隔(单位:毫秒)
DATA_DETECTION_INTERVAL=1000
# ============================================================
# 注意事项:
# 1. 等号两边不要有空格
# 2. 字符串值不需要引号
# 3. #开头的行为注释
# 4. 修改后执行 ./qaup.sh restart 使配置生效
# ============================================================
设置文件权限(推荐<EFBFBD><EFBFBD>:
# 只有owner可读写,防止密码泄露
chmod 600 .env
📁 部署目录结构
/app/ # 应用部署目录
├── qaup-admin.jar # 应用jar包
├── qaup.sh # 启动脚本(已修改)
├── .env # 环境变量配置文件(新增)
├── logs/ # 日志目录
│ └── qaup-admin.jar.log
└── config/ # 可选:外部配置目录
└── .env.backup-* # 配置备份文件
🚀 日常使用流程
1. 修改API配置
# 编辑环境变量文件
vim .env
# 修改内容示例:
AIRPORT_API_BASE_URL=http://新服务器IP:8090
AIRPORT_API_USERNAME=新用户名
AIRPORT_API_PASSWORD=新密码
VEHICLE_API_BASE_URL=http://新服务器IP:8091
# 保存并退出
:wq
2. 重启应用使配置生效
./qaup.sh restart
输出示例:
Stop qaup-admin.jar
qaup-admin.jar (pid:12345) exiting...
qaup-admin.jar exited.
Loading environment variables from /app/.env
Environment variables loaded successfully
Start qaup-admin.jar success...
3. 验证配置是否生效
方法1: 查看日志
tail -f logs/qaup-admin.jar.log
查找包含 base-url 或 API调用相关的日志,确认使用的是新地址。
方法2: 查看环境变量(启动前测试)
# 加载环境变量
export $(cat .env | grep -v '^#' | grep -v '^$' | xargs)
# 查看变量值
echo $AIRPORT_API_BASE_URL
echo $VEHICLE_API_BASE_URL
方法3: 使用管理端点(如果开启)
curl http://localhost:8080/actuator/env | grep AIRPORT_API
🔄 配置管理最佳实践
1. 备份配置
每次修改前备份:
# 备份到config目录
mkdir -p config
cp .env config/.env.backup-$(date +%Y%m%d-%H%M%S)
# 查看备份列表
ls -lh config/.env.backup-*
示例:
config/.env.backup-20250110-093000
config/.env.backup-20250110-143000
config/.env.backup-20250110-170000
2. 回滚配置
# 查看可用备份
ls config/.env.backup-*
# 恢复指定备份
cp config/.env.backup-20250110-093000 .env
# 重启应用
./qaup.sh restart
3. 多环境配置管理
准备不同环境的配置文件:
/app/config/
├── .env.dev # 开发环境配置
├── .env.test # 测试环境配置
├── .env.prod # 生产环境配置
└── .env.dr # 容灾环境配置
切换环境:
# 切换到测试环境
cp config/.env.test .env
./qaup.sh restart
# 切换到生产环境
cp config/.env.prod .env
./qaup.sh restart
4. 配置差异对比
# 对比当前配置和备份配置
diff .env config/.env.backup-20250110-093000
# 对比不同环境配置
diff config/.env.prod config/.env.test
🔒 安全建议
1. 文件权限控制
# .env 文件只允许owner读写
chmod 600 .env
# qaup.sh 可执行
chmod 755 qaup.sh
# jar包只读
chmod 444 qaup-admin.jar
2. Git版本控制
如果使用Git管理部署脚本,务必排除敏感文件:
# 创建 .gitignore
cat > .gitignore << EOF
# 敏感配置文件
.env
.env.*
# 日志文件
logs/
*.log
# jar包(通过CI/CD部署)
*.jar
# 临时文件
*.tmp
*.swp
EOF
可以提交的文件:
qaup.sh- 启动脚本.env.example- 配置模板(不含真实密码)
示例配置模板 (.env.example):
# ========== 机场数据API配置 ==========
AIRPORT_API_BASE_URL=http://your-airport-api-server:8090
AIRPORT_API_USERNAME=your-username
AIRPORT_API_PASSWORD=your-password
# ========== 无人车厂商API配置 ==========
VEHICLE_API_BASE_URL=http://your-vehicle-api-server:8091
VEHICLE_API_TIMEOUT=1000
VEHICLE_API_RETRY=3
# ========== 数据采集配置 ==========
DATA_COLLECTOR_INTERVAL=250
DATA_DETECTION_INTERVAL=1000
3. 密码管理建议
- 使用强密码
- 定期更换密码
- 不同环境使用不同密码
- 使用密钥管理工具(如 Vault、AWS Secrets Manager)
📋 完整环境变量列表
必需环境变量
| 环境变量名 | 描述 | 默认值 | 示例 |
|---|---|---|---|
| AIRPORT_API_BASE_URL | 机场数据API基础URL | http://localhost:8090 | http://192.168.1.100:8090 |
| AIRPORT_API_USERNAME | 机场API用户名 | dianxin | dianxin |
| AIRPORT_API_PASSWORD | 机场API密码 | dianxin@123 | SecurePass123 |
| VEHICLE_API_BASE_URL | 无人车API基础URL | http://localhost:8091 | http://192.168.1.101:8091 |
可选环境变量
| 环境变量名 | 描述 | 默认值 | 示例 |
|---|---|---|---|
| VEHICLE_API_TIMEOUT | 无人车API超时时间(毫秒) | 1000 | 2000 |
| VEHICLE_API_RETRY | 无人车API重试次数 | 3 | 5 |
| DATA_COLLECTOR_INTERVAL | 数据采集间隔(毫秒) | 250 | 500 |
| DATA_DETECTION_INTERVAL | 检测间隔(毫秒) | 1000 | 1500 |
扩展环境变量(如果需要)
如果未来需要更多配置通过环境变量控制,可以继续扩展:
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=qaup
DB_USERNAME=postgres
DB_PASSWORD=123456
# Redis配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# 日志级别
LOG_LEVEL_QAUP=info
LOG_LEVEL_SPRING=warn
🧪 测试验证
1. 本地测试
# 1. 创建测试配置
cat > .env.test << EOF
AIRPORT_API_BASE_URL=http://test-airport:8090
AIRPORT_API_USERNAME=test-user
AIRPORT_API_PASSWORD=test-pass
VEHICLE_API_BASE_URL=http://test-vehicle:8091
EOF
# 2. 使用测试配置
cp .env.test .env
# 3. 启动应用
./qaup.sh start
# 4. 查看日志验证
tail -f logs/qaup-admin.jar.log | grep -E "airport|vehicle"
2. 配置验证脚本
创建验证脚本 verify-config.sh:
#!/bin/bash
# 配置验证脚本
echo "========== 环境变量配置验证 =========="
if [ ! -f .env ]; then
echo "❌ .env 文件不存在"
exit 1
fi
echo "✅ .env 文件存在"
# 加载环境变量
export $(cat .env | grep -v '^#' | grep -v '^$' | xargs)
# 验证必需变量
REQUIRED_VARS=(
"AIRPORT_API_BASE_URL"
"AIRPORT_API_USERNAME"
"AIRPORT_API_PASSWORD"
"VEHICLE_API_BASE_URL"
)
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var}" ]; then
echo "❌ 缺少必需环境变量: $var"
exit 1
else
echo "✅ $var = ${!var}"
fi
done
echo "========== 验证通过 =========="
使用:
chmod +x verify-config.sh
./verify-config.sh
🔧 故障排查
问题1: 环境变量未生效
症状: 修改了 .env 但应用仍使用旧配置
排查:
# 1. 确认 .env 文件格式正确(无空格、无引号)
cat .env
# 2. 手动测试环境变量加载
export $(cat .env | grep -v '^#' | grep -v '^$' | xargs)
echo $AIRPORT_API_BASE_URL
# 3. 确认应用已重启
./qaup.sh status
ps -ef | grep qaup-admin.jar
# 4. 查看启动日志
tail -100 logs/qaup-admin.jar.log
解决: 确保执行了 ./qaup.sh restart
问题2: .env 文件格式错误
常见错误:
# ❌ 错误:等号两边有空格
AIRPORT_API_BASE_URL = http://localhost:8090
# ❌ 错误:值使用了引号
AIRPORT_API_BASE_URL="http://localhost:8090"
# ❌ 错误:多余的导出语句
export AIRPORT_API_BASE_URL=http://localhost:8090
# ✅ 正确
AIRPORT_API_BASE_URL=http://localhost:8090
问题3: 权限问题
症状: 无法读取 .env 文件
# 检查文件权限
ls -l .env
# 修复权限
chmod 600 .env
chown app-user:app-group .env
📊 方案对比
与其他方案的对比
| <EFBFBD><EFBFBD>性 | 环境变量方案 | 外部配置文件 | 配置中心 |
|---|---|---|---|
| 修改便捷性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 无需重新打包 | ✅ | ✅ | ✅ |
| 是否需要重启 | ✅ 需要 | ✅ 需要 | ❌ 不需要 |
| 实施复杂度 | 简单 | 简单 | 中等 |
| 适用场景 | 生产环境 | 生产环境 | 企业级/微服务 |
| 成本 | 无 | 无 | 需要额外服务 |
🎯 总结
优点
- ✅ 无需重新打包jar - 修改
.env即可 - ✅ 修改简单直观 - 纯文本编辑
- ✅ 回滚容易 - 备份/恢复
.env文件 - ✅ 版本控制友好 - 可管理多环境配置
- ✅ 安全性好 - 敏感信息不打包到jar
- ✅ 环境隔离 - 不同环境使用不同配置
- ✅ 零成本 - 无需额外组件
适用场景
- ✅ Docker部署环境
- ✅ 多环境部署(开发/测试/生产)
- ✅ 配置项以API地址、认证信息为主
- ✅ 配置变更频率不高(月度/季度级别)
不适用场景
- ❌ 需要实时配置生效(无法重启)
- ❌ 配置项非常多且复杂
- ❌ 微服务架构(建议使用配置中心)
🔄 后续优化方向
短期优化
- 配置校验: 启动前校验配置格式和必需项
- 配置加密: 敏感信息使用加密存储
- 配置模板: 提供不同场景的配置模板
长期规划
如果项目规模扩大、配置项增多,建议引入配置中心(Nacos/Apollo):
- 配置实时生效
- 版本管理和灰度发布
- 统一管理多服务配置
- 配置变更审计
📚 参考资料
Spring Boot 配置文档
配置优先级
Spring Boot 配置加载优先级(从高到低):
- 命令行参数
- 操作系统环境变量 ⭐ 本方案使用
application-{profile}.properties/yml(外部)application-{profile}.properties/yml(jar内)application.properties/yml(外部)application.properties/yml(jar内)
📞 支持与维护
常见问题
如遇到问题,请检查:
.env文件格式是否正确- 是否执行了
./qaup.sh restart - 启动日志是否有错误信息
- 文件权限是否正确
配置变更记录
建议维护配置变更日志:
# 创建变更记录文件
cat > config/CHANGELOG.md << EOF
# 配置变更记录
## 2025-01-10 14:00
- 修改机场API地址: http://old:8090 -> http://new:8090
- 操作人: 张三
- 原因: 服务器迁移
## 2025-01-09 10:00
- 初始化生产环境配置
- 操作人: 李四
EOF
文档结束
最后更新: 2025-01-10 文档版本: v1.0 维护者: QAUP Team