docker网络
一、docker网络类型
Docker安装时会自动的在Docker host上创建三种网络,我们可以使用docker netwokr ls查看。这三种网络分别是none网络、host网络、bridge网络,bridge网络是我们在创建容器时默认使用的网络。
docker network ls
NETWORK ID NAME DRIVER SCOPE
aa894a535163 bridge bridge local
e632387f1e35 host host local
53dd0861786d none null local
1.1 None网络
none网络就是什么都没有的网络。在这个网络下的容器除了lo,没有其他任何网卡。容器创建时,可以通过--network=none指定使用none网络,通过下面这个示例可以看出,创建容器时指定容器网络类型为none时,容器内只有一个lo网络。
[root@ldh ~]# docker pull busybox
[root@ldh ~]# docker run --name a1 -it --rm --network=none busybox:latest
/ # 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
none网络是个封闭的网络,使用了这种网络类型的容器无法在网络层被访问。封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。
1.2 Host网络
使用host网络的容器共享Docker host的网络栈,容器的网络配置与Docker host完全一样。可以通过--network=host指定使用host网络。可以通过以下示例看到,创建容器指定容器网络为host时,容器直接共享了Docker host的网络,能够获取到Docker host的网络信息。
[root@ldh ~]# docker run -it --name a1 --rm --network=host busybox:latest
/ # 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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:87:11:e4 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.5/24 brd 192.168.100.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::72b1:63fc:272:c80c/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
link/ether 02:42:27:ce:5b:49 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
直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再使用了。
# 以httpd为例,开启apache服务,占用80端口
yum -y install httpd
systemctl restart httpd
ss -anlt | grep 80
LISTEN 0 128 :::80 :::*
# 可以看到80端口已经被使用
[root@ldh ~]# docker run -itd --name nginx --network=host nginx:latest
e9036ae2d7c4cff020fcb186f9cfadaf3de28fce91597d9b0ae2a8d1aa375dee
[root@ldh ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e9036ae2d7c4 nginx:latest "/docker-entrypoint.…" 24 seconds ago Exited (1) 21 seconds ago nginx
# 可以看到nginx容器没有运行
1.3 Bridge网络
Docker安装时会创建一个命名为docker0的linux bridge。如果不指定--network,创建的容器默认都会挂到docker0上。如下示例,docker0上没有任何其他网络设备。
[root@ldh ~]# yum install bridge-utils
[root@ldh ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024227ce5b49 no
我们新创建一个容器,一个新的网络接口veth...被挂到了docker0上了,veth...就是新创建容器的虚拟网卡。由于在创建容器的时候使用了--rm参数,退出容器时会自动的删除容器,需要开启多个终端进行示例操作。
[root@ldh ~]# docker run -it --name a1 --rm busybox:latest
/ # 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
[root@ldh ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024227ce5b49 no veth1c2b156
容器有一个网卡eth0@if5。实际上eth0@if5和veth...是一对veth pair。veth pair是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一堆网卡,网卡的一头(eth0@if5)在容器中,另一头(veth...)挂在网桥docker0上,其效果就是将eth0@if5也挂在了docker0上。
我们还看到eth0@if5已经配置了IP172.17.0.2,可以通过如下命令查看bridge网络的配置信息
[root@ldh ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "aa894a53516352df029b8dedcd25f8dbbe2c38ea85673cb7b840346ff4ced065",
"Created": "2025-10-10T18:05:20.436250929+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": {
"b4e53552619839017b8102613909db8d78b6eeee2fe5cdaf6fde4f63312a432d": {
"Name": "a1",
"EndpointID": "90bb2c8f8b789dca046e04e58bd94fe03d843c44e5c6b331b625d5401787906d",
"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": {}
}
]
......
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
......
原来bridge网络配置的subnet就是172.17.0.0/16,并且网关是172.17.0.1。容器创建时,Docker会自动从172.17.0.0/16分配一个IP,这里16位的掩码保证有足够多的IP可以供容器使用。
1.4 自定义Bridge网络
之前我们所使用的网络都是安装Docker时默认生成的网络。我们可以通过bridge驱动创建类似前面默认的bridge网络,示例如下
[root@ldh ~]# docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 ldh
0c7bf8cc3db1e2346200f10c1f48ee9192d443e0f73385bd94e9ba74dd1a7367
其中,网络名称为:ldh,类型为:bridge,地址池为:172.20.0.0/16,网关为:172.20.0.1
[root@ldh ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
aa894a535163 bridge bridge local
e632387f1e35 host host local
0c7bf8cc3db1 ldh bridge local
53dd0861786d none null local
[root@ldh ~]# ip a
......
6: br-0c7bf8cc3db1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:4c:b6:2a:7f brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255 scope global br-0c7bf8cc3db1
valid_lft forever preferred_lft forever
创建新的容器,指定使用ldh网络,还可以使用--ip指定容器所使用的IP,这个IP必须是ldh网络地址池中的IP。如果不指定IP,那么ldh网络会自动给容器分配IP。
# 自动分配IP
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh busybox:latest
/ # 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
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 手动指定IP
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh --ip 172.20.0.100 busybox:latest
/ # 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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:64 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.100/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
如果创建一个容器a1,使用默认的bridge网络,再创建第二个容器a2,使用ldh网络,这种情况下两个容器之间不能够直接通讯的。只有指定了相同的网络的容器才能够互通。其实我们可以为容器指定多个网络,实现容器之间的通讯,示例如下,创建新的容器,指定ldh网络,使用connect参数为该容器添加默认bridge网络,或者其他的bridge网络。
# 创建并运行a1容器,使用默认bridge网络
[root@ldh ~]# docker run -it --name a1 --rm busybox:latest
/ # ip a
......
11: eth0@if12: <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
# 创建并运行a2容器,使用ldh网络
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh busybox:latest
/ # ip a
......
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到a1容器与a2容器的IP不是一个网段的,所以不能够直接通讯。
给a2容器添加默认的bridge网络
[root@ldh ~]# docker network connect bridge a2
/ # ip a
......
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
15: eth1@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth1
valid_lft forever preferred_lft forever
这样a2容器就具有一个与a1容器同样网段的IP了,那么它们之间就可以直接通讯了。
二、docker容器之间的访问方式
容器之间访问可以使用以下方式
-
基于IP地址进行访问
-
基于容器名进行访问
-
多个容器共享同一个网络协议栈
注意:只有在同一个Docker网络中的容器才能够互相通讯;只有使用了默认的Bridge网络的容器是无法使用基于容器名的方式进行容器互访的。
2.1 基于IP地址进行访问
创建一个容器a1,使用ldh网络,指定IP为172.20.0.50
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh --ip 172.20.0.50 busybox:latest
创建第二个容器a2,使用ldh网络,指定IP为172.20.0.100
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh --ip 172.20.0.100 busybox:latest
直接ping对方的IP进行访问
/ # ping 172.20.0.100
PING 172.20.0.100 (172.20.0.100): 56 data bytes
64 bytes from 172.20.0.100: seq=0 ttl=64 time=0.140 ms
64 bytes from 172.20.0.100: seq=1 ttl=64 time=0.046 ms
64 bytes from 172.20.0.100: seq=2 ttl=64 time=0.048 ms
64 bytes from 172.20.0.100: seq=3 ttl=64 time=0.047 ms
^C
--- 172.20.0.100 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.046/0.070/0.140 ms
通过以上两个示例得知,在同一个网络中的容器,是可以使用IP进行互相访问的。
2.2 基于容器名进行访问
通过IP访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过Docker自带的DNS服务解决。
从Docker 1.10版本开始,Docker daemon实现了一个内嵌的DNS server,使容器可以直接通过"容器名"通信。方法很简单,只要在启动时用--name为容器命名就可以了。
以centos镜像举例(有ping命令,没有ip a命令)
# 创建a1容器,使用ldh网络
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh centos:7
[root@d69e08a904b7 /]# ip a
bash: ip: command not found
# 创建a2容器,使用ldh网络
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh centos:7
[root@f32d9923bd73 /]# ip a
bash: ip: command not found
可以看到我们不知道a1容器与a2容器的IP地址
ping对方的容器名
[root@d69e08a904b7 /]# ping a2
PING a2 (172.20.0.3) 56(84) bytes of data.
64 bytes from a2.ldh (172.20.0.3): icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from a2.ldh (172.20.0.3): icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from a2.ldh (172.20.0.3): icmp_seq=3 ttl=64 time=0.037 ms
^C
--- a2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.035/0.037/0.040/0.005 ms
通过以上示例得知,创建容器时,使用--name定义容器名称,当容器启动时,Docker daemon会把容器名与容器获取的IP进行绑定,写入到Docker DNS中,这样容器之间访问就可以基于容器名实现了,如果容器停止了,该容器所对应的DNS信息就会从Docker DNS中删除。使用Docker DNS有个限制,只能在新创建的bridge网络(自定义的网络)中使用。
2.3 joined容器
Joined(联合)容器是另一种实现容器间通信的方式。joined容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。
# 创建a1容器,使用ldh网络
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh busybox:latest
/ # 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
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 创建a2容器,--network指定为容器a1
[root@ldh ~]# docker run -it --name a2 --rm --network=container:a1 busybox:latest
/ # 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
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以发现a1容器与a2容器的网络栈一样
ping对方容器名
/ # ping a1
PING a1 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.030 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.038 ms
^C
--- a1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.030/0.034/0.038 ms
使用joined容器的方式实现容器间的通讯,需要注意的是两个容器之间的应用端口容易发生冲突,两个容器共享一个网络栈,那么容器中的应用在运行时,绑定的IP也是一样。
2.4 容器访问外部
同虚拟机访问外部网络使用的都是NAT地址转换原理。
2.5 外部访问容器
使用的是docker端口映射原理。
Docker 端口映射是指将容器内部的端口映射到宿主机的端口上,从而使外部可以访问容器内的服务。默认情况下,Docker 容器运行时是无法被外部网络直接访问的,因此需要进行端口映射。
也可以使用host网络,容器共享Docker host网络栈。