文章目录
- Docker:网络
-
- [Docker 网络类型及适用场景](#Docker 网络类型及适用场景)
- [深入理解 Bridge 模式](#深入理解 Bridge 模式)
-
- [Bridge 网络的工作原理](#Bridge 网络的工作原理)
- [Bridge 网络的特点](#Bridge 网络的特点)
- [实际演示 Bridge 网络](#实际演示 Bridge 网络)
- 自定义容器网络
-
- [创建自定义 Bridge 网络](#创建自定义 Bridge 网络)
- 为现有容器连接/断开网络
- 理解容器之间的连通性
- 容器通信的三种方式
-
- IP地址通信
- [Docker DNS Server](#Docker DNS Server)
- [joined 容器](#joined 容器)
- 容器如何访问外部世界
- 外部世界如何访问容器
- 常见问题排查指南
- 总结要点
Docker:网络
Docker 网络类型及适用场景
bash
# 查看Docker提供的所有网络
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
c7647d1ba21b bridge bridge local
bcd91df332f4 host host local
b2c1b8659b9e none null local
| 网络类型 | 说明 | 适用场景 |
|---|---|---|
| bridge | 默认网络,Docker启动时自动创建 | 默认选择,单机环境,容器间隔离通信 |
| host | 直接使用宿主机网络 | 高性能需求,如网络测试工具 |
| none | 无网络,完全隔离 | 安全性要求极高,离线数据处理 |
下面分别讨论他们
none网络
none网络的driver类型是null,IPAM字段为空。挂在none网络上的容器只有lo,无法与外界通信。
容器创建时,可以通过 --network=none 指定使用 none 网络。

使用场景:
封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用 none 网络。
比如某个容器的唯一用途是生成随机密码,就可以放到 none 网络中避免密码被窃取。
host网络
挂在host网络上的容器共享宿主机的network namespace。即容器的网络配置与host网络配置完全一样。
可以通过 --network=host 指定使用 host 网络。

使用场景:
直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。Docker host 的另一个用途是让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案
深入理解 Bridge 模式
应用最广泛也是默认的 bridge 网络。
Bridge 网络的工作原理
Docker 安装时会创建一个 命名为 docker0 的 linux bridge,实际上它是 Linux 的一个 bridge (网桥),可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定--network,创建的容器默认都会挂到 docker0 上。
Docker 就创建了在主机和所有容器之间一个虚拟共享网络 当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包), 这对接口
- 一端在容器内即 eth0;
- 另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)
通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

Bridge 网络的特点
- ✅ 容器间可以相互通信(在同一bridge上)
- ✅ 容器可以访问外网(通过NAT)
- ❌ 外网不能直接访问容器(需要端口映射)
- ✅ 支持自定义IP地址范围
实际演示 Bridge 网络
先配置yum源用于安装软件
bash
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# vim cloud.repo
[root@docker yum.repos.d]# cat cloud.repo
[centos-openstack-victoria]
name=CentOS 8 - OpenStack victoria
baseurl=https://mirrors.aliyun.com/centos-vault/8-stream/cloud/x86_64/openstack-victoria/
enabled=1
gpgcheck=0
[root@docker yum.repos.d]# yum install -y bridge-utils
[root@docker yum.repos.d]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02423e94ecd7 no
现在可以发现 docker0 上没有任何其他网络设备,我们创建一个来看看有什么变化
bash
[root@docker ~]# docker run -itd --name busybox1 busybox
8b4f5b920c986ed772d959dc96a06e2269cb21a500c5a059e7de738eb08c0b26
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02423e94ecd7 no veth98cfaef
一个新的网络接口 veth98cfaef 被挂到了 docker0 上,veth98cfaef就是新创建容器的虚拟网卡。
下面看一下容器的网络配置。
bash
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
# 容器里的网卡是4号网卡名字叫eth0,对面是5号网卡
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
在容器里我们看见的网卡是 eth0@if5而不是veth98cfaef?
实际上eth0@if5 和 veth98cfaef 是一对veth pair。veth pair 是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0@if5)在容器中,另一头(veth98cfaef)挂在网桥 docker0 上,其效果就是将 eth0@if5 也挂在了 docker0 上。
在宿主机上查看IP地址,可以证明Docker0上的vethddb2744和容器中的eth0@if25 是一对
bash
[root@docker ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
... ...
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:3e:94:ec:d7 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:3eff:fe94:ecd7/64 scope link
valid_lft forever preferred_lft forever
# 在宿主机看到有块网卡:`5: veth98cfaef@if4`
# 证明了容器busybox1里的`eth0`连接到了docker0网桥的`veth98cfaef`
5: veth98cfaef@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether b2:a1:33:fb:65:63 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::b0a1:33ff:fefb:6563/64 scope link
valid_lft forever preferred_lft forever
回到容器的网络来看,eth0@if5 网卡已经配置了IP 172.17.0.2/16 为什么是这个网段呢?让我们通过 docker network inspect bridge 看一下 bridge 网络的配置信息:
bash
[root@docker ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "7a21e27314b9bbf1a0be7a396592f21384af82371ac61294c93feeefcbe379b4",
"Created": "2025-12-14T19:37:51.138840458+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"8b4f5b920c986ed772d959dc96a06e2269cb21a500c5a059e7de738eb08c0b26": {
"Name": "busybox1",
"EndpointID": "3fc7ccd36e171dfab0d304284acf522fa71b4437228f400d8530055b0ef979aa",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
原来 bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。这个网关在哪儿呢?大概你已经猜出来了,就是 docker0。
bash
[root@docker ~]# ip a | grep docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
所以当前的容器网络拓扑图是这样的:

容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以供容器使用。
除了 none, host, bridge 这三个自动创建的网络,用户也可以根据业务需要创建 user-defined 网络
自定义容器网络
Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建跨主机的网络,我们后面有章节单独讨论。
创建自定义 Bridge 网络
bash
# 1. 创建自定义bridge网络
$ docker network create \
--driver bridge \
--subnet=192.168.100.0/24 \
--gateway=192.168.100.1 \
--opt "com.docker.network.bridge.name"="mybridge" \
mynet
# 参数说明:
# --driver:网络驱动类型
# --subnet:子网段
# --gateway:网关地址
# --opt:额外选项
# 2. 查看创建的网络
$ docker network ls
$ docker network inspect mynet
# 3. 使用自定义网络运行容器
$ docker run -d --name app1 --network mynet nginx
$ docker run -d --name app2 --network mynet nginx
# 4. 容器会获得192.168.100.x的IP
$ docker inspect app1 | grep IPAddress
我们可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:
bash
[root@docker ~]# docker network create --driver bridge my_net
c997ae1668421e2bc6d725ac60610416e7020f35328de13547467deba8ac3d21
查看一下当前 host 的网络结构变化
bash
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-c997ae166842 8000.02420c198c24 no
docker0 8000.02423e94ecd7 no veth98cfaef
新增了一个网桥 br-c997ae166842,这里 br-c997ae166842 正好是新建 bridge 网络 my_net 的短 id。执行 docker network inspect 查看一下 my_net 的配置信息:
bash
[root@docker ~]# docker network inspect my_net
[
{
"Name": "my_net",
"Id": "c997ae1668421e2bc6d725ac60610416e7020f35328de13547467deba8ac3d21",
"Created": "2025-12-14T20:16:37.710331443+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段。
我们可以自己指定 IP 网段吗?
答案是:可以。
只需在创建网段时指定 --subnet 和 --gateway 参数:
bash
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
a15e1ccf58d2faf31dd7088abed414f46d0bfe612ce9732ad64a77a5470114d3
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-a15e1ccf58d2 8000.024226a832ff no #my_net2
br-c997ae166842 8000.02420c198c24 no #my_net
docker0 8000.02423e94ecd7 no veth98cfaef
[root@docker ~]# docker network inspect my_net2
[
{
"Name": "my_net2",
"Id": "a15e1ccf58d2faf31dd7088abed414f46d0bfe612ce9732ad64a77a5470114d3",
"Created": "2025-12-14T20:23:53.334856989+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.22.16.0/24",
"Gateway": "172.22.16.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
容器要使用新的网络,需要在启动时通过 --network 指定:
bash
[root@docker ~]# docker run -it --network=my_net2 --name busybox2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.2/24 brd 172.22.16.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ctrl+P,ctrl+q退出容器
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-a15e1ccf58d2 8000.024226a832ff no vethfbda331 #my_net2上新增的接口vethfbda331连接容器busybox2
br-c997ae166842 8000.02420c198c24 no
docker0 8000.02423e94ecd7 no veth98cfaef
容器分配到的 IP 为 172.22.16.2。
到目前为止,容器的 IP 都是 docker 自动从 subnet 中分配,我们能否指定一个静态 IP 呢?
答案是:可以,通过--ip指定。
bash
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:08 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.8/24 brd 172.22.16.255 scope global eth0
valid_lft forever preferred_lft forever
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-a15e1ccf58d2 8000.024226a832ff no veth2119a95 #veth2119a95是连接busybox3
vethfbda331
br-c997ae166842 8000.02420c198c24 no
docker0 8000.02423e94ecd7 no veth98cfaef
注意:只有使用
--subnet创建的网络才能指定静态 IP。my_net 创建的时候没有指定 subnet ,如果指定静态ip 会报错
bash[root@docker ~]# docker run -it --network=my_net --ip 172.18.0.8 busybox docker: Error response from daemon: invalid config for network my_net: invalid endpoint settings: user specified IP address is supported only when connecting to networks with user configured subnets. See 'docker run --help'.
当前的docker host 和容器的网络拓扑图是这样的:

为现有容器连接/断开网络
bash
# 将已有容器连接到新网络
$ docker network connect mynet comtainer1
# 断开容器与网络的连接
$ docker network disconnect bridge comtainer1
# 一个容器可以连接多个网络
$ docker inspect comtainer1 # 查看所有网络接口
理解容器之间的连通性
网络连通性规则表
| 场景 | 是否可通信 | 原因 |
|---|---|---|
| 同bridge网络的容器之间 | ✅ | 在同一二层网络 |
| 不同bridge网络的容器之间 | ❌ | 网络隔离,需要路由器 |
| 容器访问宿主机 | ✅ | docker0网桥连接宿主机 |
| 宿主机访问容器 | ✅ | 通过docker0网桥 |
| 容器访问另一个bridge的容器 | ❌ | 需要将容器加入同一网络 |
现在我们来讨论上面几个容器之间的连通性
目前,busybox2,busybox3 容器都挂在 my_net2 上,应该能够互通,我们来验证一下
bash
[root@docker ~]# docker exec -it busybox2 sh
/ # ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:AC:16:10:02
inet addr:172.22.16.2 Bcast:172.22.16.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1532 (1.4 KiB) TX bytes:0 (0.0 B)
/ # ping -c 3 172.22.16.8
PING 172.22.16.8 (172.22.16.8): 56 data bytes
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.124 ms
64 bytes from 172.22.16.8: seq=1 ttl=64 time=0.098 ms
64 bytes from 172.22.16.8: seq=2 ttl=64 time=0.105 ms
--- 172.22.16.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.098/0.109/0.124 ms
# ping my_net2网关地址
/ # ping -c 3 172.22.16.1
PING 172.22.16.1 (172.22.16.1): 56 data bytes
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.114 ms
64 bytes from 172.22.16.1: seq=1 ttl=64 time=0.091 ms
64 bytes from 172.22.16.1: seq=2 ttl=64 time=0.094 ms
--- 172.22.16.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.091/0.099/0.114 ms
可见同一网络中的容器、网关之间都是可以通信的。
my_net2 与默认 bridge 网络(docker0)能通信吗?
从拓扑图可知,两个网络属于不同的网桥,应该不能通信,我们通过实验验证一下,让 busybox2 容器 ping buxybox1 容器:
bash
/ # ping -c 3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
/ #
那么,不同的网络如果加上路由应该就可以通信了吧?
确实,如果 host 上对每个网络的都有一条路由,同时操作系统上打开了 ip forwarding,host 就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。下面我们来看看 docker host 满不满足这些条件呢?
bash
# 查看 host 上的路由表
[root@docker ~]# ip r
default via 192.168.108.2 dev ens160 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-c997ae166842 proto kernel scope link src 172.18.0.1 linkdown
172.22.16.0/24 dev br-a15e1ccf58d2 proto kernel scope link src 172.22.16.1
192.168.108.0/24 dev ens160 proto kernel scope link src 192.168.108.30 metric 100
172.17.0.0/16 和 172.22.16.0/24 两个网络的路由都定义好了。
bash
# 再看看 ip forwarding
[root@docker ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
条件都满足,为什么不能通行呢?
我们还得看看路由表 iptables:
bash
[root@docker ~]# iptables-save
# Generated by iptables-save v1.8.5 on Sun Dec 14 20:53:32 2025
*filter
:INPUT ACCEPT [2934:3722546]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [2011:161365]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o br-a15e1ccf58d2 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-a15e1ccf58d2 -j DOCKER
-A FORWARD -i br-a15e1ccf58d2 ! -o br-a15e1ccf58d2 -j ACCEPT
-A FORWARD -i br-a15e1ccf58d2 -o br-a15e1ccf58d2 -j ACCEPT
-A FORWARD -o br-c997ae166842 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-c997ae166842 -j DOCKER
-A FORWARD -i br-c997ae166842 ! -o br-c997ae166842 -j ACCEPT
-A FORWARD -i br-c997ae166842 -o br-c997ae166842 -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-a15e1ccf58d2 ! -o br-a15e1ccf58d2 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i br-c997ae166842 ! -o br-c997ae166842 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-a15e1ccf58d2 -j DROP `看这里`
-A DOCKER-ISOLATION-STAGE-2 -o br-c997ae166842 -j DROP `看这里`
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Sun Dec 14 20:53:32 2025
# Generated by iptables-save v1.8.5 on Sun Dec 14 20:53:32 2025
*security
:INPUT ACCEPT [2928:3721172]
:FORWARD ACCEPT [6:504]
:OUTPUT ACCEPT [2011:161365]
COMMIT
# Completed on Sun Dec 14 20:53:32 2025
# Generated by iptables-save v1.8.5 on Sun Dec 14 20:53:32 2025
*raw
:PREROUTING ACCEPT [2943:3723302]
:OUTPUT ACCEPT [2011:161365]
COMMIT
# Completed on Sun Dec 14 20:53:32 2025
# Generated by iptables-save v1.8.5 on Sun Dec 14 20:53:32 2025
*mangle
:PREROUTING ACCEPT [2943:3723302]
:INPUT ACCEPT [2934:3722546]
:FORWARD ACCEPT [9:756]
:OUTPUT ACCEPT [2011:161365]
:POSTROUTING ACCEPT [2017:161869]
COMMIT
# Completed on Sun Dec 14 20:53:32 2025
# Generated by iptables-save v1.8.5 on Sun Dec 14 20:53:32 2025
*nat
:PREROUTING ACCEPT [13:1898]
:INPUT ACCEPT [3:188]
:POSTROUTING ACCEPT [28:1682]
:OUTPUT ACCEPT [27:1598]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.22.16.0/24 ! -o br-a15e1ccf58d2 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-c997ae166842 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i br-a15e1ccf58d2 -j RETURN
-A DOCKER -i br-c997ae166842 -j RETURN
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed on Sun Dec 14 20:53:32 2025
iptables DROP 掉了网桥 docker0 与 br-ec761bc51778(my_net2) 之间双向的流量。
bash
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-a15e1ccf58d2 8000.024226a832ff no veth2119a95
vethfbda331
br-c997ae166842 8000.02420c198c24 no
docker0 8000.02423e94ecd7 no veth98cfaef
从规则的命名 DOCKER-ISOLATION 可知 docker 在设计上就是要隔离不同的 netwrok。
那么,怎么样才能让 busybox1与busybox2 通信呢?
答案是:为 busybox1 容器添加一块 my_net2 的网卡。这个可以通过docker network connect 命令实现。
bash
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5fd01690769 busybox "sh" 27 minutes ago Up 27 minutes busybox3
3d01847e1758 busybox "sh" 29 minutes ago Up 29 minutes busybox2
8b4f5b920c98 busybox "sh" About an hour ago Up About an hour busybox1
[root@docker ~]# docker network connect my_net2 busybox1
我们在busybox1 容器中查看一下网络配置
bash
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
12: eth1@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:03 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.3/24 brd 172.22.16.255 scope global eth1
valid_lft forever preferred_lft forever
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-a15e1ccf58d2 8000.024226a832ff no veth2119a95 #busybox3
veth9d5661d #busybox1
vethfbda331 #busybox2
br-c997ae166842 8000.02420c198c24 no
docker0 8000.02423e94ecd7 no veth98cfaef
busybox1 容器中增加了一个网卡 eth1,分配了 my_net2 的 IP 172.22.16.3。现在 busybox2 应该能够访问busybox1 了,验证一下:
bash
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.118 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.101 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.106 ms
--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.101/0.108/0.118 ms
所以,当前的容器网络拓扑应该是这样的

容器通信的三种方式
容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。
IP地址通信
从上一个的例子可以得出这样一个结论:两个容器要能通信,必须要有属于同一个网络的网卡。
具体做法是在容器创建时通过 --network 指定相应的网络,或者通过 docker network connect 将现有容器加入到指定网络。
缺点:IP地址可能变化,不实用
Docker DNS Server
虽然ip地址通信,满足了通信需求,但是不够灵活,因为我们在配置之前是无法确定ip的,部署之后在确定ip比较麻烦,对于这个问题,可以通过docker自带的DNS 服务解决
从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过"容器名"通信。方法很简单,只要在启动时用 --name 为容器命名就可以了。
例如:
启动两个容器 bbox1 和 bbox2:
bash
[root@docker ~]# docker run -itd --network my_net2 --name bbox1 busybox
[root@docker ~]# docker run -itd --network my_net2 --name bbox2 busybox
然后,bbox2 就可以直接ping 到 bbox1了:
bash
[root@docker ~]# docker exec -it bbox2 sh
/ # ping -c 3 bbox1
PING bbox1 (172.22.16.2): 56 data bytes
64 bytes from 172.22.16.2: seq=0 ttl=64 time=0.108 ms
64 bytes from 172.22.16.2: seq=1 ttl=64 time=0.106 ms
64 bytes from 172.22.16.2: seq=2 ttl=64 time=0.099 ms
--- bbox1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.099/0.104/0.108 ms
但是,docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。
joined 容器
joined 容器是另一种实现容器间通信的方式。
joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。请看下面的例子:
先创建一个 httpd 容器,名字为 web1。
bash
[root@docker ~]# docker run -it -d --name web1 httpd
0c3cc4832c1479cb2f17368784b7e69a721595d4fb93f9f85423045b4eeb0f13
我们一起来看一下web1 的网络
bash
[root@docker ~]# docker exec -it web1 bash
root@0c3cc4832c14:/usr/local/apache2# apt-get update
root@0c3cc4832c14:/usr/local/apache2# apt-get install iproute2 -y
root@0c3cc4832c14:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
然后创建 busybox 容器并通过 --network=container:web1 指定 jointed 容器为 web1:
bash
[root@docker ~]# docker run -it --network container:web1 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
注意 busybox 容器中的网络配置信息,可以发现 busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈。busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。
bash
/ # wget 127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
saving to 'index.html'
index.html 100% |************************************************************************************| 191 0:00:00 ETA
'index.html' saved
/ # cat index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>It works! Apache httpd</title>
</head>
<body>
<p>It works!</p>
</body>
</html>
joined 容器非常适合以下场景:
- 不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。
- 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。
容器如何访问外部世界
在我们当前的实验环境下,docker host 是可以访问外网的。
我们来试试容器是否能访问外网
bash
[root@docker ~]# docker run -it --name test1 busybox
/ #
/ # ping -c 3 www.baidu.com
PING www.baidu.com (153.3.238.28): 56 data bytes
64 bytes from 153.3.238.28: seq=0 ttl=127 time=18.799 ms
64 bytes from 153.3.238.28: seq=1 ttl=127 time=37.631 ms
64 bytes from 153.3.238.28: seq=2 ttl=127 time=90.365 ms
--- www.baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 18.799/48.931/90.365 ms
可见,容器默认就能访问外网。
请注意:这里外网指的是容器网络以外的网络环境,并非特指 internet。
现象很简单,但更重要的:我们应该理解现象下的本质。

原理:NAT(网络地址转换)
容器(172.17.0.2) → docker0 → 宿主机eth0 → 互联网
请求源IP NAT转换 路由转发
172.17.0.2 → 宿主机IP → 目标服务器
外部世界如何访问容器
端口映射
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射端口:
bash
# 将容器端口映射到宿主机端口
$ docker run -d -p 8080:80 --name web nginx
# -p 宿主机端口:容器端口
# 访问:http://宿主机IP:8080
# 映射多个端口
$ docker run -d -p 8080:80 -p 8443:443 nginx
# 指定宿主机IP
$ docker run -d -p 192.168.1.100:8080:80 nginx
# 随机映射端口(该随机指宿主机端口随机)
$ docker run -d -p 80 nginx
$ docker port <容器名> # 查看映射的端口
容器启动后,可通过 docker ps 或者 docker port 查看到 host 映射的端口。
bash
[root@docker ~]# docker run -d -p 80 httpd
15ecb2f72463fd6b8552b321570c7f4d3f7e361e6b1a5184babdb44ec22b69f0
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15ecb2f72463 httpd "httpd-foreground" 5 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp, :::32768->80/tcp flamboyant_torvalds
[root@docker ~]# docker port 15ecb2f72463
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768
在上面的例子中,httpd 容器的 80 端口被映射到 host 32768 上,这样就可以通过 <host ip>:<32768> 访问容器的 web 服务了。
bash
[root@docker ~]# curl 192.168.108.30:32768
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>It works! Apache httpd</title>
</head>
<body>
<p>It works!</p>
</body>
</html>

常见问题排查指南
问题1:容器无法访问外网
bash
# 检查步骤:
1. 检查宿主机网络:ping baidu.com
2. 检查Docker服务:systemctl status docker
3. 检查容器DNS:docker exec <容器> cat /etc/resolv.conf
4. 检查iptables:sudo iptables -L -n
问题2:容器间无法通信
bash
# 检查步骤:
1. 确认容器在同一网络:docker network inspect <网络名>
2. 检查防火墙规则
3. 尝试使用IP而非容器名测试
4. 查看容器日志:docker logs <容器>
问题3:端口映射不生效
bash
# 检查步骤:
1. 确认端口是否被占用:netstat -tlnp | grep 8080
2. 检查防火墙是否开放端口
3. 确认映射命令正确:docker port <容器>
4. 重启Docker服务:systemctl restart docker
总结要点
| 概念 | 要点 | 命令 |
|---|---|---|
| 查看网络 | 列出所有网络 | docker network ls |
| 创建网络 | 自定义bridge | docker network create |
| 连接网络 | 容器加入网络 | docker network connect |
| 端口映射 | 暴露容器服务 | docker run -p |
| 容器通信 | 使用容器名 | 需在同一自定义网络 |
| 查看详情 | 网络详细信息 | docker network inspect |
bash
# 1. 查看docker0网桥信息
$ ip addr show docker0
# 输出:inet 172.17.0.1/16
# 2. 运行容器(默认使用bridge网络)
$ docker run -d --name web1 nginx
$ docker run -d --name web2 nginx
# 3. 查看容器IP地址
$ docker inspect web1 | grep IPAddress
# 输出:"IPAddress": "172.17.0.2"
$ docker inspect web2 | grep IPAddress
# 输出:"IPAddress": "172.17.0.3"
# 4. 测试容器间通信
$ docker exec web1 ping 172.17.0.3
# ✅ 可以ping通
# 5. 查看网络详细信息
$ docker network inspect bridge