在之前的文章中已經介紹過單主機Docker容器的網絡互聯,但是實際生産中我們很多時候都是多台主機部署Docker環境,且每台主機上都運作數量不等的容器,如果需要這些容器共同提供服務,就需要解決跨主機容器間的網絡通信問題,是以這裡就來記錄一下常用的跨主機容器間的網絡通信方案。
Docker主機之間容器通信解決方案:
橋接主控端網絡
端口映射
Docker網絡驅動
○ Overlay:基于VXLAN封裝實作Docker原生Overlay網絡
○ Macvlan:Docker主機網卡接口邏輯上分為多個子接口,每個子接口辨別一個VLAN。容器接口直接連接配接Docker主機網卡接口,通過路由政策轉發到另一台Docker主機
第三方網絡項目
○ 隧道方案
☑ Flannel:支援UDP和VXLAN封裝傳輸方式
☑ Weave:支援UDP(sleeve模式)和VXLAN(優先fastdp模式)
☑ OpenvSwitch:支援VXLAN和GRE協定
○ 路由方案
☑ Calico:支援BGP協定和IPIP隧道。每台主控端作為虛拟路由,通過BGP協定實作不同主機容器間通信
環境準備:
IP位址
主機名
Docker版本
系統(核心版本)
節點1
192.168.49.41
docker01.contoso.com
1.13.1
CentOS 7(3.10.0-693.el7.x86_64)
節點2
192.168.49.42
docker02.contoso.com
CentOS 7(3.10.0-693.el7.x86_64)
橋接模式:
對橋接模式而言,主控端位于同一個區域網路,将每一個主控端上的容器網絡橋接到主控端網絡中,容器和主控端同在一個區域網路中,因而可以互相通信。
1)在主控端上建立網橋(如不特别指明,以下指令均需在兩台主機上執行)
2)給網橋配置IP位址
3)檢視網橋資訊
4)配置Docker啟動選項
5)重新開機docker服務
6)建立容器并驗證
在Docker01上執行:
在Docker02上執行:
在Docker01上上驗證:
在Docker02上上驗證:
結論:橋接模式是跨主機容器網絡互聯較簡答的一種方式,直接将容器網絡橋接到區域網路中,這樣容器和主控端就在同一網段,友善進行容器操作。但因為每台主機上的容器都直接從區域網路中擷取IP位址,卻沒有統一對不同主機上容器擷取的IP位址進行登記,很容易導緻IP位址沖突,雖然可以通過使用--fixed-cidr來指定,但是這樣隔離網段也不太友善,網絡劃分需注意。
端口映射:
端口映射,顧名思義就是将容器的服務所運作的端口映射到主控端的某一個端口,然後其他的容器通過主控端的對應端口進行通路。
1)建立帶端口映射的容器
因為使用端口映射的方式,是以不需要單獨建立容器網絡,我們使用預設的docker0網絡即可。
2)在主控端的防火牆中檢視端口映射
3)測試容器間通信
在nat01上執行:
在nat02上執行:
結論:使用端口映射的方式,隻是将容器的端口通過NAT方式映射到主控端網絡的某一個端口,隻要主控端能互相通信,容器之間就能通過主控端的指定端口進行通信。但是這種方式需要對每一個容器都映射端口,而且主控端的端口也是有限的(不可複用),是以會有一定的局限性。
Overlay網絡:
overlay 網絡驅動程式在多個 Docker 守護程序主機之間建立一個分布式網絡。這個網絡在允許容器連接配接并進行安全通信的主機專用網絡之上(overlay 覆寫在上面)。Docker 透明地處理每個 Docker 守護程序與目标容器之間的資料包的路由。
Docker通過Overlay網絡驅動程式支援多主機容器網絡通信。要想使用Docker原生Overlay網絡,需要滿足以下任意條件:
Docker運作在Swarm模式
使用鍵值存儲的Docker主機叢集
這裡我選擇第二種方式,需滿足以下條件:
1)叢集中主機連接配接到鍵值存儲,Docker支援Consul、Etcd和Zookeeper
2)叢集中主機運作一個Docker守護程序
3)叢集中主機必須具有唯一的主機名,因為鍵值存儲使用主機名來辨別叢集成員
4)叢集中Linux主機核心版本3.12+,支援VXLAN資料包處理,否則可能無法通信
節點1:docker01 192.168.49.41 鍵值存儲
節點2:docker02 192.168.49.42
實作過程:
1)在節點1上下載下傳并安裝consul
2)在節點1上啟動consul服務
3)修改節點1上的docker守護程序
4)同樣的方法修改節點2的docker守護程序
5)到consul的UI界面檢視節點是否添加

