Docker 网络详解:(三)四大网络模式

大家好,我是费益洲。上一篇文章Docker 网络详解:(二)虚拟网络环境搭建与测试详细介绍了如何使用 Linux Bridge、veth pair 和 Network Namespace 模拟搭建 Docker 的虚拟网络环境。上一篇文章是本文的基础,未观看的同志请移步上篇文章。本文将不再赘述基础知识,主要介绍 Docker 的四大网络模式。

1. 简介

Docker 的网络模式决定了容器如何与外界及其他容器进行网络通信,了解这些模式有助于根据实际需求为容器选择合适的网络配置。Docker 主要提供了四种网络模式:​​Bridge​​、​​Host​​、​Container 和 ​​None,核心区别如下所示:

网络模式 本质
Bridge 默认模式。通过虚拟网桥 docker0 连接容器,容器有独立网络命名空间和 IP
Host 容器直接使用宿主机的网络命名空间,没有独立网络栈
Container 新容器与指定容器共享网络命名空间(IP 和端口范围)
None 不为容器配置任何网络接口,只有回环接口 lo

💡 Docker 在安装完成后,首次启动 Docker 守护进程(dockerd)时,就会自动创建三个默认网络:Bridge、Host、None,以及 Bridge 模式所需要的 Linux Bridge docker0。

可以使用命令行docker network ls列出这些网络:

