11-Docker Bridge详解
容器之间是如何通信的?
操作前删除test2的容器。
-
查看当前机器上docker的网络
docker network ls
NETWORK ID NAME DRIVER SCOPE 056d0ece100f bridge bridge local a78b081f0bda host host local 51a236124cac none null local
这条命令会列举出当前机器上有哪些网络。其实test1 就是连接到bridge这个网络上的。
-
查看bridge的网络详细信息
docker network inspect 056d0ece100f # 这个是bridge的 NETWORK ID
在结果中找到
Containers
这一项。"Containers": { "da991beadf34ef53be9cf3de8f0c5ba1599b76f4433f6627f96c46c09751ecf5": {"Name": "test1","EndpointID": "4764dcc3a29b9ee7efb6ea5dc5c905840362c8ddc0d944356a4c0e7b07a99d98","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": "" }
说明这个test1 这个容器是连接到bridge网络上的。
-
查看当前机器的网路
ip a
我们可以找到这两条,
docker0
与veth01f8da0
(可能是不一样的,但都是veth开头, veth是 virtual ethernet)4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:57:ac:11:fe brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft forever inet6 fe80::42:57ff:feac:11fe/64 scope link valid_lft forever preferred_lft forever 22: veth01f8da0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether d2:61:e8:a9:d7:9c brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::d061:e8ff:fea9:d79c/64 scope link valid_lft forever preferred_lft forever
docker0
是一个本机的network namespace,而 busybox有自己的 network namespaceveth01f8da0@if21
,它是连接到docker0
上的。那么 test1 是如何连接的呢?首先查看 它的网络docker exec test1 ip a
其中有这一条
21: eth0@if22: <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 eth0valid_lft forever preferred_lft forever
其中
eth0@if22
和 外面的veth01f8da0@if21
是一对 veth,然后连接到docker0
的网桥上。那我们验证一下是否是这样。首先安装一个工具。
sudo yum install bridge-utils
运行命令
brctl show
bridge name bridge id STP enabled interfaces docker0 8000.024257ac11fe no veth01f8da0
我们可以看到当前机器内只有一个
linux bridge
。这里有一个接口interfaces
,不难发现它的名称和之前本机网络中的22: veth01f8da0@if21
是一样的。所以这个接口是连接到docker0
的bridge上的。 -
再创建一个test2容器
docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done"
查看本机的bridge情况。
这个bridge就是通过
docker network ls
命令获取的。docker network inspect 056d0ece100f # 也可以通过docker network inspect bridge
"Containers": { "da991beadf34ef53be9cf3de8f0c5ba1599b76f4433f6627f96c46c09751ecf5": {"Name": "test1","EndpointID": "4764dcc3a29b9ee7efb6ea5dc5c905840362c8ddc0d944356a4c0e7b07a99d98","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": "" }, "db730b8fe9ca0a6fcdb215b15b894768e0a14cf45493d413a8b7363403c1c574": {"Name": "test2","EndpointID": "7cbae53c21a06866b140a683c993fddbc80edcf96a9c9b59669934dace123956","MacAddress": "02:42:ac:11:00:03","IPv4Address": "172.17.0.3/16","IPv6Address": "" }
我们可以看到test2容器已经在这个bridge内了。
-
本机查看网络
ip a
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:57:ac:11:fe brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft forever inet6 fe80::42:57ff:feac:11fe/64 scope link valid_lft forever preferred_lft forever 22: veth01f8da0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether d2:61:e8:a9:d7:9c brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::d061:e8ff:fea9:d79c/64 scope link valid_lft forever preferred_lft forever 26: vethb9d5db9@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 9a:1c:2c:48:04:70 brd ff:ff:ff:ff:ff:ff link-netnsid 1inet6 fe80::981c:2cff:fe48:470/64 scope link valid_lft forever preferred_lft forever
我们发现又多了一个
vethb9d5db9
。这是因为我们创建了test2,则必须在主机上再生成一个veth才能连接到docker0
上,到这里我们应该可以看出。为了使容器在主机间通讯,则必须需要有两个veth,而成对的虚拟接口被叫做“peers”,它被链接到主机内核的内部,因此(数据)包能在他们之间传输。
再次查看本机的网桥情况
brctl show
bridge name bridge id STP enabled interfaces docker0 8000.024257ac11fe no veth01f8da0vethb9d5db9
可以看到
docker0
已经连接了两个veth
接口。 -
此时拓扑图是什么样的?
图中绿色的方块就是
veth
,成对的veth
才能连接到docker0
。这很像我们现实中的网络,就好比 两个人两台电脑连接到了同一台路由器上,路由器为这两台电脑分配了两个ip。但是此时 test1和test2只是组成了局域网,并不能访问互联网。
容器是如何连接互联网的?
其实是通过了 NAT 技术。
首先linux主机是可以访问外网的,比如可以通过eth0访问外网。
eth0,eth1,eth2,代表网卡一,网卡二,网卡三(一般是有线连接),如果是无线网连接是 wlp5s0
那么 test1 容器想访问外网,可以通过 docker0
这个bridge,然后做一个NAT地址转换成eth0地址,然后发送到外网。
NAT 是通过iptabels实现的,具体可以自己google