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