核心痛点:为什么 Docker 需要网络?
实际项目通常不是一个容器,而是多个容器共同工作(如:用户 -> Nginx -> 后端服务 -> MySQL/Redis)。Docker 网络主要解决三个核心问题:
容器自己怎么联网?(访问互联网)
外部怎么访问容器?(端口映射)
容器之间怎么通信?(跨容器互联)
一、 环境基础:Docker 启动前后的网络差异
1. Docker 未启动时的默认网络情况
在未启动 Docker 前,宿主机执行ifconfig通常能看到:
ens33:宿主机的真实物理网卡lo:本地回环网卡 (127.0.0.1)virbr0:如果 CentOS 安装了虚拟化服务(libvirt),会生成一个以网桥连接的私网地址(如192.168.122.1),提供 NAT 访问外网的功能。如果不使用虚拟化,可以直接卸载:yum remove libvirt-libs.x86_64
2. Docker 启动后的网络情况
Docker 启动后,宿主机网络会产生一个名为docker0的虚拟网桥。
[root@zzyy ~]# ifconfig docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255可以看到,它默认分配了172.17.0.1的网关 IP,它将在内核层连通所有容器和本地主机,放入同一个物理网络。
二、 常用基本命令与能干嘛?
查看网络:
docker network ls(默认会创建 bridge、host、none 三个网络)查看网络源数据:
docker network inspect XXX网络名字删除网络:
docker network rm XXX网络名字能干嘛:容器间的互联和通信、端口映射。最核心的是:容器 IP 变动时,可以通过服务名直接网络通信而不受影响。
三、 四大网络模式总体介绍与选型
可以通过--network参数指定不同模式:
| 模式 | 核心特点 | 典型场景 | 启动命令参数 |
|---|---|---|---|
| bridge | 独立网络空间,连接到docker0虚拟网桥 | 普通项目,最常用,默认模式 | --network bridge |
| host | 直接使用宿主机网络,不虚拟自己的网卡 | 对网络性能要求极高的程序、网络监控 | --network host |
| none | 基本没有网络,只有lo回环接口 | 需要完全隔离网络的程序,不需要网络 | --network none |
| container | 共享另一个容器的网络空间(IP、端口范围) | 特殊协作场景,辅助容器 | --network container:NAME/ID |
四、 网络模式深度拆解与真实环境排错
1. bridge 模式(默认,重点理解)
是什么:Docker 服务默认创建一个docker0网桥(虚拟交换机),将容器和宿主机放到同一个物理网络。
容器实例内默认网络IP生产规则与案例(IP 变动大坑):
启动两个 ubuntu 容器u1和u2,通过docker inspect查看 IP,发现分别为172.17.0.2和172.17.0.3。
如果关闭u2,新建u3,会发现u3的 IP 变成了172.17.0.3(复用了被释放的 IP)。
⚠️结论:docker 容器内部的 IP 是有可能会发生改变的!因此推荐使用服务名/容器名通信。
两两匹配验证(veth pair 机制):
在宿主机执行ip addr看到28: veth14fc73a@if27;进入容器执行ip addr看到27: eth0@if28。
🔍原理解析:
@ifX表示对端接口编号。宿主机 28 ↔ 容器 27,这就证明这是一对 veth pair(虚拟网线)。
互通与抓包:
容器 A 可以直接 ping 容器 B 的 IP,也能访问对方开启的服务。
不能主动偷看对方流量:Linux 网络命名空间隔离,A 只能看到进出自己 eth0 的数据包。
宿主机可以抓全部流量:在宿主机执行
tcpdump -i docker0,就能抓到两个容器之间所有通信数据包(因为 docker0 网桥本身属于宿主机的网络命名空间)。
2. host 模式(避坑重点)
是什么:容器不会获得独立的 Network Namespace,而是和宿主机共用一个,直接使用宿主机的 IP 和端口,不需要额外 NAT 转换。
⚠️ 真实排错大坑:
# 错误示范:指定了 --network host 还指定 -p docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8 # 警告信息:WARNING: Published ports are discarded when using host network mode原因:使用 host 模式时,-p设置的端口映射参数将不会起到任何作用,且端口号会以主机端口号为主,重复时则递增。
解决:使用 host 模式直接去掉-p参数,通过http://宿主机IP:端口直接访问。此时容器共享宿主机网络 IP,外部主机与容器可以直接通信。
3. none 模式
是什么:禁用网络功能。Docker 容器没有网卡、IP、路由等信息,只有一个lo(127.0.0.1) 标识。
使用场景:不需要网络的隔离环境。优点是隔离能力强,缺点是基本无法进行正常网络通信。
4. container 模式(特殊协作)
是什么:新创建的容器不会创建自己的网卡,而是和一个指定的容器共享 IP、端口范围等。两个容器除了网络方面,文件系统、进程列表等还是隔离的。
❌ 错误案例(端口冲突):共用网络时如果两个容器都映射相同的端口,会直接报错conflicting options: port publishing and the container type network mode.(相当于两个容器公用同一个 IP 和同一个端口,导致端口冲突)。
✅ 正确案例(Alpine 演示):
docker run -it --name alpine1 alpine /bin/sh docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh在 alpine1 和 alpine2 中分别执行ip addr,发现两者的eth0网卡 IP 完全一样,证明网络共用。
⚠️ 生命周期绑定坑:假如此时关闭 alpine1,再进入 alpine2 执行ip addr,发现eth0消失了,只剩下lo回环接口。证明 alpine2 的网络完全依赖 alpine1。
五、 端口映射与跨容器通信(解决外部访问与互联)
1. 端口映射(解决外部访问容器)
容器 IP(如172.17.0.2)是 Docker 内部网络,外部无法直接访问。通过端口映射-p解决。
语法:
-p 8080:80(宿主机端口:容器端口)。底层原理:用户访问
服务器IP:8080-> 宿主机 8080 端口 -> Docker 转发/NAT -> 容器内部 80 端口 -> Nginx 服务。端口映射不是简单的“两个端口绑定”,而是 Docker 利用 Linux 网络转发和 NAT 等机制完成流量转发。
2. 跨容器通信(Docker DNS)
推荐做法:自定义网络 + 容器名通信。
docker network create mynet docker run -d --name backend --network mynet nginx docker run -d --name mysql --network mynet mysql在 backend 容器中直接连接
mysql:3306。为什么不能写死 IP:容器 IP 可能发生变化(重启、重建后 IP 会变),容器名/服务名更加稳定,更容易维护。
完整解析流程:
Backend 发起请求 mysql:3306->Docker DNS 解析 mysql->解析到 172.18.0.3 容器 IP->目标端口。这也是 Docker Compose 中mysql:3306这种写法的基础。
六、 底层原理:Linux 网络能力的组合
Docker 网络本质上是把 Linux 提供的四大网络能力组合起来,为容器提供网络功能。
Network Namespace(网络隔离的基础)
让不同进程拥有独立的网络环境(独立的 IP、网卡设备、路由表、防火墙规则),互相看不到对方的网络配置。veth pair(虚拟网线)
连接容器和宿主机。可以理解为一根虚拟网线,两端各有一个虚拟网卡。一端放在容器里(eth0),一端放在宿主机上(vethxxx)。容器eth0发出的数据包,通过 veth pair 这根“网线”,直接传到宿主机的网络线上。Linux Bridge(虚拟交换机)
Docker 默认创建的docker0网桥,相当于 Linux 中的虚拟交换机。所有宿主机侧的 veth 全部接入同一个网桥。
容器 A 和容器 B 通信路径:容器 A -> veth -> docker0 -> veth -> 容器 B。在同一网段下,二层可以直接互通,不需要经过宿主机路由转发。路由与 NAT(解决容器访问互联网)
容器的172.17.0.2属于 Docker 内部网络,外部网络无法直接识别和路由。通过NAT(网络地址转换),把容器的内部地址转换成宿主机可以对外通信的公网/局域网 IP 地址。
Docker 网络底层完整链路:
容器之间通信:容器 A -> eth0 -> veth pair -> Linux Bridge -> veth pair -> eth0 -> 容器 B
容器访问互联网:容器 -> veth -> docker0 -> 路由 -> NAT -> 宿主机网卡 -> 互联网
七、 核心知识总结(记住这四句话)
网络模式:决定容器使用什么网络环境(
bridge/host/none/container)。端口映射:解决外部如何访问容器(
-p 宿主机端口:容器端口)。跨容器通信:通过自定义网络 + Docker DNS,用容器名/服务名互相访问,规避 IP 变动带来的问题。
底层原理:Docker 利用 Linux 的 Network Namespace(网络隔离)、veth pair(虚拟网卡对)、Linux Bridge(虚拟交换机)、路由和 NAT(地址转换)等底层网络能力,组合构建了容器的网络世界。