Docker容器網絡

概述

自從docker容器出現以來,容器的網絡通訊就一直是你們關注的焦點,也是生產環境的迫切需求。而容器的網絡通訊又能夠分爲兩大方面:單主機容器上的相互通訊,和跨主機的容器相互通訊。而本文將分別針對這兩方面,對容器的通訊原理進行簡單的分析,幫助你們更好地使用docker。html

 

docker單主機容器通訊

基於對net namespace的控制,docker能夠爲在容器建立隔離的網絡環境,在隔離的網絡環境下,容器具備徹底獨立的網絡棧,與宿主機隔離,也可使容器共享主機或者其餘容器的網絡命名空間,基本能夠知足開發者在各類場景下的須要。按docker官方的說法,docker容器的網絡有五種模式:node

  • bridge:docker默認的網絡模式,爲容器建立獨立的網絡命名空間,容器具備獨立的網卡等全部單獨的網絡棧,是最經常使用的使用方式。
  • host:直接使用容器宿主機的網絡命名空間。
  • none:爲容器建立獨立網絡命名空間,但不爲它作任何網絡配置,容器中只有lo,用戶能夠在此基礎上,對容器網絡作任意定製。
  • 其餘容器:與host模式相似,只是容器將與指定的容器共享網絡命名空間。
  • 用戶自定義:docker 1.9版本之後新增的特性,容許容器使用第三方的網絡實現或者建立單獨的bridge網絡,提供網絡隔離能力。

這些網絡模式在相互網絡通訊方面的對好比下所示:mysql

模式 是否支持多主機 南北向通訊機制 東西向通訊機制
bridge 宿主機端口綁定 經過Linux bridge
host 按宿主機網絡通訊 按宿主機網絡通訊
none 沒法通訊 只能用link通訊
其餘容器 宿主機端口綁定 經過link通訊
用戶自定義 按網絡實現而定 按網絡實現而定 按網絡實現而定

南北向通訊指容器與宿主機外界的訪問機制,東西向流量指同一宿主機上,與其餘容器相互訪問的機制。linux

host模式

因爲容器和宿主機共享同一個網絡命名空間,換言之,容器的IP地址即爲宿主機的IP地址。因此容器能夠和宿主機同樣,使用宿主機的任意網卡,實現和外界的通訊。其網絡模型能夠參照下圖:
host模式sql

採用host模式的容器,能夠直接使用宿主機的IP地址與外界進行通訊,若宿主機具備公有IP,那麼容器也擁有這個公有IP。同時容器內服務的端口也可使用宿主機的端口,無需額外進行NAT轉換,並且因爲容器通訊時,再也不須要經過linuxbridge等方式轉發或者數據包的拆封,性能上有很大優點。固然,這種模式有優點,也就有劣勢,主要包括如下幾個方面: docker

  • 最明顯的就是容器再也不擁有隔離、獨立的網絡棧。容器會與宿主機競爭網絡棧的使用,而且容器的崩潰就可能致使宿主機崩潰,在生產環境中,這種問題多是不被容許的。
  • 容器內部將再也不擁有全部的端口資源,由於一些端口已經被宿主機服務、bridge模式的容器端口綁定等其餘服務佔用掉了。

bridge模式

bridge模式是docker默認的,也是開發者最常使用的網絡模式。在這種模式下,docker爲容器建立獨立的網絡棧,保證容器內的進程使用獨立的網絡環境,實現容器之間、容器與宿主機之間的網絡棧隔離。同時,經過宿主機上的docker0網橋,容器能夠與宿主機乃至外界進行網絡通訊。其網絡模型能夠參考下圖:
bridge模式安全

從上面的網絡模型能夠看出,容器從原理上是能夠與宿主機乃至外界的其餘機器通訊的。同一宿主機上,容器之間都是鏈接掉docker0這個網橋上的,它能夠做爲虛擬交換機使容器能夠相互通訊。然而,因爲宿主機的IP地址與容器veth pair的 IP地址均不在同一個網段,故僅僅依靠veth pair和namespace的技術,還不足以使宿主機之外的網絡主動發現容器的存在。爲了使外界能夠方位容器中的進程,docker採用了端口綁定的方式,也就是經過iptables的NAT,將宿主機上的端口端口流量轉發到容器內的端口上。 服務器

舉一個簡單的例子,使用下面的命令建立容器,並將宿主機的3306端口綁定到容器的3306端口:
docker run -tid --name db -p 3306:3306 mysql 網絡

在宿主機上,能夠經過iptables -t nat -L -n,查到一條DNAT規則:tcp

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,性能和效率上的損耗是能夠預見的。

