Docker網絡深度解讀


點擊打開鏈接

Docker概念和默認網絡

什麼是Docker網絡呢?總的來說,網絡中的容器們可以相互通信,網絡外的又訪問不了這些容器。具體來說,在一個網絡中,它是一個容器的集合,在這個概念裏面的一個容器,它會通過容器的IP直接去通信,又能保證在這個集合外的一些容器不能夠通過這個容器IP去通信,能做到網絡隔離。網絡這個概念是由網絡的驅動去創建、管理的。網絡的驅動又分爲全局的和本地的,全局的意思是這個網絡可以跨主機,沒必要說我的兩個容器非要在一個主機上才能通過這個網絡去通信,我可以在不同主機上還是通過容器的IP相互通信。

本地網絡

411be7918155e00b18863881650edb24786648a2

首先我們看一個本地網絡的圖,這個圖中有一臺主機,上面跑了四個容器,分別分佈在兩個網絡裏面,一個是NET1,一個是NET2。NET1裏面的兩個容器是可以互相通過自己的IP通信的,但是NET1裏面的容器和NET2裏面的容器又是隔離的,這樣就是Docker的一個網絡概念。

全局網絡

5d644be114a98f7e2ade739fc756b2fa6f5a4938

全局網絡意思是,一個網絡裏面的容器是可以跨主機的。C1的容器可以和主機2上的C3容器,通過它們IP直接通信,而不用管所在的主機在哪個地方。這個圖裏面我們還可以看到一個細節,同一個容器可以加入到兩個網絡裏面,比如C4它可以和網絡1裏面的兩個容器通信,也可以和網絡2裏面的C5進行通信,這樣我們就可以實現更加複雜的一些組合。比如C5是一個數據庫的容器,我不想讓這個數據被前面的WEB應用或者其他的應用去訪問到,只想讓我的中間鍵應用去訪問到。這樣就可以通過讓中間鍵應用加入到一個後臺網絡、一個前臺網絡的組合來實現這種互聯和網絡的控制。

網絡服務發現

c3fa6ba34ebe62e770587afb6c5cb0afe29bb97e

在1.10版本增加了網絡服務發現,什麼意思呢?比如,我的一個網絡有兩個容器,我們可以直接通過IP進行通信,但是我的容器它可能某一段時間跪掉了,它可能在跪掉之後再去重啓,我這時就不知道它的IP了,或者它一關閉之後,我這邊感知不到,這樣就要觸發很多複雜的一些處理流程。在1.10時它去做這樣的一件事,它在每個容器裏面內置了一個DNS的服務器,在服務器RUN起來之後,會寫一個容器名,或者是這個容器的一個別名和它IP的一個解析。外部容器去訪問我的DB容器時,它能夠通過DB這個名字來解析到DB容器的IP地址,這樣在DB容器重啓之後,這個解析會動態去調整,就能實現一個服務的發現。

Docker默認的網絡驅動

Docker默認的會有一些網絡驅動,它本地的網絡驅動有這幾種。none網絡驅動意思是,我創建一個容器,但是沒有它的一些網絡配置,單獨一個命名空間,它不能和其他容器通信,也不能訪問外網。host的網絡驅動和宿主機共享網絡棧、它和宿主機看到同樣的接口,包括它自己暴露的端口,都是和宿主機在同一個網絡空間裏面。

e79f2fead86dfa0e0f7d7868df8f10bffa555d3e

bridge網絡驅動,它是一個本地的網絡驅動,上圖主機上有兩個bridge網絡,它實際上是通過Linux的bridge去驅動的,通過容器裏面掛載一個網卡,對應的是在宿主機上一個veth,容器的請求會直接轉發到這個veth上面,bridge上面會對這個請求進行洪泛,它就能到達這個網絡裏面的另外一個容器。同理,另外一個網絡,它跟這個網絡裏面的容器沒有在同一個網橋上面,所以他們之間是互相不能通信的。bridge驅動還會實現另外一個功能,比如說C1的容器,他要訪問公網,它通過bridge出去的時候,他最終到達宿主機的接口,他會做一個網絡地址的轉換,把容器的IP轉換成宿主機的IP,這樣就能訪問公網。或者我的容器可能希望服務映射到外面去,讓別的機器或別的公開服務可以訪問到,他可以做一個DNAT一個規則,比如我的容器是Nginx,它裏面是80端口,我想映射到主機的一個9080,可以直接通過主機的9080去訪問,他可以去做一個DNAT的配置,這是bridge的驅動。

