Skip to content

第 5 章 网络:容器间通信 ​

本章目标:理解 bridge / host / none 三种网络模式,掌握自定义 bridge 网络下的容器互联(容器名即域名),分清"端口发布"与"容器间通信"两回事。

1. 容器网络要解决的三件事 ​

  1. 对外暴露:让宿主机/外部能访问容器内端口——第 3 章的 -p 端口发布;
  2. 容器间通信:多个容器互相访问——本章主角;
  3. 网络隔离:让不该互相访问的容器彼此看不见——网络本身就是安全边界。

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 网络带来两个关键能力:

  1. 所有加入该网络的容器同处一个子网;
  2. 内建 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 进容器验证连通性。

练习 ​

  1. 创建自定义网络 demo-net,运行两个 alpine 容器(sleep 300)并加入该网络,用 ping 按名字双向验证连通。
  2. 再运行一个不加 --network 的 alpine 容器,从它 ping demo-net 里的容器名,观察失败并解释原因(第 4 节)。
  3. 用 docker network inspect demo-net 找出各容器的 IP,对照 docker exec 里 ip addr 的结果。
  4. 思考题:生产环境为什么推荐"数据库放单独网络、只让应用容器加入"?(提示:结合第 4 节的隔离演示。)

可运行示例见 examples/05-networking/,按其中的 README 步骤执行。

📖本文阅读--次|📊全站访问--次|👥访客--人