none模式

在這種模式下,容器有獨立的網絡棧,但不包含任何網絡配置,只具備lo這個loopback網卡用於進程通訊。也就是說,none模式爲容器作了最少的網絡設置,可是俗話說得好「少便是多」,在沒有網絡配置的狀況下,經過第三方工具或者手工的方式,開發這任意定製容器的網絡,提供了最高的靈活性

其餘容器模式

其餘網絡模式是docker中一種較爲特別的網絡的模式。在這個模式下的容器,會使用其餘容器的網絡命名空間,其網絡隔離性會處於bridge橋接模式與host模式之間。當容器共享其餘容器的網絡命名空間,則在這兩個容器之間不存在網絡隔離,而她們又與宿主機以及除此以外其餘的容器存在網絡隔離。其網絡模型能夠參考下圖:
container模式

在這種模式下的容器能夠經過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跨主機容器通訊

早期你們的跨主機通訊方案主要有如下幾種:

  • 容器使用host模式:容器直接使用宿主機的網絡,這樣天生就能夠支持跨主機通訊。雖然能夠解決跨主機通訊問題,但這種方式應用場景頗有限,容易出現端口衝突,也沒法作到隔離網絡環境,一個容器崩潰極可能引發整個宿主機的崩潰。

  • 端口綁定:經過綁定容器端口到宿主機端口,跨主機通訊時,使用主機IP+端口的方式訪問容器中的服務。顯而易見,這種方式僅能支持網絡棧的四層及以上的應用,而且容器與宿主機緊耦合,很難靈活的處理,可擴展性不佳。

  • docker外定製容器網絡:在容器經過docker建立完成後,而後再經過修改容器的網絡命名空間來定義容器網絡。典型的就是好久之前的pipework,容器以none模式建立,pipework經過進入容器的網絡命名空間爲容器從新配置網絡,這樣容器網絡能夠是靜態IP、vxlan網絡等各類方式,很是靈活,容器啓動的一段時間內會沒有IP,明顯沒法在大規模場景下使用,只能在實驗室中測試使用。

  • 第三方SDN定義容器網絡:使用Open vSwitch或Flannel等第三方SDN工具,爲容器構建能夠跨主機通訊的網絡環境。這些方案通常要求各個主機上的docker0網橋的cidr不一樣,以免出現IP衝突的問題,限制了容器在宿主機上的可獲取IP範圍。而且在容器須要對集羣外提供服務時,須要比較複雜的配置,對部署實施人員的網絡技能要求比較高。

上面這些方案有各類各樣的缺陷,同時也由於跨主機通訊的迫切需求,docker 1.9版本時,官方提出了基於vxlan的overlay網絡實現,原生支持容器的跨主機通訊。同時,還支持經過libnetwork的plugin機制擴展各類第三方實現,從而以不一樣的方式實現跨主機通訊。就目前社區比較流行的方案來講,跨主機通訊的基本實現方案有如下幾種:

  • 基於隧道的overlay網絡:按隧道類型來講,不一樣的公司或者組織有不一樣的實現方案。docker原生的overlay網絡就是基於vxlan隧道實現的。ovn則須要經過geneve或者stt隧道來實現的。flannel最新版本也開始默認基於vxlan實現overlay網絡。

  • 基於包封裝的overlay網絡:基於UDP封裝等數據包包裝方式,在docker集羣上實現跨主機網絡。典型實現方案有weaveflannel的早期版本。

  • 基於三層實現SDN網絡:基於三層協議和路由,直接在三層上實現跨主機網絡,而且經過iptables實現網絡的安全隔離。典型的方案爲Project Calico。同時對不支持三層路由的環境,Project Calico還提供了基於IPIP封裝的跨主機網絡實現。

下面,本從網絡通訊模型的角度,對這些方案的通訊原理作一個簡單的比較,從中能夠窺見各類方案在性能上的本質差異。

docker容器的CNM模型

首先,科普下docker容器的CNM網絡模型,calico、weave等第三方實現都是基於CNM模型與docker集成的。CNM網絡模型的結構以下圖所示:
docker-cnm-model

在上面的圖中:

  • Sandbox表明容器的網絡命名空間,包含了容器的完整網絡棧,不一樣的容器之間能夠徹底隔離。在宿主機上,就表現爲獨立的網絡命名空間。
  • Endpoint表明容器接入網絡的端點,能夠形象地認爲一個Endpoint對容器來講,就是一張物理網卡。
  • Network表明一組能夠直接相互通訊的Endpoint集合,能夠基於LinuxBridge或者VLAN實現。在宿主機上,每一個網絡都是一個獨立的網絡命名空間,宿主機上同一網絡的的容器,都經過veth pair連接到這個網絡命名空間上。