40aef45f7ed4d2a262d3dd6e333cbda12a128363

Docker默認還有一個overlay的驅動,它主要是去實現跨主機的一個通信,它會在主機之間通過vxlan的方式打一個隧道,實現我的主機上的容器去訪問主機上的容器,最終會轉換成一個vxlan裏面的通信。

Docker跨主機網絡

沒有跨主機網絡時,比如一個應用有兩個服務,兩個服務不可能部署到同一個機器上,這樣沒辦法做到高可用,所在的主機一掛,上面所有的服務都掛了。如果讓它部署到兩個主機上面,但是兩個主機上面這個容器的IP在主機外面是看不到的。所以只能把容器的IP轉換成了一個宿主機的一個IP,或者宿主機的一個訪問端點,才能讓外部的主機訪問。所以,以前的方式是通過端口映射,把容器的一個端口映射到主機的一個端口,讓另外一個主機和這個主機映射到這個容器上去通信。這樣會帶來哪些問題?首先我通過端口映射,比如說我映射到8090端口,我另外再想起一個容器。他就得映射到另外一個端口,因爲宿主機上只有這一個8090端口,它不可能說共享這個端口,所以一個主機上去起容器的時候,需要管理端口的列表。映射出去之後是宿主機的一個端口,這樣這個端口就是對外暴露的,可能要去控制一下,這個端口只能說主機要去訪問,這樣要去做一些安全的配置,所以這樣的整個架構是非常複雜的。在Docker1.9之後,增加了跨主機的網絡,它就可以直接通過容器的IP去通信,通過這個外部跟它是隔離的,這樣又能做到安全,我就算再起一個容器,它容器的IP端口是不會衝突的。

封包模式

封包模式,比如overlay驅動,它是用VXLAN的協議去把容器之間的請求封裝成VXLAN的請求,將鏈路層的以太網包封裝到UDP包中進行傳輸。

f35f75d31aad9ccf8828c5635bfe5d2314d88ea1

這裏有一個簡單的圖來介紹封包模式,首先舉個例子,從C1去訪問宿主機上C2的容器,先通過C1發出這個包之後,它首先進行封包,要查找中心化存儲C2是在哪個主機上的,查到的是這個主機上,就把這個請求的包封裝成宿主機之間的包,把這個包送達到對應宿主機上,再通過一定的約定去解包,最終轉發到另外一個主機上的一個容器。其缺點是對帶寬的損耗比較大,因爲看到這裏去封包,它肯定是把這個容器的包上面又加了一層包,這個包上面肯定會有一些自己的佔用,一般像封包模式,MTU最終都會小於宿主機之間的MTU,它還會造成一些資源佔用。比如說在這個地方去封包的時候,它可能會佔用CPU去做一下封包操作,還會佔用CPU去做解包的操作,所以會增加主機上的負載,但是它的好處是對基礎設施要求比較低,它只需要兩個宿主機之間可以三層互通。

62f38414dc15f751820a1b54678d7d21b359d5e3

下面我們以Docker的overlay驅動來介紹下封包的實現,它的封包方式是基於VXLAN。上圖是它的針格式,VXLAN內部把一個二層的包、鏈路層的一個請求封裝成一個VXLAN的一個包,這裏面會有一個約定的信息,比如VXLAN ID,還有一個外部的UDP的頭,最終會把這個包通過UDP發往對應的主機上面去,對應的主機再做VXLINE的解包。Docker還會做IP的地址管理和網絡信息同步。

路由模式

44237a4c3a450f6c5901bfd36901c9dae8bb380b

