Veth Pair |
這部份內容主要介紹一個設備: Veth Pair .
做爲一個容器,它能夠聲明直接使用宿主機的網絡棧,即:不開啓 Network Namespace .在這種狀況下,這個容器啓動後,直接監聽的就是宿主機的 80 端口.
像這樣直接使用宿主機網絡棧的方式,雖然能夠爲容器提供良好的網絡性能,但也會不可避免地引入共享網絡資源的問題,好比端口衝突.因此,在大多數狀況下,咱們都但願容器進程能使用本身 Network Namespace 裏的網絡棧,即:擁有屬於本身的 IP 地址和端口.
可是這個時候,就有另一個問題了:這個別隔離的容器進程,該如何跟其餘 Network Namespace 裏的容器進程進行交互呢?
最直接的辦法,就是把它們用一根網線鏈接起來;而若是想要實現多臺主機之間的通訊,那就須要用網線,把它們鏈接在一臺交換機上.
在 Linux 中,可以起到虛擬交換機做用的網絡設備,是網橋( Bridge ).它是一個工做在數據鏈路層( Data Link )的設備,主要功能是根據 MAC 地址學習來將數據包轉發到網橋的不一樣端口( Port )上.
爲了實現這個目的, Docker 項目會默認在宿主機上建立一個名叫 docker0 的網橋,凡是鏈接在 docker0 網橋上的容器,均可以經過它來進行通訊.
可是,咱們又該如何把這些容器"鏈接"到 docker0 網橋上呢?此時,咱們就須要使用一種名叫 Veth Pair 的虛擬設備了.
Veth Pair 設備的特色是:它被建立出來後,老是以兩張虛擬網卡( Veth Peer )的形式成對出現的.而且,從其中一個"網卡"發出的數據包,能夠直接出如今與它對應的另外一張"網卡"上,哪怕這兩個"網卡"在不一樣的 Network Namespace 裏面.這樣,用來鏈接不一樣 Network Namespace 的"網線"就成爲了可能.nginx
舉個例子 |
好比,如今咱們啓動了一個叫作 nginx-1 的容器:web
$ docker run –d --name nginx-1 nginx
而後咱們能夠進入到這個容器中,查看一下它的網絡設備:docker
# 在宿主機上 $ 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
能夠看到,在這個容器中,有一張叫作 eth0 的網卡,它正是一個 Veth Pair 設備在容器裏的這一端.經過 route 命令,能夠查看到 nginx-1 容器的路由表,可以看到,這個 eth0 網卡是這個容器裏的默認路由設備;全部對 172.17.0.0/16 網段的請求,也會被交給 eth0 來處理(第二條 172.17.0.0 路由規則)
而這個 Veth Pair 設備的另外一端,則在宿主機上.能夠經過查看宿主機的網絡設備看到它,以下所示:bash
# 在宿主機上 $ 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
經過 ifconfig 命令的輸出,咱們能夠看到, nginx-1 容器對應的 Veth Pair 設備,在宿主機上是一張虛擬網卡,它的名字是: veth9c02e56 .而且,經過 brctl show 的輸出,能夠看到這張網卡被"插"在了 docker0 上.
若是此時,咱們在這臺宿主機上啓動另外一個 Docker 容器,好比 nginx-2 :網絡
$ docker run –d --name nginx-2 nginx $ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242d8e4dfc1 no veth9c02e56 vethb4963f3
會發現,有一個新的,名叫 vethb4963f3 的虛擬網卡,也被"插"在了 docker0 網橋上.此時,若是在 nginx-1 容器中 ping 一下 nginx-2 容器的 IP 地址( 172.17.0.3 ),就會發現,在同一宿主機上的兩個容器,默認就是相互連通的.
以上整個流程,來一張示意圖:(這樣能夠更清楚一些)
此時,應該就能夠理解了,在默認狀況下,被限制在 Network Namespace 裏的容器進程,其實是經過 Veth Pair 設備 + 宿主機網橋的方式,實現了和其餘容器的數據交換.
因此,若是遇到容器連不通"外網"時,第一反應應該是先試試 docker0 網橋能不能 ping 通,而後查看一下跟 docker0 和 Veth Pair 設備相關的 iptables 規則是否是有異常,通常就可以找到問題的答案.
以上介紹的是單機容器網絡的實現原理和 docker0 網橋的做用.在這裏的關鍵在於,容器若是想要和外界進行通訊,它發出的 IP 包就必須從它的 Network Namespace 裏出來,來到宿主機上,而解決這個問題的方法就是:爲容器建立一個一端在容器裏充當默認網卡,另外一端在宿主機上的 Veth Pair 設備.svg
思惟擴展 |
看到這裏,估計你會有另一個疑問,那我若是想要"跨主機通訊"呢?
在 Docker 的默認配置下,一臺宿主機上的 docker0 網橋,和其餘宿主機上的 docker0 網橋,沒有任何關聯,它們互相之間就沒辦法連通.
可是若是咱們經過軟件的方式,建立一個整個集羣"公用"的網橋呢?而後把集羣裏全部的容器都鏈接到這個網橋上,是否是就能夠相互通訊了?
一點兒毛病都沒.
這樣,咱們就能夠畫出以下的示意圖:
經過示意圖,可以看到,構建這種容器網絡的核心在於:咱們須要在已有的宿主機網絡上,再經過軟件構建出一個覆蓋在已有宿主機網絡之上的,能夠把全部容器連通在一塊兒的虛擬網絡.這種技術就是: Overlay Network (覆蓋網絡).
可是這只是理論上,落實到實際,仍是有些出入的.
後面我看時間和精力,若是可能,再寫一篇關於"跨主機"通訊的講解文章(感受有些難度,我不肯定可以講清楚,可是儘可能)oop
以上內容來自我學習<深刻剖析Kubernetes>專欄文章以後的一些看法,有偏頗之處,還望指出.
感謝您的閱讀~性能