docker原生overlay的網絡通訊模型

docker官方文檔的示例中,overlay網絡是在swarm集羣中配置的,但實際上,overlay網絡能夠獨立於swarm集羣實現,只須要知足如下前提條件便可。

  • 有consul或者etcd,zookeeper的集羣key-value存儲服務

  • 組成集羣的全部主機的主機名不容許重複,由於docker守護進程與consul通訊時,以主機名相互區分

  • 全部主機均可以訪問集羣key-value的服務端口,按具體類型須要打開進行配置。例如docker daemon啓動時增長參數
    --cluster-store=etcd://<ETCD-IP>:4001 -
    -cluster-advertise=eth0:2376

  • overlay網絡依賴宿主機三層網絡的組播實現,須要在全部宿主機的防火牆上打開下列端口

協議 端口 說明
udp 4789 容器之間流量的vxlan端口
tcp/udp 7946 docker守護進程的控制端口

+ 宿主機內核版本3.10以上(1.9版本時,要求3.16以上)

知足以上條件後,就能夠經過docker network命令來建立跨主機的overlay網絡了,例如:
docker network create -d overlay overlaynet
在集羣的不一樣主機上,使用overlaynet這個網絡建立容器,造成以下圖所示的網絡拓撲:
docker-overlay-network

因爲容器和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-等序號,有時候不帶。但不影響網絡的通訊和操做。

從這個通訊過程當中來看,跨主機通訊過程當中的步驟以下:
1. 容器的網絡命名空間與overlay網絡的網絡命名空間經過一對veth pair鏈接起來,當容器對外通訊時,veth pair起到網線的做用,將流量發送到overlay網絡的網絡命名空間中。
2. 容器的veth pair對端eth2與vxlan設備經過br0這個Linux bridge橋接在一塊兒,br0在同一宿主機上起到虛擬機交換機的做用,若是目標地址在同一宿主機上,則直接通訊,若是再也不則經過設置在vxlan1這個vxlan設備進行跨主機通訊。
3. vxlan1設備上會在建立時,由docker daemon爲其分配vxlan隧道ID,起到網絡隔離的做用。
4. docker主機集羣經過key/value存儲共享數據,在7946端口上,相互之間經過gossip協議學習各個宿主機上運行了哪些容器。守護進程根據這些數據來在vxlan1設備上生成靜態MAC轉發表。
5. 根據靜態MAC轉發表的設置,經過UDP端口4789,將流量轉發到對端宿主機的網卡上。
6. 根據流量包中的vxlan隧道ID,將流量轉發到對端宿主機的overlay網絡的網絡命名空間中。
7. 對端宿主機的overlay網絡的網絡命名空間中br0網橋,起到虛擬交換機的做用,將流量根據MAC地址轉發到對應容器內部。

雖然上面的網絡通訊模型能夠實現容器的跨主機通訊,但仍是有一些缺陷,形成實際使用上的不便,例如:

  • 因爲vxlan網絡與宿主機網絡默認再也不同一網絡環境下,爲了解決宿主機與容器的通訊問題,docker爲overlay網絡中的容器額外增長了網卡eth1做爲宿主機與容器通訊的通道。這樣在使用容器服務時,就必須根據訪問性質的不一樣,選擇不一樣的網卡地址,形成使用上的不便。
  • 容器對外暴露服務仍然只能使用端口綁定的方式,外界沒法簡單地直接使用容器IP訪問容器服務。
  • 從上面的通訊過程當中來看,原生的overlay網絡通訊必須依賴docker守護進程及key/value存儲來實現網絡通訊,約束較多,容器在啓動後的一段時間內可能沒法跨主機通訊,這對一些比較敏感的應用來講是不可靠的。

weave網絡通訊模型

weave經過在docker集羣的每一個主機上啓動虛擬的路由器,將主機做爲路由器,造成互聯互通的網絡拓撲,在此基礎上,實現容器的跨主機通訊。其主機網絡拓撲參見下圖:
weave主機拓撲

如上圖所示,在每個部署Docker的主機(多是物理機也多是虛擬機)上都部署有一個W(即weave router,它自己也能夠以一個容器的形式部署)。weave網絡是由這些weave routers組成的對等端點(peer)構成,而且能夠經過weave命令行定製網絡拓撲。

