一、前言:业务背景与痛点

在微服务架构演进的过程中,为了安全起见,我们通常会用 Nginx 作为唯一流量入口,坚决不把底层的微服务和基建(如网关、Nacos)直接暴露到公网。

在单台服务器上混合部署这些组件时,走内网通信显然性能最好。但 Docker 容器有个致命痛点:每次重启后,其内网 IP 都会被重新分配。若在配置里写死内网 IP,服务一重启必定失联。

为了破局,我们需要用**“服务名”**代替脆弱的 IP。然而 Docker 规定:只有处于同一网络下的容器,才能通过服务名互相解析。这就引出了本文主题——如何构建统一的全局基建网络。

二、服务通信方案比对:IP vs 服务名

在深入配置之前,我们先科普一下容器间相互调用的三种常见姿势。为什么在生产环境中,我们必须强推“服务名”通信?

通信方式 底层逻辑与表现 致命痛点 生产推荐指数
公网 IP 直连 走外网绕一圈,需要宿主机暴露端口(如 8848、3306)。 极度不安全,随时可能被扫描攻击;且增加网络延迟和公网带宽成本。 ❌ 严禁使用
内网 IP 直连 使用 Docker 分配的内网网段(如 172.18.x.x)直连。 容器重启后 IP 极易变动,导致配置失效,维护成本极其高昂。 ⚠️ 极不推荐
服务名直连 借助 Docker 内置 DNS,将固定的服务名动态解析为最新内网 IP。 前置条件苛刻:要求所有相关容器必须被加入到同一个自定义网络中。 ⭐⭐⭐⭐⭐ 生产标配

由于“服务名直连”是唯一的正解,接下来我们就要解决它的前置条件:给所有服务分配统一的虚拟网络。

三、底层网络驱动选型

针对 Docker 容器间的互通,新手往往容易在网桥、主机网络等模式中迷失。大白话来说,咱们到底该给容器装哪种“虚拟网卡”?

网络驱动 底层逻辑与通信方式 隔离性与端口特征 核心适用场景
bridge (桥接) 虚拟路由器分配内网 IP,支持服务名互相通信。 极好。内外隔离,外界访问需通过 -p 宿主机打孔映射。 微服务主力军。适合单台服务器的多容器互联(本文首选)。
host (主机) 放弃隔离,直接共用宿主机网络栈和物理端口。 无隔离。无需映射,极易发生“端口冲突”报错。 性能狂魔。仅限对网络延迟极度苛刻的高级网关或底层监控 Agent。
overlay (覆盖) 跨主机组网,底层通过隧道协议实现多机通信。 跨节点互联。需依赖 Docker Swarm 或 K8s 集群。 🚀 集群化标配。后续架构演进为多节点集群时,跨主机互通就靠它了!
none (小黑屋) 只有本地环回网卡(lo),绝对孤立。 绝对安全隔离。无法与任何外部通信。 纯本地批处理、高密级离线计算任务。

💡 补充一点:本文咱们主要解决单台服务器内的互通,所以核心使用的是 bridge 桥接模式。未来如果你接触到跨多台服务器的集群环境,底层网络就会用到上面提到的 overlay,大家先有个大概的印象即可。

接下来,我们将直接进入基于 bridge 驱动的全局网络实战,让所有的基建和服务搬进统管的小区。

四、核心架构与数据流向

我们可以通过一张简图,3 秒钟内看懂改造后的网络拓扑全貌与数据流向:

jenkins-network 独立构建网络

宿主机 xf-infra-net 全局基建网络 172.x.x.x

HTTP 80/443

proxy_pass http://cloud-gateway:9090

服务发现与内部路由

JDBC jdbc:mysql://mysql:3306

Redis redis://redis:6379

服务注册/发现

服务注册/发现

1. 拉取代码并编译镜像

2. docker run 部署业务容器
强行注入 xf-infra-net

客户端请求

Nginx 流量网关
公网唯一入口

Spring Cloud Gateway
基于服务名

业务微服务
cloud-user等

MySQL 基建

Redis 基建

Nacos 注册中心
nacos:8848

Jenkins 持续集成

代码仓库

五、环境准备与架构边界规划

在动手实战之前,我们必须先划定架构边界。很多新手为了追求“一家人就要整整齐齐”的快感,会把服务器上所有的容器(甚至包括 Jenkins)一股脑儿全拉进全局网络,这就踩了生产环境的大坑。

🚨 避坑核心原则:按运行时角色进行网络物理隔离。

必须加入统一网络的(运行时“住户”)

  • 注册中心与网关:如 Nacos、Spring Cloud Gateway。它们是流量枢纽,必须互通。
  • 数据存储与缓存:如 MySQL、Redis、Elasticsearch。业务微服务每天要与它们高频交换数据。
  • 业务微服务:所有处理业务逻辑的容器。