如上圖,比如,主機1上的容器想要訪問主機2的容器,首先這個機器上是沒有主機2的IP地址,它出了機器之後到達路由器,再通過路由器上的路由表,去把對應的請求網端轉發到對應的主機2上面,主機2上面是有這個容器的IP,所以它就能夠做到這個容器的跨主機通信。它的好處在於它沒有封包,所以它的性能很好,但是它對於基礎設施有一些要求,比如我的基礎設施要支持、能夠配置這個路由表,如果用Linux路由要支持二層的轉發。

40e5882f11b3d30d52b12783205fe115d27485ac

VPC網絡驅動是在阿里雲的VPC基礎上,能夠實現容器互通的一種方案。首先在Docker DM啓動時,或者是在創建網絡時,會從每個機器的一箇中心化存儲裏面,拿到兩個自己的網端,比如這個機器上的網端,比如左邊主機上的網端就是172.19.1.1/24,它通過阿里雲的openapi去配置這個轉發表,把這個網端的地址都轉發到這個主機上面。另外一個主機啓動時,把它拿到一個可用的網端,去配置阿里雲的一個路由表,把這個網端的請求轉發到自己的主機上面,比如說我這邊的一個容器想要去訪問主機2上C2的容器時,它這個包最終到達,通過vSwitch到達阿里雲VPC的vRouter時,通過查詢路由表把實時的請求包轉發到主機2上面,最終實現C1和C2的通信。

跨主機網絡方案對比

封包模式的優點是對基礎設施的要求比較低,但是它性能損耗比較大,路由模式是沒有封包的,所以它性能比較好,但是對基礎設施有一定要求,比如說要支持路由表,或者要支持二層的轉發。

阿里雲服務的網絡方案

容器服務上面現在有兩種集羣,一種是阿里雲的ECS集羣,這種集羣的節點都是在阿里雲的同地域或者同一個VPC下面的ECS,或者是混合雲的集羣,阿里雲的混合雲集羣節點是在用戶自己建立的機房,或者分佈在不同的雲供應商上面。

8ce89db02d53270f4db4a61e2ab0b684aeb63e0a

在阿里雲的ECS集羣上面,網絡架構是這樣的,容器之間去通信,還是通過overlay驅動,它的好處是對基礎設施要求比較低,所以它只需要主機之間互通就可以了,容器去訪問外網,或者容器想要暴露端口給外網就通過一個gateway_bridge的網橋、本地的一個驅動,這個是供容器訪問外網和容器的端口映射。在ECS集羣上面,VPC網絡是通過VPC驅動的路由表把對應的請求轉發到容器所在機器上面,它去訪問外網和做端口映射也是和剛纔所介紹的overlay是同樣的。

b3c806fe7d84eb80b6cb87ab6a2f22f11583d7fc

混合雲集羣是結合阿里雲的VPC技術去實現容器之間的網絡互通。在混合雲集羣裏面是通過專線的方式,把對應的數據中心的請求轉發到我的數據中心裏面,或者把數據中心的請求訪問VPC的,通過專線的一個路由也可以轉發到VPC裏面,再通過路由表把容器的請求轉發到對應的主機上面,最終實現的方式是把我VPC裏面的容器和數據中心裏面的容器互通。

b60ec28d1c53667c1e09293f5df6913f0689c05b

剛纔我們介紹的都是容器之間通信,我們可以不通過端口映射的方式做到端口不衝突,怎麼能夠做到我想要外部訪問時,也能做到就一個負載均衡,怎麼能做到一個機器上面部署多個容器,然後端口不衝突呢?這時候阿里雲就提供了這樣的一個負載均衡方案。比如說我的網站有兩個域名,一個是購物的域名,一個是付款的,但是我總共就三臺機器,每個服務要做到高可用,所以起了很多的容器,這樣在同一個主機上就要去處理,怎麼讓它保障單個不衝突,容器服務是提供一個這樣的方案,我們在集羣裏面會部署一套路由的一個服務,首先請求,比如說我的公司域名的泛解析會解析到我的路由服務上面去,路由服務再通過請求的域名Host,去把這個請求直接轉發到容器上面,最終實現我的一個請求可以轉發到容器上面,但是我的容器並沒有映射出端口,也不需要去解決端口衝突的問題。


原文鏈接

發佈了35 篇原創文章 · 獲贊 109 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章