Docker容器网络模式

想象一下,Docker 容器就像是一栋大型公寓楼(宿主机)里的一个个独立房间

每个房间(容器)里都住着不同的“租客”(应用程序),比如一个房间里住着 Web 服务器,另一个房间里住着 数据库

默认情况下,为了安全,这些房间的墙壁是不透音、不透光的。Web 服务器想跟数据库说句话(发个请求),直接喊是听不见的。

那么,Docker 是如何让这些房间互相“串门”,或者让外面的人访问房间的呢?

场景一:默认模式 —— “同一楼层的邻居” (Bridge 网络)

当直接运行 docker run 而不指定网络时,容器会自动加入默认的 bridge 网络。可以通过docker inspect 容器ID来查看查看其Networks配置,如下图就是加入的默认bridge网络:

  • 发生了什么? Docker 会在宿主机上创建一个虚拟的网桥(叫 docker0)。每个新容器启动时,Docker 会拉一根虚拟网线,一头插在容器里,另一头插在 docker0 网桥上。
  • 怎么通信?
    • 容器 A 访问 容器 B:A 知道 B 的内部 IP(比如 172.17.0.3),可以直接 ping 通。
    • 缺点:IP 是动态分配的!如果容器 B 重启了,IP 可能变了,A 就找不到 B 了。而且,不能通过容器名字访问(默认 bridge 网络不支持内置 DNS 解析)。

场景二:进阶模式 —— “自带电话簿的 VIP 套房” (自定义 Bridge 网络)

这是生产环境推荐的做法。创建一个专属的网络,把容器加进去。

# 1. 创建一个叫 my-net 的专属网络
docker network create my-net
# 2. 启动容器时加入这个网络
docker run -d --name web --network my-net nginxdocker run -d --name db --network my-net mysql
  • 神奇之处(服务发现): 在这个网络里,Docker 充当了DNS 服务器的角色。
    • 容器 web 想访问 db,不需要知道 db 的 IP 是多少。
    • 它只需要喊:ping db 或者访问 http://db:3306
    • Docker 会自动把名字 db 解析成当前的 IP 地址。
    • 比喻:就像在公司里,你不用记同事的工位号,直接在通讯录搜“张三”就能打电话。哪怕张三换了工位(IP 变了),通讯录会自动更新。

场景三:对外营业 —— “公寓大门的门禁” (端口映射 -p)

容器默认是隔离的,外网(互联网)无法直接访问容器内部。如果你想让外面的用户访问容器里的 Web 服务,需要端口映射

docker run -p 8080:80 nginx
  • 含义:
    • 8080宿主机端口(公寓大门的门牌号)。
    • 80容器端口(房间内部的门牌号)。
  • 流程:
    1. 用户访问 http://你的服务器 IP:8080
    2. 请求到达宿主机大门。
    3. Docker 的 iptables 规则(门禁系统)发现:“哦,找 8080 的?转发给内部容器的 80 端口!”
    4. 容器处理请求,原路返回。
  • 比喻:外卖员(外部用户)不能进房间,只能送到公寓前台(宿主机 8080 端口),前台再打电话让房间里的租客(容器 80 端口)下来拿

场景四:特殊模式 —— “没有墙壁”与“孤岛”

除了默认的 Bridge,Docker 还有几种特殊的网络模式:

1. Host 模式 (--network host)

  • 比喻:容器不住房间了,直接睡在公寓大厅里
  • 特点:容器没有自己的网络命名空间,直接使用宿主机的网络。
  • 优点:性能最好,没有 NAT 转发的损耗。
  • 缺点:端口容易冲突(容器占用了 80,宿主机就不能用 80 了),隔离性差。
  • 命令docker run --network host ...

2. None 模式 (--network none)

  • 比喻关禁闭
  • 特点:容器只有 lo 回环接口,完全断网,连不了外网,也连不了其他容器。
  • 用途:极高安全需求,或者后续手动配置网络。

3. Overlay 模式 (跨主机通信)

  • 比喻连接两栋不同大楼的地下隧道
  • 场景:Docker Swarm 或 Kubernetes 集群。
  • 特点:容器 A 在服务器 1 上,容器 B 在服务器 2 上,但它们感觉像是在同一个局域网里,可以直接通过名字通信。
  • 原理:通过 VXLAN 等技术封装数据包,在物理网络之上叠加一层虚拟网络。

如何查看网络状况?

作为管理员,你怎么知道这些“网线”是怎么连的?

  1. 查看有哪些网络:docker network ls
  2. 查看某个网络的详情(比如谁在里面):docker network inspect my-net在输出的 JSON 里,找到 Containers 字段,你能看到每个容器的 IP 地址和 MAC 地址。