Docker 服务去除 --net=host 的技术方案与实践总结
一、背景说明
在现有生产环境中,Java 服务以 Docker 容器形式运行,历史上为了避免端口和网络问题,统一采用了 --net=host 模式启动容器。该方式虽然简单直接,但存在以下问题:
- 容器与宿主机网络完全共享,隔离性差
- 端口冲突风险高,难以进行服务编排
- 不利于后续向标准化容器部署或 Kubernetes 迁移
- 排查网络问题时难以区分宿主与容器边界
因此,决定逐步去除 --net=host,回归 Docker 默认 bridge 网络模型。
二、移除 --net=host 面临的两个核心问题
在生产环境中移除 --net=host,必须解决以下两个关键问题,否则会直接导致服务不可用。
问题一:必须精准掌握服务真实监听的端口号
在 --net=host 模式下,容器内服务直接监听宿主机端口,端口关系不显式,容易产生以下问题:
- 实际监听端口不清楚
- 防火墙与安全组配置不准确
- 端口暴露依赖经验而非事实
问题二:注册到注册中心的 IP 必须是跨主机可达的地址
在 Docker bridge 模式下,容器会被分配一个形如 172.17.x.x 的 IP,该 IP 具有以下特性:
- 仅在当前宿主机内部可达
- 不同宿主机上的 Docker bridge 网络相互隔离
- 同网段不代表互通
如果将该 IP 注册到注册中心(如 Nacos),跨主机服务调用会直接失败。
三、问题一的解决方案:精准确认服务端口
1. 确认 JVM 实际监听端口
通过以下方式确认 Java 服务监听的端口:
# 查看容器pid
docker inspect -f '{{.State.Pid}}' 容器名称
# 当有--net=host时可用
ss -tulnp | grep pid
# 无--net=host时可用
nsenter -t pid -n ss -tulnp最终确认:
- 服务端口:8003
- 管理/监控端口:9997(如有)
2. Docker 显式映射端口
容器启动时,使用明确的端口映射:
-p 8003:8003
-p 9997:9997同时在宿主机防火墙与云厂商安全组中放行对应端口。
四、问题二的解决方案:正确注册服务 IP
1. 问题根因分析
在 bridge 网络模式下,服务自动注册到 Nacos 的 IP 为:
172.17.x.x该 IP 仅在本机 Docker 网络中可达,跨宿主机通信会出现:
No route to host这并非 Nacos 或 Feign 的问题,而是网络模型不成立。
2. 正确的 IP 注册策略
服务注册到 Nacos 的 IP,必须满足以下条件:
- 跨宿主机可达
- 与端口映射模型一致
- 网络路径清晰可控
最终选择:
- 使用宿主机内网 IP(VPC IP)注册到 Nacos
例如:
-e SPRING_CLOUD_NACOS_DISCOVERY_IP=172.16.0.41或配置文件中:
spring:
cloud:
nacos:
discovery:
ip: 172.16.0.413. 关于 metadata 中的公网IP与内网ip
以下参数仅用于展示,不参与服务路由:
--spring.cloud.nacos.discovery.metadata.host_public_ip=公网ip --spring.cloud.nacos.discovery.metadata.host_private_ip=内网ip不会影响 Feign / Ribbon / LoadBalancer 的调用行为。
五、最终 Docker 启动示例
docker run -d \
--name st_remit_weibo_prod \
-p 8003:8003 \
-p 9997:9997 \
-e JAVA_TOOL_OPTIONS='-Dserver.port=8003 -Xms2048m -Xmx4096m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/logs/xxx/heapdump-%p-%t.hprof' \
-e SPRING_CLOUD_NACOS_DISCOVERY_IP=172.16.0.41 \
<image> \
--spring.profiles.active=prod --spring.cloud.nacos.discovery.metadata.host_public_ip=公网ip --spring.cloud.nacos.discovery.metadata.host_private_ip=内网ip六、验证方式
Nacos 控制台中:
- 服务实例 IP 显示为
172.16.x.x - 端口为
8003
- 服务实例 IP 显示为
从另一台宿主机容器中:
curl http://172.16.0.41:8003/actuator/healthFeign 调用正常,无
No route to host
七、结论
--net=host并非生产环境的必选项删除
--net=host的前提是:- 明确服务端口
- 使用跨主机可达的 IP 注册服务
Docker bridge + 宿主机内网 IP + 明确端口映射,是当前架构下最稳定、可控的方案
本方案为后续容器标准化和平台化部署打下基础
最后编辑:张三 更新时间:2026-01-14 17:39