自從docker容器出現以來,容器的網絡通訊就一直是你們關注的焦點,也是生產環境的迫切需求。而容器的網絡通訊又能夠分爲兩大方面:單主機容器上的相互通訊和跨主機的容器相互通訊。而本文將分別針對這兩方面,對容器的通訊原理進行簡單的分析,幫助你們更好地使用docker。html
基於對net namespace的控制,docker能夠爲在容器建立隔離的網絡環境,在隔離的網絡環境下,容器具備徹底獨立的網絡棧,與宿主機隔離,也可使容器共享主機或者其餘容器的網絡命名空間,基本能夠知足開發者在各類場景下的須要。按docker官方的說法,docker容器的網絡有五種模式:node
這些網絡模式在相互網絡通訊方面的對好比下所示:linux
模式docker |
是否支持多主機 | 南北向通訊機制 | 東西向通訊機制安全 |
bridge | 否 | 宿主機端口綁定 | 經過Linux bridge |
host | 是 | 按宿主機網絡通訊 | 按宿主機網絡通訊 |
none | 否 | 沒法通訊 | 只能用link通訊 |
其餘容器 | 否 | 宿主機端口綁定 | 經過link通訊 |
用戶自定義 | 按網絡實現而定 | 按網絡實現而定 | 按網絡實現而定 |
南北向通訊指容器與宿主機外界的訪問機制,東西向流量指同一宿主機上與其餘容器相互訪問的機制。服務器
因爲容器和宿主機共享同一個網絡命名空間,換言之,容器的IP地址即爲宿主機的IP地址。因此容器能夠和宿主機同樣,使用宿主機的任意網卡,實現和外界的通訊。其網絡模型能夠參照下圖:網絡
採用host模式的容器,能夠直接使用宿主機的IP地址與外界進行通訊,若宿主機具備公有IP,那麼容器也擁有這個公有IP。同時容器內服務的端口也可使用宿主機的端口,無需額外進行NAT轉換,並且因爲容器通訊時,再也不須要經過linuxbridge等方式轉發或者數據包的拆封,性能上有很大優點。固然,這種模式有優點,也就有劣勢,主要包括如下幾個方面:tcp
bridge模式是docker默認的,也是開發者最常使用的網絡模式。在這種模式下,docker爲容器建立獨立的網絡棧,保證容器內的進程使用獨立的網絡環境,實現容器之間、容器與宿主機之間的網絡棧隔離。同時,經過宿主機上的docker0網橋,容器能夠與宿主機乃至外界進行網絡通訊。其網絡模型能夠參考下圖:工具
從該網絡模型能夠看出,容器從原理上是能夠與宿主機乃至外界的其餘機器通訊的。同一宿主機上,容器之間都是鏈接到docker0這個網橋上的,它能夠做爲虛擬交換機使容器能夠相互通訊。然而,因爲宿主機的IP地址與容器veth pair的 IP地址均不在同一個網段,故僅僅依靠veth pair和namespace的技術,還不足以使宿主機之外的網絡主動發現容器的存在。爲了使外界能夠方位容器中的進程,docker採用了端口綁定的方式,也就是經過iptables的NAT,將宿主機上的端口端口流量轉發到容器內的端口上。oop
舉一個簡單的例子,使用下面的命令建立容器,並將宿主機的3306端口綁定到容器的3306端口:
docker run -tid –name db -p 3306:3306 MySQL
在宿主機上,能夠經過iptables -t nat -L -n,查到一條DNAT規則:
DNAT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
上面的172.17.0.5即爲bridge模式下,建立的容器IP。
很明顯,bridge模式的容器與外界通訊時,一定會佔用宿主機上的端口,從而與宿主機競爭端口資源,對宿主機端口的管理會是一個比較大的問題。同時,因爲容器與外界通訊是基於三層上iptables NAT,性能和效率上的損耗是能夠預見的。
在這種模式下,容器有獨立的網絡棧,但不包含任何網絡配置,只具備lo這個loopback網卡用於進程通訊。也就是說,none模式爲容器作了最少的網絡設置,可是俗話說得好「少便是多」,在沒有網絡配置的狀況下,經過第三方工具或者手工的方式,開發這任意定製容器的網絡,提供了最高的靈活性。
其餘網絡模式是docker中一種較爲特別的網絡的模式。在這個模式下的容器,會使用其餘容器的網絡命名空間,其網絡隔離性會處於bridge橋接模式與host模式之間。當容器共享其餘容器的網絡命名空間,則在這兩個容器之間不存在網絡隔離,而她們又與宿主機以及除此以外其餘的容器存在網絡隔離。其網絡模型能夠參考下圖:
在這種模式下的容器能夠經過localhost來同一網絡命名空間下的其餘容器,傳輸效率較高。並且這種模式還節約了必定數量的網絡資源,但它並無改變容器與外界通訊的方式。在一些特殊的場景中很是有用,例如,kubernetes的pod,kubernetes爲pod建立一個基礎設施容器,同一pod下的其餘容器都以其餘容器模式共享這個基礎設施容器的網絡命名空間,相互之間以localhost訪問,構成一個統一的總體。
在用戶定義網絡模式下,開發者可使用任何docker支持的第三方網絡driver來定製容器的網絡。而且,docker 1.9以上的版本默認自帶了bridge和overlay兩種類型的自定義網絡driver。能夠用於集成calico、weave、openvswitch等第三方廠商的網絡實現。
除了docker自帶的bridge driver,其餘的幾種driver均可以實現容器的跨主機通訊。而基於bdrige driver的網絡,docker會自動爲其建立iptables規則,保證與其餘網絡之間、與docker0之間的網絡隔離。例如,使用下面的命令建立一個基於bridge driver的自定義網絡:
docker network create bri1
則docker會自動生成以下的iptables規則,保證不一樣網絡上的容器沒法互相通訊。
-A DOCKER-ISOLATION -i br-8dba6df70456 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-8dba6df70456 -j DROP
除此以外,bridge driver的全部行爲都和默認的bridge模式徹底一致。而overlay及其餘driver,則能夠實現容器的跨主機通訊。
早期你們的跨主機通訊方案主要有如下幾種:
上面這些方案有各類各樣的缺陷,同時也由於跨主機通訊的迫切需求,docker 1.9版本時,官方提出了基於vxlan的overlay網絡實現,原生支持容器的跨主機通訊。同時,還支持經過libnetwork的plugin機制擴展各類第三方實現,從而以不一樣的方式實現跨主機通訊。就目前社區比較流行的方案來講,跨主機通訊的基本實現方案有如下幾種:
下面,本從網絡通訊模型的角度,對這些方案的通訊原理作一個簡單的比較,從中能夠窺見各類方案在性能上的本質差異。
首先,科普下docker容器的CNM網絡模型,calico、weave等第三方實現都是基於CNM模型與docker集成的。CNM網絡模型的結構以下圖所示:
在上面的圖中:
docker官方文檔的示例中,overlay網絡是在swarm集羣中配置的,但實際上,overlay網絡能夠獨立於swarm集羣實現,只須要知足如下前提條件便可。
協議
端口 說明
udp 4789 容器之間流量的vxlan端口 tcp/udp 7946 docker守護進程的控制端口
宿主機內核版本10以上(1.9版本時,要求3.16以上)
知足以上條件後,就能夠經過docker network命令來建立跨主機的overlay網絡了,例如: docker network create -d overlay overlaynet 在集羣的不一樣主機上,使用overlaynet這個網絡建立容器,造成以下圖所示的網絡拓撲:
因爲容器和overlay的網絡的網絡命名空間文件再也不操做系統默認的/var/run/netns下,只能手動經過軟鏈接的方式查看。
ln -s /var/run/docker/netns /var/run/netns
這樣就能夠經過ip netns查看到容器和網絡的網絡命名空間了。
容器的網絡命名空間名稱能夠經過docker inspect -f ‘{{.NetworkSettings.SandboxKey}}’ <容器ID>方式查看到。網絡的網絡命名空間則是經過docker network ls查看到的網絡短ID。
有時候網絡的網絡命名空間名稱前面會帶上1-、2-等序號,有時候不帶。但不影響網絡的通訊和操做。
從這個通訊過程當中來看,跨主機通訊過程當中的步驟以下:
雖然上面的網絡通訊模型能夠實現容器的跨主機通訊,但仍是有一些缺陷,形成實際使用上的不便,例如:
weave經過在docker集羣的每一個主機上啓動虛擬的路由器,將主機做爲路由器,造成互聯互通的網絡拓撲,在此基礎上,實現容器的跨主機通訊。其主機網絡拓撲參見下圖:
如上圖所示,在每個部署Docker的主機(多是物理機也多是虛擬機)上都部署有一個W(即weave router,它自己也能夠以一個容器的形式部署)。weave網絡是由這些weave routers組成的對等端點(peer)構成,而且能夠經過weave命令行定製網絡拓撲。
每一個部署了weave router的主機之間都會創建TCP和UDP兩個鏈接,保證weave router之間控制面流量和數據面流量的經過。控制面由weave routers之間創建的TCP鏈接構成,經過它進行握手和拓撲關係信息的交換通訊。控制面的通訊能夠被配置爲加密通訊。而數據面由weave routers之間創建的UDP鏈接構成,這些鏈接大部分都會加密。這些鏈接都是全雙工的,而且能夠穿越防火牆。
當容器經過weave進行跨主機通訊時,其網絡通訊模型能夠參考下圖:
從上面的網絡模型圖中能夠看出,對每個weave網絡中的容器,weave都會建立一個網橋,而且在網橋和每一個容器之間建立一個veth pair,一端做爲容器網卡加入到容器的網絡命名空間中,併爲容器網卡配置ip和相應的掩碼,一端鏈接在網橋上,最終經過宿主機上weave router將流量轉發到對端主機上。其基本過程以下:
weave默認基於UDP承載容器之間的數據包,而且能夠徹底自定義整個集羣的網絡拓撲,但從性能和使用角度來看,仍是有比較大的缺陷的:
calico是純三層的SDN 實現,它基於BPG 協議和Linux自身的路由轉發機制,不依賴特殊硬件,容器通訊也不依賴iptables NAT或Tunnel 等技術。可以方便的部署在物理服務器、虛擬機(如 OpenStack)或者容器環境下。同時calico自帶的基於iptables的ACL管理組件很是靈活,可以知足比較複雜的安全隔離需求。
在主機網絡拓撲的組織上,calico的理念與weave相似,都是在主機上啓動虛擬機路由器,將每一個主機做爲路由器使用,組成互聯互通的網絡拓撲。當安裝了calico的主機組成集羣后,其拓撲以下圖所示:
每一個主機上都部署了calico/node做爲虛擬路由器,而且能夠經過calico將宿主機組織成任意的拓撲集羣。當集羣中的容器須要與外界通訊時,就能夠經過BGP協議將網關物理路由器加入到集羣中,使外界能夠直接訪問容器IP,而不須要作任何NAT之類的複雜操做。
當容器經過calico進行跨主機通訊時,其網絡通訊模型以下圖所示:
從上圖能夠看出,當容器建立時,calico爲容器生成veth pair,一端做爲容器網卡加入到容器的網絡命名空間,並設置IP和掩碼,一端直接暴露在宿主機上,並經過設置路由規則,將容器IP暴露到宿主機的通訊路由上。於此同時,calico爲每一個主機分配了一段子網做爲容器可分配的IP範圍,這樣就能夠根據子網的CIDR爲每一個主機生成比較固定的路由規則。
當容器須要跨主機通訊時,主要通過下面的簡單步驟:
從上面的通訊過程來看,跨主機通訊時,整個通訊路徑徹底沒有使用NAT或者UDP封裝,性能上的損耗確實比較低。但正式因爲calico的通訊機制是徹底基於三層的,這種機制也帶來了一些缺陷,例如:
轉自:https://www.cnblogs.com/ilinuxer/p/6680205.html
docker容器網絡參見:https://blog.csdn.net/zjysource/article/details/52055820