第 5 章 网络:容器间通信
本章目标:理解 bridge / host / none 三种网络模式,掌握自定义 bridge 网络下的容器互联(容器名即域名),分清"端口发布"与"容器间通信"两回事。
1. 容器网络要解决的三件事
- 对外暴露:让宿主机/外部能访问容器内端口——第 3 章的
-p端口发布; - 容器间通信:多个容器互相访问——本章主角;
- 网络隔离:让不该互相访问的容器彼此看不见——网络本身就是安全边界。
2. 网络模式总览
bash
docker network ls # 列出网络
docker network inspect bridge # 查看某个网络的成员与子网默认有三个内置网络:
| 模式 | 说明 | 适用场景 |
|---|---|---|
bridge(默认) | 容器接入虚拟网桥,NAT 对外,容器间可互访但只能靠 IP | 单容器、无互联需求 |
host | 容器共享宿主机网络栈,无独立 IP(-p 失效) | 追求极低延迟、需要大量端口的场景 |
none | 无网络 | 完全离网的容器 |
- 默认 bridge 的容器不在同一个局域网内(各自独立子网),相互之间只能靠 IP 访问,不支持容器名 DNS 解析——这是它的最大短板,也是下一节自定义网络的动机;
- host 模式下容器直接用宿主机的 IP 和端口,性能最好但隔离最弱,且
-p会被忽略(端口天然共享)。
3. 自定义 bridge 网络:容器名即域名
用户自定义的 bridge 网络带来两个关键能力:
- 所有加入该网络的容器同处一个子网;
- 内建 DNS 解析:容器名 = 域名,容器间按名字互相访问,IP 变了也不受影响。
bash
docker network create demo-net # 创建自定义网络
docker run -d --name app --network demo-net alpine sleep 300
docker run -d --name web --network demo-net -p 8084:80 nginx:alpine
docker exec app ping -c 2 web # 按名字 ping 通(容器名即域名)
docker exec web ping -c 2 app # 双向都通输出示例:
text
PING web (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.103 ms
...一个容器可以同时加入多个网络:docker network connect demo-net 容器名 / docker network disconnect。典型拓扑——前端容器既在 front 网络对外、又在 back 网络连后端:
bash
docker network create front
docker network create back
docker run -d --name api --network back alpine sleep 300
docker run -d --name web --network front --network back nginx:alpine # 同时加入两个网络
docker exec web ping -c 2 api # 走 back 网络访问后端4. 默认 bridge 的局限与网络隔离
局限演示——默认 bridge 下按名字访问会失败:
bash
docker run -d --name c1 alpine sleep 300
docker run -d --name c2 alpine sleep 300
docker exec c1 ping -c 2 c2 # 失败:ping: bad address 'c2'(默认网络无 DNS 解析)
docker exec c1 ping -c 2 172.17.0.x # 只能改用 IP(且 IP 不稳定)隔离演示——不同网络的容器互不可见:
bash
docker run -d --name iso alpine sleep 300 # 在默认 bridge 网络
docker exec iso ping -c 2 app # 失败:app 在 demo-net,跨网络不可达网络隔离意味着:只有加入同一自定义网络的容器才能互相通信——这是微服务架构里"数据库容器只对应用容器开放"的实现基础。
5. 端口发布 vs 容器间通信
这是新手最容易混淆的一对概念:
text
┌─ 容器间通信:同一网络内按名字直连,不经过 -p ──────────┐
▼ │
外部/宿主机 ──-p 8084:80──▶ web(nginx) ── 容器名直连 ──▶ app(后端) │
│
-p 只负责"对外发布",容器与容器之间说话不需要也不应该用 -p │
└───────────────────────────────────────────────────┘- 对外暴露:
-p把容器端口发布到宿主机,供外部访问; - 容器间通信:同网络容器按名字直连(如
curl http://web:80),不经过-p。
也就是说:即使不给任何容器配 -p,同一自定义网络里的容器依然能互相访问;-p 只是"对外开门"。
6. 网络调试与清理
bash
docker network inspect demo-net # 查看网络成员、子网、网关
docker exec app ip addr # 容器内查看自己的 IP(alpine 需先 apk add iproute2)
docker network disconnect demo-net app # 把容器移出网络
docker network rm demo-net # 删除网络(先移除所有容器)
docker network prune # 清理所有未被使用的网络常见排查思路:容器间不通 → ① 确认在同一网络(network inspect 看成员)② 确认按名字而非 IP ③ 确认没有防火墙/安全组挡在中间。
常见误区
- 误区:默认网络下容器可以按名字互 ping。 正确:只有自定义网络提供容器名 DNS 解析;默认 bridge 只能靠 IP。
- 误区:容器间通信要用
-p。 正确:-p只做对外端口发布;容器间通信在同网络内按名字直连。 - 误区:
--link是容器互联的正解。 正确:--link是 Docker 早期方案,已废弃,用自定义网络替代。 - 误区:所有容器默认都在同一个"局域网"里。 正确:默认 bridge 下容器各自隔离(只能 IP 互访),要组网必须加入同一个自定义网络。
小结
- 三种内置网络:bridge(默认)、host(共享宿主机栈)、none(无网)。
- 自定义 bridge 网络提供容器名 DNS 解析——容器互联的正解,
docker network create+--network。 - 网络即边界:只有同一网络内的容器才能互相通信,用于服务隔离。
- 对外用
-p端口发布,容器间按名字直连,两者互不替代。 - 调试:
docker network inspect看成员与子网,docker exec进容器验证连通性。
练习
- 创建自定义网络
demo-net,运行两个alpine容器(sleep 300)并加入该网络,用ping按名字双向验证连通。 - 再运行一个不加
--network的alpine容器,从它pingdemo-net里的容器名,观察失败并解释原因(第 4 节)。 - 用
docker network inspect demo-net找出各容器的 IP,对照docker exec里ip addr的结果。 - 思考题:生产环境为什么推荐"数据库放单独网络、只让应用容器加入"?(提示:结合第 4 节的隔离演示。)
可运行示例见
examples/05-networking/,按其中的 README 步骤执行。