坚决不要加入统一网络的(非运行时“施工队”)

  • Jenkins 等 CI/CD 工具:它是“起重机”,只负责拉代码、打镜像、下达 docker run 指令。它压根不需要在运行时去调 Nacos 的接口。强行混入业务网桥,其庞大的磁盘 I/O 和网络吞吐极易造成业务网络的拥堵和延迟。

最终原则:让 Jenkins 永远呆在独立的 jenkins-network 里,让业务组件在全局网络中畅游!

  • 基础设施版本要求:JDK 17, Docker Engine 24.0+, Docker Compose V2, Nginx 1.24+

📦 配套微服务源码获取
本文涉及的微服务和网关项目代码均已完整开源。
🔗 源码仓库地址点击前往GitHub获取源码
(注:本文重点在运维架构改造,业务源码仅供各位在本地实战时作为联调参考)

技术局限性与使用边界
真实的微服务通常是跨多台节点部署的,但饭要一口口吃,本方案主要帮你彻底打通单台物理机的服务闭环。若未来演进为跨机器集群,底层网络则需顺势升级为 Overlay 方案。同时,单机部署大量容器时,严禁硬编码分配全量资源,必须针对每个服务进行内存和 CPU 的隔离设限。

六、核心实践与核心参数推演

1. 现状摸底:查看隔离的“信息孤岛”

在创建统一基建网络之前,我们先通过命令查看当前服务器的网络现状:

# 查看所有 Docker 网络
docker network ls

在这里插入图片描述

你会发现,几乎每种基建组件在使用 docker-compose 启动时,Docker 都会“贴心”地为它创建一个独立的专属网络(如 nacos_default)。这就导致它们互相之间是完全物理隔离的“信息孤岛”。如果不借助公网 IP 绕行,它们根本无法互通。

2. 手动创建全局基建网络

首先,我们要在宿主机层面打地基,建立一个公共的桥接网络 xf-infra-net

# 默认使用 bridge 驱动创建全局基建网络,用于 Nacos、MQ、网关等
docker network create xf-infra-net

在这里插入图片描述

🚨 高阶拓展:路由劫持与网络黑洞
如果你是在企业内网的物理机上操作,直接使用上述默认命令可能会有隐患。Docker 默认会随机分配一个 172.x.0.0/16 的网段,如果这个网段恰好和你们公司的办公网或 VPN 网段冲突,Docker 就会在操作系统的底层路由表里“劫持”这个网段。
这会导致一个极其隐蔽的 Bug:你的这台服务器将再也无法访问公司内网里同网段的其他物理机器(请求全被 Docker 内部网卡拦截并吞没,导致 Timeout)。

企业级严谨做法:如果你担心未来可能的网段冲突,可以强制划定一个冷门网段:

# 强制指定冷门网段(如 172.30.0.0/16),彻底杜绝与企业内网路由冲突
docker network create --subnet=172.30.0.0/16 xf-infra-net

3. 改造 Compose 基建配置

在改造之前,我们可以先针对特定的服务(比如 Nacos)进行深度实现,看看它目前的网络归属:

# 查看 Nacos 容器的底层网络详情
docker inspect nacos

在这里插入图片描述

接下来,我们需要修改 Nacos、MySQL、Nginx 等基建的 docker-compose.yml,把它们拉入全局网络。

💡 补充一点:在 Compose 中配置网络,常见的有两种方式,大家别搞混了:
方式一:在配置中让 Compose 自己新建网络(适用于组件自己关起门来玩)

services:
  service-a:
    image: busybox
    networks:
      - my-private-net

networks:
  my-private-net:
    driver: bridge # 告诉 Compose 自己建一个全新的桥接网络

方式二:加入外部已存在的网络(咱们当前采取的方案)

因为咱们已经在宿主机上手动建好了 xf-infra-net,所以必须采用方式二。修改基建的 docker-compose.yml,让它们直接“插”到全局网络中:

services:
  nacos:
    image: nacos/nacos-server:v2.2.3
    container_name: nacos
    networks:
      - xf-infra-net  # 🔌 极其直白:直接插上全局网
    ports:
      - "8848:8848"

networks:
  xf-infra-net:       # 👈 变量名直接就叫 xf-infra-net
    external: true    # 👈 明确告诉 Docker,这网是外部现成的,别盲目新建!

使用 docker-compose downup -d 重新构建启动服务后,我们再次执行 docker inspect nacos 进行对比:
在这里插入图片描述

此时,Nacos 已经成功搬进了我们统管的全局基建网络中。

4. 改造 Jenkins 流水线脚本

📌 前置参考:本节仅针对网络改造部分,只展示核心的 docker run 容器部署脚本。如果你还没有搭建好完整的 Jenkins CI/CD 流程,可以先阅读我的上一篇前置教程:点击阅读:完整的 Jenkins 流水线搭建实战,打好基础再来实战本篇。