每一個部署了weave router的主機之間都會創建TCP和UDP兩個鏈接,保證weave router之間控制面流量和數據面流量的經過。控制面由weave routers之間創建的TCP鏈接構成,經過它進行握手和拓撲關係信息的交換通訊。控制面的通訊能夠被配置爲加密通訊。而數據面由weave routers之間創建的UDP鏈接構成,這些鏈接大部分都會加密。這些鏈接都是全雙工的,而且能夠穿越防火牆。
當容器經過weave進行跨主機通訊時,其網絡通訊模型能夠參考下圖:
docker weave網絡拓撲

從上面的網絡模型圖中能夠看出,對每個weave網絡中的容器,weave都會建立一個網橋,而且在網橋和每一個容器之間建立一個veth pair,一端做爲容器網卡加入到容器的網絡命名空間中,併爲容器網卡配置ip和相應的掩碼,一端鏈接在網橋上,最終經過宿主機上weave router將流量轉發到對端主機上。其基本過程以下:

  1. 容器流量經過veth pair到達宿主機上weave router網橋上。
  2. weave router在混雜模式下使用pcap在網橋上截獲網絡數據包,並排除由內核直接經過網橋轉發的數據流量,例如本子網內部、本地容器之間的數據以及宿主機和本地容器之間的流量。捕獲的包經過UDP轉發到所其餘主機的weave router端。
  3. 在接收端,weave router經過pcap將包注入到網橋上的接口,經過網橋的上的veth pair,將流量分發到容器的網卡上。

weave默認基於UDP承載容器之間的數據包,而且能夠徹底自定義整個集羣的網絡拓撲,但從性能和使用角度來看,仍是有比較大的缺陷的:

  • weave自定義容器數據包的封包解包方式,不夠通用,傳輸效率比較低,性能上的損失也比較大。
  • 集羣配置比較負載,須要經過weave命令行來手工構建網絡拓撲,在大規模集羣的狀況下,加劇了管理員的負擔。

calico網絡通訊模型

calico是純三層的SDN 實現,它基於BPG 協議和Linux自身的路由轉發機制,不依賴特殊硬件,容器通訊也不依賴iptables NAT或Tunnel 等技術。可以方便的部署在物理服務器、虛擬機(如 OpenStack)或者容器環境下。同時calico自帶的基於iptables的ACL管理組件很是靈活,可以知足比較複雜的安全隔離需求。

在主機網絡拓撲的組織上,calico的理念與weave相似,都是在主機上啓動虛擬機路由器,將每一個主機做爲路由器使用,組成互聯互通的網絡拓撲。當安裝了calico的主機組成集羣后,其拓撲以下圖所示:
calico主機拓撲

每一個主機上都部署了calico/node做爲虛擬路由器,而且能夠經過calico將宿主機組織成任意的拓撲集羣。當集羣中的容器須要與外界通訊時,就能夠經過BGP協議將網關物理路由器加入到集羣中,使外界能夠直接訪問容器IP,而不須要作任何NAT之類的複雜操做。

當容器經過calico進行跨主機通訊時,其網絡通訊模型以下圖所示:
calico容器通訊

從上圖能夠看出,當容器建立時,calico爲容器生成veth pair,一端做爲容器網卡加入到容器的網絡命名空間,並設置IP和掩碼,一端直接暴露在宿主機上,並經過設置路由規則,將容器IP暴露到宿主機的通訊路由上。於此同時,calico爲每一個主機分配了一段子網做爲容器可分配的IP範圍,這樣就能夠根據子網的CIDR爲每一個主機生成比較固定的路由規則。

當容器須要跨主機通訊時,主要通過下面的簡單步驟:

  1. 容器流量經過veth pair到達宿主機的網絡命名空間上。
  2. 根據容器要訪問的IP所在的子網CIDR和主機上的路由規則,找到下一跳要到達的宿主機IP。
  3. 流量到達下一跳的宿主機後,根據當前宿主機上的路由規則,直接到達對端容器的veth pair插在宿主機的一端,最終進入容器。

從上面的通訊過程來看,跨主機通訊時,整個通訊路徑徹底沒有使用NAT或者UDP封裝,性能上的損耗確實比較低。但正式因爲calico的通訊機制是徹底基於三層的,這種機制也帶來了一些缺陷,例如:

    • calico目前只支持TCP、UDP、ICMP、ICMPv6協議,若是使用其餘四層協議(例如NetBIOS協議),建議使用weave、原生overlay等其餘overlay網絡實現。
    • 基於三層實現通訊,在二層上沒有任何加密包裝,所以只能在私有的可靠網絡上使用。
    • 流量隔離基於iptables實現,而且從etcd中獲取須要生成的隔離規則,有一些性能上的隱患。

轉載:http://blog.csdn.net/yarntime/article/details/51258824

相關文章
相關標籤/搜索