目錄nginx
極客時間 張磊 深刻剖析Kubernetes 課程筆記docker
一個Linux容器的網絡棧被隔離在本身的Network Namespace中,Network Namespace包括了:網卡(Network Interface),迴環設備(Lookback Device),路由表(Routing Table)和iptables規則。bash
# 聲明直接使用宿主機的網絡棧 docker run -d -net=host --name nginx-host nginx
大多數狀況下,都但願容器使用本身的網絡棧:即擁有本身的IP地址和端口。網絡
那麼宿主機上不一樣network namespace下的容器之間如何通訊?Linux 網橋(Bridge)oop
網橋是Linux內核中的一個模塊,做用相似於虛擬交換機,它工做在鏈路層,主要功能是將數據包根據MAC地址轉發到不一樣的端口。spa
利用Veth Path做爲「網線」將不一樣Network Namespace下的容器鏈接到網橋上。3d
啓動一個容器查看其中的網絡設備:code
# 在宿主機上 $ docker exec -it nginx-1 /bin/bash # 在容器裏 root@2b3c181aecf1:/# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0 inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link> ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet) RX packets 364 bytes 8137175 (7.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 281 bytes 21161 (20.6 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 172.17.0.1 0.0.0.0 UG 0 0 0 eth0 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
能夠看到容器nginx-1
內部有一個接口eth0
,這個接口是Veth Pair設備的一端,做爲容器內的一個虛擬接口,Veth Pair的另外一端鏈接在外部的網橋docker0
上。blog
同時,容器內部的默認下一跳地址爲172.17.0.1
,接口爲eth0
,咱們在宿主機執行ifconfig
能夠看到,這個下一跳的IP地址就是docker0
網橋的IP地址。接口
# 在宿主機上 $ ifconfig ... docker0 Link encap:Ethernet HWaddr 02:42:d8:e4:df:c1 inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:d8ff:fee4:dfc1/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:309 errors:0 dropped:0 overruns:0 frame:0 TX packets:372 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:18944 (18.9 KB) TX bytes:8137789 (8.1 MB) veth9c02e56 Link encap:Ethernet HWaddr 52:81:0b:24:3d:da inet6 addr: fe80::5081:bff:fe24:3dda/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:288 errors:0 dropped:0 overruns:0 frame:0 TX packets:371 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:21608 (21.6 KB) TX bytes:8137719 (8.1 MB) $ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242d8e4dfc1 no veth9c02e56
同時,能夠看到建立的Veth Pair設備在宿主機上名稱爲veth9c02e56
,經過brctl
命令,能夠看到該設備被鏈接到了docker0
網橋上。
這時,咱們再建立nginx-2
容器:
$ docker run –d --name nginx-2 nginx $ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242d8e4dfc1 no veth9c02e56 vethb4963f3
能夠看到docker0
網橋上被插入了另外一個Veth Pair設備vethb4963f3
。同時,在nginx-1
中PING 172.17.0.3(nginx-2的IP地址),是能夠通的。
原理:
當在nginx-1中PING 172.17.0.3時,匹配到了nginx-1路由表中的第二條規則,路由規則的第二條中,全部發往網絡172.17.0.0/16
的數據包的網關爲0.0.0.0
,這條規則爲直連規則,即:凡是匹配到這條規則的IP包,應該通過本機的eth0
接口,經過二層網絡直接發往目的主機。
而爲了經過二層網絡進行轉發,須要目的地址172.17.0.3
的MAC地址,因此經過eth0
接口發送一個 ARP 請求,來得到172.17.0.3
的MAC地址。
ARP請求經過eth0
接口發送給宿主機上的docker0
網橋,而後被轉發到全部鏈接在docker0
網橋上的接口,容器nginx-2
收到ARP請求以後返回一個包含本身MAC地址的ARP響應,該響應經過docker0
網橋回覆給nginx-1
。
nginx-1
本身的網絡協議棧收到MAC地址後,將該地址寫入鏈路層數據包頭,而後將數據包經過eth0
發送出去。
值得注意的是,全部被插到網橋上的接口都被降級爲網橋的一個端口,也就是說,這些接口都失去了拒絕接收鏈路層數據包的權利,只要網橋將數據包轉發給該接口,那麼它必須接收。
docker0
在接收到來自nginx-1
的數據包後,繼續扮演二層交換機的做用,將數據轉發給nginx-2
。
總之,被限制在Network Namespace中的容器進程,經過Veth Pair設備+宿主機網橋的方式,實現容器之間的數據交換。
相似,從宿主機訪問容器內部,也是經過docker0
網橋將數據轉發到容器內。
經過軟件的方式,構建一個跨主機的「公用」網橋,而後把各個容器都鏈接到這個「公用」網橋上。
這種技術被稱爲 Overlay Network。即:在已經存在的宿主機網絡上,再經過軟件構建一個在已有宿主機之上的、能夠把全部容器連通在一塊兒的虛擬網絡。