业务容器(通过 Jenkins docker run 启动)必须使用 --network 参数强行入网,并且全部改用服务名连接

docker run -d \
    --name ${CONTAINER_NAME} \
    -p ${CONTAINER_PORT}:${CONTAINER_PORT} \
    --restart=always \
    --network xf-infra-net \
    -m 800m \
    --cpus="1.0" \
    -v /data/servers/logs:/data/servers/logs \
    -e JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC" \
    -e NACOS_SERVER_ADDR=nacos:8848 \
    -e NACOS_USERNAME=nacos \
    -e NACOS_PWD=******** \
    ${FULL_IMAGE_NAME}:${IMAGE_TAG}
  • 核心参数与边界推演
    • --network xf-infra-net:打破隔离,此时容器内部可以把 nacos 当成内网 IP 解析。
    • -m 800m--cpus="1.0":限制该微服务最多使用 800M 物理内存和 1 个 CPU 时间片,防止单点故障拖垮整台服务器。
    • -Xms256m -Xmx512m:基于 800m 容器限额计算,留出近 300m 的冗余空间给 MetaSpace 与堆外内存,彻底杜绝 OOM Killed

5. Nginx 流量收口点配置

⚠️ 前置大前提:在配置路由转发之前,你的 Nginx 容器本身也必须加入 xf-infra-net 全局网络(配置方式与上文的 Nacos 完全一致,不再赘述)。

此时由于 Nginx 和所有的服务都身处同一个统管小区,Nginx 反向代理就可以彻底关闭具体微服务和网关的物理端口暴露,直接通过服务名进行安全的内网流量分发了。

常规情况下,如果能绝对保证网关(cloud-gateway)比 Nginx 先启动,可以直接这样写死地址:

    # 基础配置(需保证网关先于 Nginx 启动)
    location /cloud/ {
        # 直接使用服务名 cloud-gateway 路由,对外隐藏真实IP与端口
        proxy_pass http://cloud-gateway:9090/; 
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

🚨 高危踩坑预警:Nginx 启动顺序依赖导致宕机
Nginx 在启动加载配置时,会立刻去解析 proxy_pass 后面的服务名。如果此时网关容器还没启动,Docker 的内置 DNS 找不到 cloud-gateway,Nginx 就会抛出 host not found in upstream 致命报错并直接挂掉(Crash)

为了完美解耦 Nginx 和微服务的启动顺序(不管谁先启动都不报错),我们需要使用 Nginx 的动态解析技巧。通过定义变量和引入 Docker 的内部 DNS,迫使 Nginx 只有在实际发生请求时,再去动态解析 IP:

    # 🌟 生产级配置:动态解析(完美解耦启动顺序防宕机)
    location /cloud/ {
        # 强制指定 Docker 的内部 DNS 服务器(固定 IP 为 127.0.0.11)
        # valid=10s 表示防 IP 动态漂移,10秒后重新解析
        resolver 127.0.0.11 valid=10s ipv6=off;
        
        # 将服务名赋值给变量(不要带后面的 URI 路径)
        set $gateway_upstream http://cloud-gateway:9090;
        
        # 代理该变量。注意:因为使用了变量,Nginx 不会再自动拼接路径,
        # 所以这里必须手动拼接 $request_uri,否则所有请求都会被发到网关根目录报 404!
        proxy_pass $gateway_upstream$request_uri; 
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

七、运行效果与结果验证

经过上面的系统改造,我们实际上已经完成了三个核心层面的“网络换防”:

  1. 基建层:Nacos 等中间件通过 docker compose up -d 重新启动,并成功接入了 xf-infra-net
  2. 业务层:Jenkins 流水线配置修改完毕,业务微服务被重新构建发布,也强制加入了全局网络。
  3. 流量层:Nginx 的反向代理路由(基于服务名)更新完毕,并通过重启容器(或 nginx -s reload)正式生效。

所有的前置拼图都已经严丝合缝地拼接完毕。是骡子是马必须拉出来遛遛,现在按以下步骤验证网络的最终连通性:

步骤 1:查看内部网络全景住户
执行 docker network inspect xf-infra-net 检查网络。你需要看到 Nacos 和刚部署的微服务确实在同一个 Containers 列表中。
在这里插入图片描述

步骤 2:直接通过 Nginx 访问验证
在网关不再对外开放 9090 端口的情况下,通过宿主机 80(本文映射端口:9001) 端口直接请求 Nginx,并成功将流量透传给了网关。
在这里插入图片描述

八、总结

建立统一的全局基建网络,是将“散兵游勇”式的容器管理走向规范化的核心一步。通过内部服务名通信,我们隐藏了内网服务的动态 IP 和真实端口,配合 Nginx 将流量与安全统一收口,整个系统的健壮性有了质的提升。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