☰
Docker 网络(二)Bridge 模式详解
2026/10/3 8:41:59 网站建设 项目流程

在 Bridge 模式下,Docker 除了分配隔离的网络命名空间之外,还会为所有的容器设置 IP 地址。当 Docker 服务器在主机上启动之后会创建新的虚拟网桥 docker0,随后在该主机上启动的全部服务在默认情况下都会与该网桥相连。

docker0 网桥使用 brctl show 命令可以查看到,此时系统没有容器运行:

root@docker-host:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES root@docker-host:~# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242df573fac no root@docker-host:~#

现在运行三个容器,分别是 nginx,redis,mysql:

root@docker-host:~# docker run -d --name nginx -p 8080:80 nginx 56e6a37041cb7478b2f908fa7edb11bc972eee9dbaea475db4f4ec6783b1e43f root@docker-host:~# docker run -d --name redis -p 6379:6379 redis cb57d69b1b9f5a489d32d53bcbae3ddca3823d50fbb4b3891ebbc4290285b468 root@docker-host:~# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=123 -p 3306:3306 mysql 67549d3119b261d58783e6a45d074d7f2b89eb65fc930752d0cbe02707a132c4 root@docker-host:~# root@docker-host:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 56bd0d50081c mysql "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql 9199dd045fd9 redis "docker-entrypoint.s…" 6 seconds ago Up 6 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis af71f1490444 nginx "/docker-entrypoint.…" 9 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx root@docker-host:~#

现在检查网桥和 iptables,注意标注的信息:

root@docker-host:~# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242df573fac no vethf4a4032 vethf5e5a3c vethfab2a5a root@docker-host:~# iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination DOCKER all -- anywhere !localhost/8 ADDRTYPE match dst-type LOCAL Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 anywhere MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:http MASQUERADE tcp -- 172.17.0.3 172.17.0.3 tcp dpt:6379 MASQUERADE tcp -- 172.17.0.4 172.17.0.4 tcp dpt:mysql Chain DOCKER (2 references) target prot opt source destination RETURN all -- anywhere anywhere DNAT tcp -- anywhere anywhere tcp dpt:http-alt to:172.17.0.2:80 DNAT tcp -- anywhere anywhere tcp dpt:6379 to:172.17.0.3:6379 DNAT tcp -- anywhere anywhere tcp dpt:mysql to:172.17.0.4:3306 root@docker-host:~#

可以看出,docker0 为每一个容器分配一个新的 IP 地址并将 docker0 的 IP 地址设置为默认的网关,其拓扑关系如下:比如,mysql 容器的 ip 是 172.17.0.4,Docker 网桥规则会将从任意源发送到当前机器 3306 端口的 TCP 包都转发到172.17.0.4:3306 所在的地址上,如果在当前机器上直接 ping 这个 IP 地址就会发现它是可以访问到的:

root@docker-host:~# ping 172.17.0.4 -c 3 PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data. 64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.086 ms 64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.056 ms 64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.064 ms --- 172.17.0.4 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2046ms rtt min/avg/max/mdev = 0.056/0.068/0.086/0.012 ms root@docker-host:~#

从上述操作我们可以知道 Docker 是如何将容器的内部的端口暴露出来并对数据包进行转发的,当有 Docker 容器需要将服务暴露给宿主机机器时,docker0 就为容器分配一个 ip 地址,同时向 iptables 追加一条新的转发规则。

我们可以通过测试 mysql 服务器是否正常运行来理解上述 Docker 的网络转发过程:

root@docker-host:~# mysqladmin -h 127.0.0.1 -P 3306 -u root -p ping Enter password: mysqld is alive root@docker-host:~#

使用 mysqladmin 客户机在宿主机的命令行中访问 127.0.0.1:3306 地址时,会经过 iptables 的预路由(NAT PREROUTING)将该 ip 定向到了 mysql 容器的 ip 地址 172.17.0.4,重定向过的数据包此时就可以通过 iptables 中的过滤转发(FILTER FORWARD)配置,最终在后路由(NAT POSTROUTING)阶段将容器 ip 地址伪装成主机的 127.0.0.1,此时,虽然从外面看起来请求的是 127.0.0.1:3306,但实际上请求的已经是 Docker 容器暴露出的端口了。

在/sys/class/net目录可以查看到以上的所有网络设备:

root@docker-host:~# ls -l /sys/class/net total 0 lrwxrwxrwx 1 root root 0 Jul 6 23:34 docker0 -> ../../devices/virtual/net/docker0 lrwxrwxrwx 1 root root 0 Jul 6 23:34 ens33 -> ../../devices/pci0000:00/0000:00:11.0/0000:02:01.0/net/ens33 lrwxrwxrwx 1 root root 0 Jul 6 23:33 lo -> ../../devices/virtual/net/lo lrwxrwxrwx 1 root root 0 Jul 7 00:30 vethf4a4032 -> ../../devices/virtual/net/vethf4a4032 lrwxrwxrwx 1 root root 0 Jul 7 00:30 vethf5e5a3c -> ../../devices/virtual/net/vethf5e5a3c lrwxrwxrwx 1 root root 0 Jul 7 00:30 vethfab2a5a -> ../../devices/virtual/net/vethfab2a5a root@docker-host:~#

总之,Docker 通过 Linux 的命名空间实现了网络的隔离,进而又通过 iptables 进行了数据包的转发,从而实现了 Docker 容器独立和完整的网络功能。

需要我把整套 Docker 网络笔记整理成一份完整 markdown 文档吗。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询