Docker 网络配置实战指南:Bridge、Host、Macvlan 与多容器互联
结论先行:90% 的 Docker 容器互联失败或连接超时,根因都在于误用了默认 Bridge 网络或外部防火墙规则冲突。独立开发者记住一条铁律:坚决弃用默认
bridge(缺少内置 DNS 解析),生产必须创建自定义网桥网络(User-defined Bridge)。同一网络内的 Web、API 与数据库直接用服务名互访,对外只暴露网关端口。Host 模式仅用于对网卡吞吐有极限压榨要求的特定网络代理,绝大多数场景自定义 Bridge 即可兼顾隔离安全性与极低延迟。
0、写在前面
用 Docker 部署微服务时,最常见的技术卡点几乎都与网络相关:
- 在同一个 VPS 上同时跑了 Web 前端与后端,前端容器代码里写
fetch("http://localhost:3000"),却始终提示连接拒绝; - 容器明明成功启动,外部浏览器访问
http://<服务器IP>:8080却始终超时无响应; - 修改了云服务器上的 UFW 防火墙关闭某端口,却震惊地发现外部依然能直接访问该端口(Docker 默认机制直接在 iptables 插入规则,绕过了 UFW)。
厘清 Docker 网络的底层原理与常用命令,不仅能让你在多容器通信时得心应手,更能从根本上消除端口被意外暴露至公网的严重安全风险。
1、期望目标
阅读并实操本文后,你将达成以下目标:
- [ ] 掌握 Docker 五大网络驱动模式(Bridge、Host、None、Overlay、Macvlan)的底层区别;
- [ ] 理解「默认 bridge」与「自定义 bridge」在 DNS 服务发现上的本质差异;
- [ ] 掌握生产级自定义网桥创建、子网划分与静态 IP 分配;
- [ ] 掌握单容器跨多网络连接实现网络隔离(反代层与数据库层的安全解耦);
- [ ] 掌握 Docker 绕过宿主机 UFW 防火墙漏洞的根本防御方案;
- [ ] 熟练排查容器网络不通、DNS 无法解析与端口被占用等故障。
2、技术架构与驱动模式对比
五大网络驱动全景对比
| 网络驱动 | 通信与隔离机制 | 性能开销 | DNS 自动解析 | 端口冲突风险 | 最佳适用场景 |
|---|---|---|---|---|---|
| 自定义 Bridge | 软件虚拟网桥,NAT 转发 | 微秒级额外开销 | 支持(通过容器名/服务名直接互通) | 无(容器各自独立内网端口) | 单机多容器微服务部署(首选推荐) |
| 默认 bridge | Docker 预置的 docker0 网桥 |
微秒级额外开销 | 不支持(只能敲 IP 地址,重启即变) | 无 | 临时调试单一容器 |
| Host | 共享宿主机网络命名空间 | 零开销(原生物理性能) | 依赖宿主机本地 /etc/hosts |
高(容器占用端口等同宿主端口) | 极端高并发、网络监控或代理节点 |
| None | 彻底关闭网络栈,仅保留回环接口 | 零开销 | 无 | 无 | 批处理离线计算、安全隔离沙盒 |
| Macvlan | 容器直接分配宿主物理网段 IP 与独立 MAC | 接近原生性能 | 依赖物理局域网路由器 DNS | 低 | 软路由、家庭 NAS 直连物理局域网 |
容器网络互联拓扑
3、实操步骤与生产命令
3.1 为什么必须弃用默认 bridge?
在终端执行:
1 | docker network ls |
你会看到一个默认名为 bridge 的网络。若在 docker run 时未显式指定 --network,容器就会被扔进该网络。
默认 bridge 的致命缺陷:
它禁用了 Docker 内部的嵌入式 DNS 服务器(127.0.0.11)。在默认网络下,容器之间想要互相访问,必须知道对方的 IP 地址,无法通过容器名称(如 web 或 db)直接通信。然而,容器在重启后分配的 IP 随时会发生改变。
3.2 创建并使用自定义 Bridge 网络
创建专属网桥只需一行命令:
1 | # 1. 创建自定义网桥 |
验证容器内服务发现:
进入 prod-app 容器,直接 ping 容器名:
1 | docker exec -it prod-app ping -c 3 prod-db |
返回输出显示已自动解析出类似 172.18.0.2 的内网 IP,通信毫无障碍。
3.3 容器连接双网络:生产级多层隔离架构
为了防止 Web 前端反代层被穿透后直接拿到核心数据库的访问权限,我们可以实施双网桥安全隔离:
frontend-net:Nginx 与 API 后端互通;backend-net:API 后端与 PostgreSQL 互通;- Nginx 物理上无法连接 PostgreSQL。
1 | # 1. 创建两个独立网络 |
此时:
edge-proxy可以解析并访问core-api;core-api可以解析并访问secret-db;edge-proxy尝试连接secret-db会直接报找不到主机名错误,实现网络隔离。
4、防御核心漏洞:Docker 绕过 UFW 防火墙
这是所有 Linux 运维新手最容易踩到的严重安全隐患。
漏洞机理
在 Ubuntu 上配置了 sudo ufw default deny incoming,并自认为没有开放 5432 端口。但当你执行:
1 | docker run -d -p 5432:5432 postgres |
Docker 守护进程会在 Linux 内核的 PREROUTING 链中直接插入 iptables 规则。这些规则在数据包到达 UFW 处理链之前就完成了 NAT 转发,导致你的 PostgreSQL 端口直接裸奔暴露在公网,遭到全网扫描。
根本解决方案:显式绑定本地环回地址
如果服务只需给宿主机或反向代理访问,映射端口时必须显式声明绑定到 127.0.0.1,切勿简写为 -p 5432:5432:
1 | # 错误写法(默认监听 0.0.0.0,绕过 UFW 对外暴露) |
在 Docker Compose 中对应写法:
1 | ports: |
5、生产避坑清单
避坑 1:容器内应用仅监听 127.0.0.1 导致端口转发连接超时
- 现象:
docker run -p 8080:8080 myapp启动成功,宿主机执行curl http://localhost:8080返回Connection reset by peer。 - 根因:容器内的应用(如 Express、FastAPI)默认监听了容器环境内的
127.0.0.1。Docker 网桥转发过来的数据包被容器网络栈丢弃。 - 解法:在应用启动配置中,监听地址统一设置为全零地址
0.0.0.0。
避坑 2:误用 --network host 导致多服务端口冲突
- 现象:两个 Nginx 容器都开启了 host 模式,第二个容器启动报错
Address already in use。 - 解法:Host 模式下容器与宿主机共享同一网络命名空间,无法享有独立的端口空间。除了特定的网络性能测试或反代场景,微服务间通信首选自定义 Bridge。
6、FAQ
Q1:清理无用网络会把正在运行的容器断网吗?
运行 docker network prune 命令时,Docker 只会清理当前没有任何运行中容器连接的空闲网络,绝不会影响正在服役中的业务容器。
Q2:单台 VPS 最多能创建多少个 Docker 网络?
Docker 默认每个 Bridge 网桥使用 /16 或 /24 子网分配 IP。单机可支持上百个虚拟网桥,足以满足多项目隔离需求。