架构进阶:从 Docker 环境变量到 Nacos 统一配置中心实战
摘要:在上篇文章中(从“裸奔”到“装甲”:基于 Docker + Spring Boot 的企业级多环境安全架构实战),我们实现了 Spring Boot 配置的“外部化”。但在微服务架构下,分散在各个服务器上的
.env文件依然难以维护。本文将带你完成从“静态环境变量”到“动态配置中心”的跃迁,使用 Nacos 统一管理所有环境配置,并实现配置热更新。
前言:当.env文件不再够用时
在上一个方案中,我们通过 Docker 的env_file注入了.env文件。这在单体应用中非常完美,但当面临以下场景时,它会显得力不从心:
配置散落:10 个服务就有 10 个
.env文件,分布在 10 台服务器上。重启代价:修改一个 Redis 地址,必须
docker restart。无版本管理:谁改了配置?什么时候改的?回滚怎么办?
安全性焦虑:虽然没进 Git,但运维手里还是握着一堆密码。
Nacos 的出现就是为了解决这些问题。它不仅是注册中心,更是配置中心。
第一章:新架构全景图
我们先来看一下引入 Nacos 后的架构变化。
1.1 架构对比
维度 | Docker Env 方案 | Nacos 方案 |
|---|---|---|
存储位置 | 服务器文件 (.env) | Nacos Server 数据库 |
更新机制 | 重启容器 | 实时推送 / 热更新 |
管理方式 | 分散管理 | 统一 Web 控制台 |
版本控制 | 无 | 自带历史版本与回滚 |
适用场景 | 单体应用 | 微服务 / 分布式 |
1.2 数据流
+-------------------+ 推送配置 +-------------------+ | Nacos Console | -----------> | Nacos Server | +-------------------+ +---------+---------+ | | 监听变更 (Long Polling) v +-------------------+ | Spring Boot App | | (Nacos Config Client)| +-------------------+第二章:Nacos 环境准备
2.1 使用 1Panel 快速部署 Nacos
如果你在用 1Panel,部署 Nacos 非常简单。
进入应用商店 -> 搜索Nacos。
选择单机模式(Standalone)。
设置端口映射(例如
8848)。启动。
2.2 初始化命名空间 (Namespace)
为了区分环境,我们在 Nacos 中创建命名空间。
Namespace ID | Name | 说明 |
|---|---|---|
| 开发环境 | 开发同学使用 |
| 测试环境 | 测试同学使用 |
| 生产环境 | 线上环境 |
第三章:Spring Boot 接入 Nacos
这是最核心的代码改造环节。
3.1 依赖变更 (pom.xml)
移除或保留原有的 Spring Cloud Alibaba 依赖。
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>3.2 配置文件大挪移
我们要把原来写在application-dev.yml里的东西,搬到 Nacos 里。
本地只保留一个bootstrap.yml(优先级最高,用于连接 Nacos)。
# bootstrap.yml spring: application: name: shiyuan-admin cloud: nacos: discovery: server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} config: server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} file-extension: yaml # 关键:指定命名空间(dev/test/prod) namespace: ${NACOS_NAMESPACE:dev} # 配置分组 group: DEFAULT_GROUP # 支持动态刷新 refresh-enabled: true3.3 Nacos 中的配置内容
在 Nacos 控制台dev命名空间下,创建配置shiyuan-admin.yaml。
Data ID:shiyuan-admin.yaml
Group:DEFAULT_GROUP
配置内容(这就是你原来的application-dev.yml去掉占位符后的版本,但密码等敏感信息依然用占位符,或者直接用真实值放在 Nacos 里更安全):
spring: datasource: dynamic: datasource: master: url: jdbc:mysql://${DB_HOST}:3306/${DB_NAME}?useSSL=false username: ${DB_USERNAME} password: ${DB_PASSWORD} data: redis: host: ${REDIS_HOST} password: ${REDIS_PASSWORD} # 邮件 mail: pass: ${MAIL_PASS} # 短信 sms: blends: aliyun: access-key-id: ${SMS_ALI_ACCESS_KEY} access-key-secret: ${SMS_ALI_SECRET}注意:你会发现这里还是有${}。这是因为 Nacos 也支持从环境变量读取(推荐),或者你也可以直接在 Nacos 里写死值。
第四章:Docker 与 Nacos 的结合(关键)
现在,我们不再需要把大量的配置塞进.env,只需要告诉 Spring BootNacos 在哪里。
4.1 新的.env文件
.env文件变得非常精简,只负责“引导”应用。
# ================== 基础 ================== CONTAINER_NAME=shiyuan-admin CODE_DIR=/opt/apps/shiyuan-admin/target JAVA_APP_PORT=9113 # ================== Nacos 环境 ================== NACOS_SERVER_ADDR=172.17.0.1:8848 # Docker 网桥地址 NACOS_NAMESPACE=dev # ================== 敏感信息(仅作为兜底) ================== # 如果 Nacos 里的配置也用了变量,这里需要提供 DB_PASSWORD=YourStrongPassword REDIS_PASSWORD=RedisPass4.2 新的 docker-compose.yml
networks: 1panel-network: external: true services: java-app: container_name: ${CONTAINER_NAME} image: bitnami/java:17 command: bash /run.sh env_file: - .env # 只注入 Nacos 地址和少量敏感变量 environment: - TZ=Asia/Shanghai # 这里不再需要 SPRING_PROFILES_ACTIVE,由 Nacos Namespace 控制 networks: - 1panel-network ports: - ${HOST_IP}:${PANEL_APP_PORT_HTTP}:${JAVA_APP_PORT} restart: on-failure:5 volumes: - ${CODE_DIR}:/app - ./run.sh:/run.sh working_dir: /app4.3 改造 run.sh(支持 JVM 参数从 Nacos 读取)
虽然配置在 Nacos,但 JVM 参数通常还是在启动时确定。
#!/bin/bash set -e cd /app echo "==> Connecting to Nacos: $NACOS_SERVER_ADDR" echo "==> Namespace: $NACOS_NAMESPACE" exec java \ -Xms512m \ -Xmx1024m \ -XX:+UseG1GC \ -XX:+HeapDumpOnOutOfMemoryError \ -Dspring.cloud.nacos.config.namespace=${NACOS_NAMESPACE} \ -Dspring.cloud.nacos.server-addr=${NACOS_SERVER_ADDR} \ -jar shiyuan-admin.jar第五章:实现“配置热更新”(@RefreshScope)
这是 Nacos 最诱人的功能。
5.1 代码示例
假设你有一个读取 Redis 配置的 Bean:
@RestController @RequestMapping("/config") @RefreshScope // 核心注解:开启配置刷新 public class ConfigController { @Value("${spring.data.redis.host}") private String redisHost; @GetMapping("/redis-host") public String getRedisHost() { return "Current Redis Host: " + redisHost; } }5.2 操作流程
修改 Nacos 中
shiyuan-admin.yaml的spring.data.redis.host。点击发布。
无需重启应用,再次访问
/config/redis-host,发现值已经变了。
第六章:Nacos 鉴权与安全
Nacos 本身也需要安全加固。
6.1 开启鉴权
在 1Panel 部署 Nacos 时,务必开启鉴权(或手动修改application.properties):
nacos.core.auth.enabled=true nacos.core.auth.system.type=nacos6.2 配置 Docker 认证
如果 Nacos 开了鉴权,.env需要增加:
NACOS_USERNAME=nacos NACOS_PASSWORD=YourNacosPassword并在bootstrap.yml中配置:
spring: cloud: nacos: username: ${NACOS_USERNAME} password: ${NACOS_PASSWORD}第七章:迁移过程中的坑与解决方案
坑 1:配置加载顺序混乱
现象:本地配置覆盖了 Nacos 配置。
解决:记住 Spring Boot 配置优先级(从高到低):
Command Line Arguments (
--server.port=8081)JNDI attributes
Java System Properties (
-Dproperty=value)OS Environment Variables (Docker env)
Nacos Config
application-{profile}.ymlapplication.yml@PropertySource
经验:不要把同样的配置写在application.yml里,否则会覆盖 Nacos。
坑 2:Nacos 连不上
现象:java.net.ConnectException: Connection refused
解决:
检查
NACOS_SERVER_ADDR是否是 Docker 容器能访问到的地址。如果是 1Panel,
127.0.0.1可能不行,要用宿主机的局域网 IP 或 Docker 网桥 IP(如172.17.0.1)。
坑 3:配置回滚
操作:在 Nacos 控制台 -> 配置管理 -> 历史版本 -> 选择版本 -> 回滚。
第八章:最终的安全架构评估
经过这次改造,我们的安全等级再次提升。
资产 | 存放位置 | 安全性 |
|---|---|---|
代码 | Git | ⭐⭐⭐⭐⭐ (无密码) |
Jar 包 | Docker Image | ⭐⭐⭐⭐⭐ (无密码) |
引导配置 |
| ⭐⭐⭐⭐ (仅 Nacos 地址) |
业务配置 | Nacos Server | ⭐⭐⭐⭐⭐ (有权限控制、审计) |
数据库 | 内网 VPC | ⭐⭐⭐⭐⭐ |
结语
从最初的“密码满天飞”,到 Docker 环境变量隔离,再到 Nacos 统一配置中心,我们不仅解决了技术问题,更完成了一次工程思维的升级。
现在的架构优势在于:
运维友好:运维只管 Nacos,不用碰代码。
开发友好:开发只看 Git,不用管密码。
应急高效:改配置不用重启,秒级生效。
审计合规:谁改了什么,一清二楚。
如果你的项目正在从单体走向微服务,或者正在为配置管理头疼,强烈建议你试试这套方案。