bash 复制代码
[root@master01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
f86f333f713f   bridge    bridge    local
f2f2f0be0448   host      host      local
d0a0462ce3e8   none      null      local

2. Bridge 模式

Bridge 模式是 Docker 的默认网络模式,当创建一个使用 Bridge 网络模式的容器时,Docker 的守护进程会为该容器创建一对 veth pair。这对 veth pair 的其中一端会被连接到 docker0 网桥,另外一端会防止在容器所在的 Network Namespace 内,同时 Docker 会从 docker0 的子网中为该容器分配一个 IP 地址,并设置 docker0 的地址为容器的默认网关。通过这种范式,主机就可以跟容器通信,容器之间也可以互相通信。Bridge 网络模式的网络拓扑如下所示:

💡 如果在创建容器是不明确指定该容器的网络模式则采用 Bridge 模式。当然 Bridge 模式也可以使用--net=bridge指定,但一般都忽略不写。

2.1 创建与使用

1️⃣ 创建网络

使用docker network create命令创建网络。eg:创建一个名为bridge-1,子网为192.168.100.0/24,网关为192.168.100.1的 Bridge 网络:

bash 复制代码
[root@master01 ~]# docker network create --driver bridge --subnet 192.168.100.0/24 --gateway 192.168.100.1 bridge-1
310c1bb719fbe3651de191dd87762f7e3949acf2453ce1cc80442a4c9b0d459c

如果不需要精细控制 IP 地址,最简单的命令是:

bash 复制代码
[root@master01 ~]# docker network create bridge-1

2️⃣ 验证网络

使用docker network ls查看所有 Docker 网络,确认新网络已创建:

bash 复制代码
[root@master01 ~]# docker network ls
NETWORK ID     NAME       DRIVER    SCOPE
f86f333f713f   bridge     bridge    local
310c1bb719fb   bridge-1   bridge    local
f2f2f0be0448   host       host      local
d0a0462ce3e8   none       null      local

可以使用docker network inspect <network-name>查看网络的详细信息:

bash 复制代码
[root@master01 ~]# docker network inspect bridge-1

3️⃣ 创建容器时指定网络

创建容器时,使用--network参数指定该容器连接到指定的网络:

bash 复制代码
[root@master01 ~]# docker run -d --name my-nginx --network bridge-1 nginx

4️⃣ 断开连接并删除网络

从网络中断开一个容器:

bash 复制代码
[root@master01 ~]# docker network disconnect bridge-1 my-nginx

删除网络:

bash 复制代码
[root@master01 ~]# docker network rm bridge-1
bridge-1

删除网络还可以使用docker netwrok prune命令,但是此命令会删除所有未被容器使用的网络,需要谨慎使用。

2.2 容器网络联通性

使用过程中,一般都是使用默认网桥 docker0,此时我们也使用 docker0 来试验容器的网络联通性。

使用默认网桥 docker0 创建一个 http server 容器,并将端口映射到宿主机:

bash 复制代码
[root@master01 test-server]# docker run -d -p 8080:8080 --name test-server feiyizhou/test-server:latest
a25b84a50e495727dda805371533b3be411a8e6c373773c2a45c637b746e7078

feiyizhou/test-server:latest 是我自己写的一个简单的 http 服务镜像,项目地址:feiyizhou/test-server

此时可以看到 docker0 网桥上已经连接了 veth pair 的一端:

bash 复制代码
[root@master01 ~]# brctl show
bridge name	bridge id		    STP enabled	interfaces
docker0		8000.02427b64190e	no		    veth521dec0

查看当前容器的 ip:

bash 复制代码
[root@master01 ~]# docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test-server
172.17.0.2

2.2.1 宿主机访问容器

由于 Docker 启动时,会为 docker0 分配 IP 并启动,并且会在 route 表里生成一条路由信息。使得宿主机可以直接连通容器网络:

bash 复制代码
[root@master01 ~]# ping -c 1 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.071 ms

--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.071/0.071/0.071/0.000 ms

服务也能够正常响应:

bash 复制代码
[root@master01 ~]# curl 172.17.0.1:8080
Hello world!

通过端口映射访问容器服务

当在创建容器时,使用了-p--publish,Docker 会通过配置 iptables 规则实现端口转发。这个过程涉及复杂的网络地址转换(NAT)和流量控制机制。以下是 Docker 端口映射转发的完整规则。

NAT 表规则

NET 表中,与 Docker 流量重定向相关的规则如下所示。其中配置 NAT 表 PREROUTING 链的目的主要是做目标地址转换,将目标为宿主机 8080 端口的流量重定向到对应容器的 IP:8080 端口,而配置 POSTROUTING 链的作用则是容器访问外部网络时,将源 IP 伪装成宿主机 IP。

bash 复制代码
[root@master01 ~]# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:8080

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:8080
...

FILTER 表规则

FILTER 表中,与 Docker 流量重定向相关的规则如下所示。配置 FILTER 表的目的主要是允许流量从宿主机转发到容器,并确保只允许目标为容器 IP 的流量通过。

bash 复制代码
[root@master01 ~]# iptables -L -n
...
Chain FORWARD (policy DROP)
target     prot opt source               destination
DOCKER-USER  all  --  0.0.0.0/0            0.0.0.0/0
DOCKER-ISOLATION-STAGE-1  all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
...
Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:8080
...

外部通过 Docker 端口映射访问容器服务时,流量路径如下所示:

2.2.2 容器访问宿主机

查看容器中的路由信息:

bash 复制代码
[root@master01 ~]# docker exec -it test-server ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 scope link  src 172.17.0.2

可以看到,所有目的地址不在当前网络(172.17.0.0/16)的流量,都发送到网关 172.17.0.1(即 docker0 网桥),然后由宿主机进行进一步的路由或 NAT 转发。此时容器到宿主机的网络是联通的:

bash 复制代码
[root@master01 ~]# docker exec -it test-server ping -c 1 172.16.200.18
PING 172.16.200.18 (172.16.200.18): 56 data bytes
64 bytes from 172.16.200.18: seq=0 ttl=64 time=0.099 ms

--- 172.16.200.18 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.099/0.099/0.099 ms

🔍 路由信息中的第二条,表明所有发送到 172.17.0.0/16 网段的流量,都直接通过 eth0 发送,而不需要经过网关。因为容器和 docker0 网桥以及同一网桥下的其他容器都在这个子网内,属于二层可达,所以直接通过 eth0 发送即可。

3. Host 模式

Host 网络模式的原理是容器与宿主机共享同一个 Network Namespace,即创建容器时不会再单独为容器创建新的 Network Namespace,这就导致了如下特点:

  • 无独立网络栈:容器不会虚拟出自己的网卡(如 eth0),也不会分配独立的 IP 地址(即没有 Docker 常见的 Container-IP,如 172.17.0.x)。它直接使用宿主机的所有网络接口、IP 地址、路由表以及 iptables 规则

  • 端口直接暴露:容器内进程绑定的任何端口都会直接在宿主机上打开。例如,容器内运行一个 Nginx 并监听 80 端口,那么该服务会立即占用宿主机的 80 端口

  • 性能优势:由于省去了网络地址转换(NAT)和 Docker 网桥(如 docker0)的转发开销 ​​,网络性能通常是最佳的,几乎与在宿主机本地运行应用无异

Host 网络模式的网络拓扑如下所示:

3.1 使用

使用 Host 模式非常简单,只需要在创建容器时使用--network host参数即可:

bash 复制代码
[root@master01 ~]# docker run -d --name test-server-host --network host feiyizhou/test-server:latest
eeb8a8786927d559b21865a0a7ffc1e770537061dd804c004bb994b317f2133e

⚠️ 由于 Host 模式与宿主机共享 Network Namespace 的特点,在创建容器前,需要确定容器使用的端口未被占用。

4. Container 模式

Container 网络模式的原理是新创建的容器和已经存在的容器共享同一个 Network Namespace,需要注意的是,Container 模式共享的 Network Namespace 和宿主机的 Network Namespace 是互相隔离的 Network Namespace。多个容器共享同一个 Network Namespace,这就导致了如下特点:

  • 共享网络栈:新创建的容器不会拥有自己独立的网络栈(如独立的网卡、IP 地址、路由表等),而是与另一个指定的容器共享所有这些网络配置

  • 隔离性:多个容器值共享了同一个 Network Namespace,但其他的 Namespace 还是互相隔离的,每个容器会有自己独立的文件系统、进程列表等

  • 通信方式:多个容器之间的网络通信可以直接通过本地回环网卡设备进行。但和宿主机的通信都会通过同一 IP 地址及配置

Container 网络模式的网络拓扑如下所示:

4.1 使用

1️⃣ 创建父容器

bash 复制代码
[root@master01 ~]# docker run -d --name nginx nginx:latest
23e58ee3d4c17db15dfb188d905c217a496b5b80ee1d5f99436f52d92b3a0d31

2️⃣ 创建子容器并指定共享父容器 Network Namespace

此时使用 Container 模式创建新的容器,使用--network container:<name|id>参数即可:

bash 复制代码
[root@master01 ~]# docker run -d --name test-server --network container:nginx feiyizhou/test-server:latest
b1dc5a841ee006288d8b8cbb8f17a9487ec4866f4954e2fc79cf39008d6a2ea6

⚠️ 注意事项

  • 端口冲突 ​​:由于共享 IP 和端口范围,​​ 两个容器不能监听同一个端口 ​​,否则后启动的容器会因端口被占用而失败

  • 依赖关系:以 Container 模式启动的容器 ​​ 依赖于它所共享网络的那个容器 ​​。如果被依赖的容器停止,那么依赖它的容器也会失去网络连接

5. None 模式

None 网络模式是 Docker 中最简单、最隔离的网络模式。它放弃了所有的自动网络配置 ​​,换来了极致的隔离性和安全性 ​​,并为自定义网络配置提供了最大的灵活性。

None 网络模式下,容器会拥有自己独立的 Network Namespace,但 Docker 不会为该容器进行任何网络配置,这就导致容器内部:

  • 除本地回环 lo 外,没有任何网络设备

  • 没有路由信息

  • 无法与外界(包括其他容器、宿主机和外部网络)进行任何网络通信

5.1 使用

此时使用 None 网络模式创建新的容器,使用--network none参数即可:

bash 复制代码
[root@master01 ~]# docker run -d --name test-server --network none feiyizhou/test-server:latest
594472eae2e5d71f265f6efcdfda8d5bf0d160fc42356f9d5e557db390baeb11
相关推荐
九河云4 小时前
传统数据安全措施与云计算数据安全的区别
运维·服务器·数据库·云计算
华仔啊5 小时前
Docker入门全攻略:轻松上手,提升你的项目效率
后端·docker·容器
kymix5 小时前
vscode 远程管理docker时,提示权限不足无法获取容器列表问题
ide·vscode·docker
Giser探索家5 小时前
建筑物孪生模型:重构空间数字化格局,赋能智慧城市
大数据·人工智能·算法·重构·分类·云计算·智慧城市
胡斌附体6 小时前
离线docker安装jupyter(python网页版编辑器)
python·docker·jupyter·image·tar·save
想躺平的咸鱼干14 小时前
远程MCP的调用和阿里云生态的知识库和工作流的使用
阿里云·大模型·云计算·idea·格式化输出·mcp
洛阳纸贵Coco.Leo.YI16 小时前
10分钟在Windows11下Ubuntu内安装docker-Version28.51
linux·ubuntu·docker
小小星球之旅17 小时前
SpringBoot后端实现阿里云oss上传文件
阿里云·云计算
java_logo20 小时前
n8n Docker 部署手册
运维·docker·容器