学习视频链接,以示尊重:https://www.bilibili.com/video/BV1og4y1q7M4?p=37
Docker 网络详解
一、理解Docker0
Docker使用的是Linux的桥接,在宿主机中是一个Docker容器的网桥docker0。
每启动一个docker容器,docker就会给docker容器分配一个ip,只要安装了docker,就会有一个网卡docker0。
使用ip addr
命令看一下网卡:
[root@iZ2ze436suxwekgjxx28iaZ ~]# ip addr
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:16:3e:32:87:68 brd ff:ff:ff:ff:ff:ff
inet 172.17.7.69/20 brd 172.17.15.255 scope global dynamic noprefixroute eth0
valid_lft 304994615sec preferred_lft 304994615sec
inet6 fe80::216:3eff:fe32:8768/64 scope link
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:05:a3:f5:55 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:5ff:fea3:f555/64 scope link
valid_lft forever preferred_lft forever
9: vethd68b892@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 66:19:f1:51:8f:d9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::6419:f1ff:fe51:8fd9/64 scope link
valid_lft forever preferred_lft forever
11: veth7542a6e@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 4e:d8:89:41:43:33 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::4cd8:89ff:fe41:4333/64 scope link
valid_lft forever preferred_lft forever
13: veth55d563b@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 4a:cb:72:7c:6a:ea brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::48cb:72ff:fe7c:6aea/64 scope link
valid_lft forever preferred_lft forever
17: veth2ebfe1b@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether ba:31:48:6f:62:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 3
inet6 fe80::b831:48ff:fe6f:62a3/64 scope link
valid_lft forever preferred_lft forever
其中:
- lo 是本地回环地
- docker0就是 docker0 地址,也就是 docker 的地址 172.17.7.69
那么,Docker如何处理容器的网络访问?
经过测试,发现主机可以ping通容器,而且容器和容器之间也可以ping通。docker0就像是一个路由器,各个容器就像是路由器下的设备,它们在同一个网段内,可以互相ping通。
这正是由于docker的evth-pair技术。
二、evth-pair技术
docker使用的是桥接模式,使用的技术是evth-pair技术。
每启动一个容器,就会多一对网卡。因为这个容器带来的网卡都是一对对的。
evth-pair 是一对的虚拟设备接口,它们都是成对出现的。一端连接着协议,一端彼此相连,所以可以彼此通信。正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备。
本来linux是ping不通容器的,但利用evth-pair在两边都搞了一个接口,接口通过一种协议可以通信,所以相当于架了一个桥,让它们可以通信。
结论:tomcat01 和 tomcat02 是公用的一个路由器 docker0.
所有的容器不指定网络的前提下,都是docker0路由的,docker会给我们的容器分配一个默认的ip。
两个容器看似是直接ping通的,实际是通过docker0来ping通的。docker0就像路由器,每run出一个容器来,就把它的地址在这个路由器上注册。
Docker网络的核心使用的是Linux的虚拟化技术,在容器内和docker0内分别建立一个虚拟网卡,再使用evth-pair技术进行连接。
Docker中的所有的网络接口都是虚拟的。因为虚拟的转发效率高。
只要容器删除,对应网桥一对就没有了。
三、- - link
如果服务宕机重启,docker分配的ip地址发生了改变,如何进行通信?
最好是可以不指定ip地址,而使用服务名称这个标识来进行通信。
可以通过比较老的--link
来解决:
将两个网络通过--link
进行连接:我们run一个centos03,使用--link
连接上centos02,然后直接在centos03中ping centos02这个名字,发现可以ping通:
root@KitDevVps:~# docker run -d -it --name centos03 --link centos02 centos
ad50e83c3041eb76d4905670a8cc91bc23c60d3933b5d5f51f702983e9f5711d
root@KitDevVps:~# docker exec -it centos03 ping centos02
PING centos02 (172.17.0.4) 56(84) bytes of data.
64 bytes from centos02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.146 ms
64 bytes from centos02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.097 ms
64 bytes from centos02 (172.17.0.4): icmp_seq=3 ttl=64 time=0.128 ms
64 bytes from centos02 (172.17.0.4): icmp_seq=4 ttl=64 time=0.097 ms
^C
--- centos02 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 45ms
rtt min/avg/max/mdev = 0.097/0.117/0.146/0.021 ms
但是如果反过来操作,发现centos02是ping不通centos03的。
root@KitDevVps:~# docker exec -it centos02 ping centos03
ping: centos03: Name or service not known
因为centos02根本不知道centos03是什么东西,没有给它配置。想让02ping通03,肯定要对02进行一些配置。
我们使用命令docker network ls
来查看当前的网络。先看一下docker network
怎么用:
root@KitDevVps:~# docker network -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
然后docker network ls
:
root@KitDevVps:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
1375b7ef4bbc bridge bridge local
b29eab4db971 host host local
acfcd6eaf888 none null local
可以看到上面有个bridge,我们可以使用docker network inspect 1375b7ef4bbc
来查看这个bridge的详细信息:
root@KitDevVps:~# docker network inspect 1375b7ef4bbc
...
"Name": "bridge",
"Id": "1375b7ef4bbcf53a812fc8397787f17f2b47ea412292daea3324e016c48f5738",
"Created": "2020-07-03T02:06:46.264143987Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"1cdd55fd90c550de6b2ad1544df5ae08b50c85d06d2a9f2e416bf0dbd0ac164d": {
"Name": "nginx1",
"EndpointID": "16c89d4f905cb8437a5a539064358a37d6ca09e46d5af653db09e639d2ff56ef",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"1ebe741425b2c80226fe265d170ed0567a6321ea7d7c4b3f4ab787985b2a6308": {
"Name": "centos02",
"EndpointID": "6f468d178b612079095203cd0df4e58705069ead019ab72011646259dac67cec",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"ad50e83c3041eb76d4905670a8cc91bc23c60d3933b5d5f51f702983e9f5711d": {
"Name": "centos03",
"EndpointID": "f54109b911f200c1afaad50d5459bb67a778fd5e64358f6344d2891e463d0598",
"MacAddress": "02:42:ac:11:00:05",
"IPv4Address": "172.17.0.5/16",
"IPv6Address": ""
},
"d07fb4674ffe04e7ef60540485c1c890faccffeb8f40c401ccf59965f1cb8760": {
"Name": "centos01",
"EndpointID": "89a3ea298b219971b9aa477efe67506e333a4d410083d56659fce3a6edbc259e",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
}
},
...
可以看到上面这一部分的containers中有正在运行的所有容器和他们的ip。当运行容器不指定ip的时候,它就会随机分配一个ip。
docker03实际上就是在本地配置了docker02的配置。
然后使用docker inspect 容器id
来查看centos03,因为我们用它link了02,但是其中并没有任何关于link的信息。
紧接着,浏览一下03中的/etc/hosts文件,寻找一下是否在这个文件中进行了配置:
root@KitDevVps:~# docker exec -it centos03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.4 centos02 1ebe741425b2
172.17.0.5 ad50e83c3041
在倒数第二行我们看到了centos02和它的ip地址以及它的id。
到此可以得知,link信息是直接写在了hosts文件中,所以我们ping centos02或者02的id,可以直接ping到。
02中的hosts文件是没有03的,有一种方案是可以手动写入,但这样就要重启容器才能生效,很麻烦。
实际上这种--link
的方式已经不推荐使用了。docker0不支持容器名,我们需要自定义网络,并且使得其支持容器名,而不使用docker0。
四、自定义网络
查看所有的docker网络:docker network ls
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b47982b38d80 bridge bridge local
28a1b197470b host host local
1a3c604475c8 none null local
其中:
- bridge:桥接,即docker0(默认)
- none:不配置网络
- host:和宿主机共享网络
使用如下启动命令时,--net bridge
可以指定,但是这个参数一般是默认的(不用写)
docker run -d -P --name tomcat01 --net bridge tomcat
docker0的特点:默认,域名不能访问,–link可以打通连接。
我们可以自定义一个网络,之后启动时指定并使用我们的自定义网络。
首先查看一下create方法的帮助文档:
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network create --help
Usage: docker network create [OPTIONS] NETWORK
Create a network
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which copying the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
创建:
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
af0c32b2c5fcbd92247d9e1f9a645ce901e0c8e3681b35b891074f5a5f355f3c
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b47982b38d80 bridge bridge local
28a1b197470b host host local
af0c32b2c5fc mynet bridge local
1a3c604475c8 none null local
[root@iZ2ze436suxwekgjxx28iaZ ~]#
查看自定义的网络:
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "af0c32b2c5fcbd92247d9e1f9a645ce901e0c8e3681b35b891074f5a5f355f3c",
"Created": "2020-10-14T21:30:47.972334524+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
至此,自定义网络创建成功!docker会帮我们维护好自定义网络中的对应关系,推荐使用。
启动容器时,使用该自定义网络,即可支持容器名访问。
五、网络连通
我们自定义的网络 mynet 中的容器和 docker0中的容器 如何连通呢?
核心命令:docker network connect
,查看其帮助文档:
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
使用该命令:docker network connect
假设 tomcat01 是 docker0 中的容器,mynet 是我们的自定义网络,现在要使得 mynet 中的容器和 tomcat01连通。
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network connect mynet tomcat01
连通之后,会将tomcat01直接加到mynet之下(可以理解为一个容器,两个ip地址)。但是docker0下的其他未connect的容器仍旧无法连通。
结论:假设要跨网络操作别人,就需要使用 docker network connect 网络名 容器名