Docker的内部DNS: 不暴露应用端口的Nacos服务注册实现方案
·
使用docker-compose 注册服务到 Nacos,同时保证应用服务本身端口不暴露,是完全可行且推荐的最佳实践。
核心思路是:利用 Docker 的内部 DNS,让服务通过容器名在内部网络中进行通信。Nacos 注册的是容器名和内部端口,而不是宿主机的 IP 和端口。
最佳实践方案
假设我们有一个 user-service 应用,运行在容器内的 8080 端口,我们需要将它注册到 Nacos,但不对宿主机暴露。
1. 关键的 Docker Compose 配置
docker-compose.yml
version: '3.8'
services:
# Nacos Server - 不对外暴露
nacos:
image: nacos/nacos-server:v2.2.0
container_name: nacos-server
environment:
- MODE=standalone
- NACOS_AUTH_ENABLE=true
networks:
- microservice-net
# 注意:没有 ports 映射,Nacos 管理界面也无法从外部访问
# 如果需要临时管理,可以按下面说明添加 127.0.0.1 绑定
# 你的业务应用 - 绝不暴露端口!
user-service:
build: ./user-service
container_name: user-service
environment:
# 关键配置:告诉Spring Cloud应用如何连接Nacos
- SPRING_CLOUD_NACOS_SERVER-ADDR=nacos:8848 # 使用容器名'nacos'
- SPRING_CLOUD_NACOS_DISCOVERY_IP=user-service # 强制注册的IP为容器名
- SPRING_CLOUD_NACOS_DISCOVERY_PORT=8080 # 注册容器内的端口
networks:
- microservice-net
# 关键:没有 ports 映射,外部无法直接访问
depends_on:
- nacos
# API网关 - 它是唯一的入口,可以暴露
api-gateway:
build: ./api-gateway
container_name: api-gateway
ports:
- "80:8080" # 唯一暴露的端口
environment:
- SPRING_CLOUD_NACOS_SERVER-ADDR=nacos:8848
networks:
- microservice-net
depends_on:
- nacos
- user-service
networks:
microservice-net:
driver: bridge
2. 关键的应用配置(Spring Cloud Application)
在你的 user-service 的 application.yml 或 bootstrap.yml 中,进行如下关键配置:
spring:
application:
name: user-service # 服务名
cloud:
nacos:
discovery:
server-addr: ${SPRING_CLOUD_NACOS_SERVER-ADDR:nacos:8848} # 从环境变量读取,默认用容器名
ip: ${SPRING_CLOUD_NACOS_DISCOVERY_IP:} # 强制指定注册的IP地址
port: ${SPRING_CLOUD_NACOS_DISCOVERY_PORT:8080} # 强制指定注册的端口
# 以下是关键中的关键!
register-enabled: true # 允许注册
enabled: true # 开启服务发现
# 确保不使用主机名和外部IP
prefer-ip-address: false # 非常重要!设为false,否则会尝试注册宿主机IP
环境变量的作用:
SPRING_CLOUD_NACOS_DISCOVERY_IP=user-service:这强制 Spring Cloud 向 Nacos 注册时,使用的 IP 地址是容器名user-service。这样,其他服务(如网关)从 Nacos 获取到的实例地址就是http://user-service:8080,这个地址在 Docker 内部网络中是可以通过 DNS 解析的。SPRING_CLOUD_NACOS_DISCOVERY_PORT=8080:确保注册的是容器内部的实际端口。
3. 工作原理流程图

- 注册:
user-service启动后,通过环境变量配置,向nacos:8848注册自己,注册的地址是容器名user-service和内部端口8080。 - 发现:
api-gateway也连接到nacos:8848,查询名为user-service的实例列表。 - 获取地址:Nacos 返回实例地址:
user-service:8080。 - 内部路由:
api-gateway直接向http://user-service:8080发起请求。Docker 的网络 DNS 会自动将容器名user-service解析为其在内部网络中的 IP 地址,通信成功。
4. 如何验证和管理?
问题: Nacos 本身没暴露端口,如何查看服务注册情况?
解决方案: 有以下几种安全的方式:
-
临时暴露 Nacos UI(仅用于调试)
修改nacos服务的配置,添加仅绑定到本地回环的端口映射:nacos: image: nacos/nacos-server:v2.2.0 ports: - "127.0.0.1:8848:8848" # 仅宿主机可通过 localhost:8848 访问 # ... 其他配置不变然后你可以在宿主机上通过
http://localhost:8848/nacos访问控制台。生产环境中应移除此映射。 -
使用命令行工具进入容器内部查看
# 进入nacos容器执行命令 docker compose exec nacos curl http://localhost:8848/nacos/v1/ns/service/list # 进入网关容器测试是否能解析user-service docker compose exec api-gateway ping user-service docker compose exec api-gateway curl http://user-service:8080/actuator/health -
通过已暴露的网关进行间接验证
如果你的网关有健康检查接口,可以通过访问网关来间接验证整个链路是否通畅。curl http://localhost:80/actuator/gateway/routes # 查看网关路由信息 curl http://localhost:80/user/api/v1/hello # 测试通过网关访问user-service
结论
要保证注册到 Nacos 的应用不暴露端口,只需做到以下几点:
- 不在 Compose 文件中为业务服务配置
ports。 - 通过环境变量
SPRING_CLOUD_NACOS_DISCOVERY_IP强制指定注册的 host 为容器名。 - 确保
spring.cloud.nacos.discovery.prefer-ip-address=false,防止注册宿主机IP。 - 所有服务(Nacos、应用、网关)连接到同一个自定义 Docker 网络。
- 让 API 网关作为唯一的对外入口。
更多推荐


所有评论(0)