6)在docker主機上建立overlay網絡
7)分别在兩個節點上建立容器
檢測容器是否可以互相通信:
工作原理:
在講解原理之前,先看看容器上的網絡資訊,這會給我們容器間通信的一些提示。
節點1上的容器網絡:
節點2上的容器網絡:
我們看到每個容器都有2張網卡,而這個172.20.0.0/24的網段是哪裡來的呢?再來看看docker主機的網絡資訊:
在節點1上:
在節點2上:
或許我們檢視網橋資訊會更直接一些:
我們再檢視namespace:
由于容器和overlay的網絡的網絡命名空間檔案不在作業系統預設的/var/run/netns下,隻能手動通過軟連接配接的方式檢視。
可以看見兩個節點主機上都有這個“1-”開頭的的namespace
檢視這個namespace中的網卡資訊(以其中一台為例):
我們看到namespace中有一個網橋br0,再檢視這個網橋的資訊:
檢視VNI(Vxlan Network identifier):
檢視vlan裝置上的靜态mac位址表:
綜上,overlay網絡的拓補如下:
這裡資料包的發送流程如下(以從左側的容器發送到右側的容器為例):
容器Container1會通過Container eth0 将這個資料包發送到 10.0.0.1 的網關。
網關将資料包發送出去後到達br0網橋。
br0網橋針對VXLAN裝置,主要用于捕獲對外的資料包通過VETP進行資料包封裝。
封裝好将VXLAN格式資料包交給eth0,通過UDP方式交給Container2的eth0。
Container2收到資料包後通過VETP将資料包解封裝。
網橋通過網關将解封裝的資料包轉發給Container eth0,完畢通信。
是以,Docker容器的overlay網絡的實作原理是:
1、docker會為每個overlay網絡建立個單獨的命名空間,在這個命名空間裡建立了個br0的bridge。
2、在這個命名空間内建立兩張網卡并挂載到br0上,建立一對veth pair端口 和vxlan裝置。
3、veth pair一端接在namespace的br0上,另一端接在container上。
4、vxlan裝置用于建立vxlan tunnel,vxlan端口的vni由docker-daemon在建立時配置設定,具有相同vni的裝置才能通信。
5、docker主機叢集通過key/value存儲(我們這裡用的是consul)共享資料,在7946端口上,互相之間通過gossip協定學習各個主控端上運作了哪些容器。守護程序根據這些資料來在vxlan裝置上生成靜态MAC轉發表。
6、vxlan裝置根據靜态mac轉發表,通過host上的4789端口将資料發到目标節點。
7、根據流量包中的vxlan隧道ID,将流量轉發到對端主控端的overlay網絡的網絡命名空間中。
8、對端主控端的overlay網絡的網絡命名空間中br0網橋,起到虛拟交換機的作用,将流量根據MAC位址轉發到對應容器内部。
(上述原理分析部分參考:https://www.bladewan.com/2017/11/17/docker_network_overlay/)
補充:如需詳細了解docker overlay網絡的實作過程,可以參考:http://chenchun.github.io/docker/2015/12/29/km-docker-overlay
Macvlan網絡:
macvlan本身是linxu kernel的子產品,本質上是一種網卡虛拟化技術。其功能是允許在同一個實體網卡上虛拟出多個網卡,通過不同的MAC位址在資料鍊路層進行網絡資料的轉發,一塊網卡上配置多個 MAC 位址(即多個 interface),每個interface可以配置自己的IP,Docker的macvlan網絡實際上就是使用了Linux提供的macvlan驅動.在實體網絡看來,每張虛拟網卡都是一個單獨的接口。
1)建立macvlan網絡
節點1:
節點2:
2)建立容器并指定IP位址
3)測試容器通信
Macvlan VLAN Bridge模式:
因為之前的操作都是在VMware Workstation虛拟機中進行,自己嘗試在VMware中的Centos7中做macvlan網卡子接口vlan網絡容器互通的測試,但是無一例外全部都無法通信,即使是開啟了網卡的混雜模式,也都不行。網上給出的方案是使用VirtualBox,但是個人使用VirtualBox+CentOS7仍然無法通信,是以改用VirtualBox+Ubuntu 16.04,測試成功,是以下面改用Ubuntu 16.04進行示範。
172.16.3.11
docker01
17.05.0-ce
Ubuntu 16.04.3 LTS(4.4.0-87-generic)
172.16.3.22
docker02
1)建立vlan
在兩個節點上操作:
2)建立macvlan網絡
3)使用macvlan建立容器
4)測試網絡是否能通信
這裡,同一個vlan的兩個節點上的容器可以通信,不同vlan的容器(無論是同一個節點還是不同節點)均不能通信,當然可以通過添加路由的方式讓不同vlan的容器通信,但是vlan劃分的目的就是隔絕網絡,是以這裡不再示範讓不同vlan容器通信的方法,網上類似的教程也很多,大家自行查找即可。