docker網絡模式

  docker 在早前的時候沒有考慮跨主機的容器通信,這個特性直到 docker 1.9 纔出現。在此之前,如果希望位於不同主機的容器能夠通信,一般有幾種方法:

  • 1、使用端口映射:直接把容器的服務端口映射到主機上,主機直接通過映射出來的端口通信

  • 2、把容器放到主機所在的網段:修改 docker 的 ip 分配網段和主機一致,還要修改主機的網絡結構

  • 3、第三方項目:flannel,weave 或者 pipework 等,這些方案一般都是通過 SDN 搭建 overlay 網絡達到容器通信的

  隨着 docker 1.9 的發佈,一個新的網絡模型被開發出來。除了能更方便地按照需求來搭建自己的網絡方案,這次發佈還讓 docker 具備了跨主機通信的功能。

  一、我們先簡單的說一下早期的主機內部容器通信的四種網絡模式:

     1 host模式

     衆所周知,Docker使用了Linux的Namespaces技術來進行資源隔離,如PID Namespace隔離進程,Mount Namespace隔離文件系統,Network Namespace隔離網絡等。一個Network Namespace提供了一份獨立的網絡環境,包括網卡、路由、Iptable規則等都與其他的Network Namespace隔離。一個Docker容器一般會分配一個獨立的Network Namespace。但如果啓動容器的時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。

例如,我們在10.10.101.105/24的機器上用host模式啓動一個含有web應用的Docker容器,監聽tcp80端口。當我們在容器中執行任何類似ifconfig命令查看網絡環境時,看到的都是宿主機上的信息。而外界訪問容器中的應用,則直接使用10.10.101.105:80即可,不用任何NAT轉換,就如直接跑在宿主機中一樣。但是,容器的其他方面,如文件系統、進程列表等還是和宿主機隔離的。

     2 container模式

     在理解了host模式後,這個模式也就好理解了。這個模式指定新創建的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過lo網卡設備通信。

     3 none模式

     這個模式和前兩個不同。在這種模式下,Docker容器擁有自己的Network Namespace,但是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。需要我們自己爲Docker容器添加網卡、配置IP等。

     4 bridge模式

     bridge模式是Docker默認的網絡設置,此模式會爲每一個容器分配Network Namespace、設置IP等,並將一個主機上的Docker容器連接到一個虛擬網橋上。

    UJFBrui.png!web

     二、第三方的跨主機通信以pipwork和flannel爲例

     2.1 pipwork

     pipework是由Docker的工程師Jérme Petazzoni開發的一個Docker網絡配置工具,由200多行shell實現,方便易用。下面用三個場景來演示pipework的使用和工作原理。


  爲了使本地網絡中的機器和Docker容器更方便的通信,我們經常會有將Docker容器配置到和主機同一網段的需求。這個需求其實很容易實現,我們只要將Docker容器和主機的網卡橋接起來,再給Docker容器配上IP就可以了。

  下面我們來操作一下,我主機A地址爲10.10.101.105/24,網關爲10.10.101.254,需要給Docker容器的地址配置爲10.10.101.150/24。在主機A上做如下操作:

安裝pipework

git clone https://github.com/jpetazzo/pipework 
cp ~/pipework/pipework /usr/local/bin/

啓動Docker容器。

docker run -itd --name test1 ubuntu /bin/bash

配置容器網絡,並連到網橋br0上。網關在IP地址後面加@指定。

若主機環境中存在dhcp服務器,也可以通過dhcp的方式獲取IP

pipework br0 test1 dhcp
pipework br0 test1 10.10.101.150/[email protected]

將主機eth0橋接到br0上,並把eth0的IP配置在br0上。這裏由於是遠程操作,中間網絡會斷掉,所以放在一條命令中執行。

ip addr add 10.10.101.105/24 dev br0; 
ip addr del 10.10.101.105/24 dev eth0;
brctl addif br0 eth0;
ip route del default;
ip route add default gw 10.10.101.254 dev br0

完成上述步驟後,我們發現Docker容器已經可以使用新的IP和主機網絡裏的機器相互通信了。

pipework工作原理分析

那麼容器到底發生了哪些變化呢?我們docker attach到test1上,發現容器中多了一塊eth1的網卡,並且配置了10.10.101.150/24的IP,而且默認路由也改爲了10.10.101.254。這些都是pipework幫我們配置的。通過查看源代碼,可以發現pipework br0 test1 10.10.101.150/24 @10.10.101.254是由以下命令完成的(這裏只列出了具體執行操作的代碼)。

創建br0網橋

若ovs開頭,則創建OVS網橋 ovs-vsctl add-br ovs*

brctl addbr $IFNAME

創建veth pair,用於連接容器和br0

ip link add name $LOCALIFNAME mtu $MTU type veth peer name $GUESTIFNAME mtu $MTU

找到Docker容器test1在主機上的PID,創建容器網絡命名空間的軟連接

DOCKERPID=$(docker inspect --format='` `.`State`.`Pid `' $GUESTNAME) 
ln -s /proc/$NSPID/ns/net /var/run/netns/$NSPID

將veth pair一端放入Docker容器中,並設置正確的名字eth1

ip link set $GUESTIFNAME netns $NSPID 
ip netns exec $NSPID ip link set $GUESTIFNAME name $CONTAINER_IFNAME

將veth pair另一端加入網橋

若爲OVS網橋則爲 ovs-vsctl add-port $IFNAME $LOCAL_IFNAME ${VLAN:+"tag=$VLAN"}

brctl addif $IFNAME $LOCAL_IFNAME

爲新增加的容器配置IP和路由

ip netns exec $NSPID ip addr add $IPADDR dev $CONTAINERIFNAME 
ip netns exec $NSPID ip link set $CONTAINERIFNAME up
ip netns exec $NSPID ip route
delete default ip netns exec $NSPID ip route add $GATEWAY/32 dev $CONTAINER_IFNAME
  1. 首先pipework檢查是否存在br0網橋,若不存在,就自己創建。若以"ovs"開頭,就會創建OpenVswitch網橋,以"br"開頭,創建Linux bridge。

  2. 創建veth pair設備,用於爲容器提供網卡並連接到br0網橋。

  3. 使用docker inspect找到容器在主機中的PID,然後通過PID將容器的網絡命名空間鏈接到/var/run/netns/目錄下。這麼做的目的是,方便在主機上使用ip netns命令配置容器的網絡。因爲,在Docker容器中,我們沒有權限配置網絡環境。

  4. 將之前創建的veth pair設備分別加入容器和網橋中。在容器中的名稱默認爲eth1,可以通過pipework的-i參數修改該名稱。

  5. 然後就是配置新網卡的IP。若在IP地址的後面加上網關地址,那麼pipework會重新配置默認路由。這樣容器通往外網的流量會經由新配置的eth1出去,而不是通過eth0和docker0。(若想完全拋棄自帶的網絡設置,在啓動容器的時候可以指定--net=none)

以上就是pipework配置Docker網絡的過程,這和Docker的bridge模式有着相似的步驟。事實上,Docker在實現上也採用了相同的底層機制。

通過源代碼,可以看出,pipework通過封裝Linux上的ip、brctl等命令,簡化了在複雜場景下對容器連接的操作命令,爲我們配置複雜的網絡拓撲提供了一個強有力的工具。當然,如果想了解底層的操作,我們也可以直接使用這些Linux命令來完成工作,甚至可以根據自己的需求,添加額外的功能。

單主機Docker容器VLAN劃分

pipework不僅可以使用Linux bridge連接Docker容器,還可以與OpenVswitch結合,實現Docker容器的VLAN劃分。下面,就來簡單演示一下,在單機環境下,如何實現Docker容器間的二層隔離。

爲了演示隔離效果,我們將4個容器放在了同一個IP網段中。但實際他們是二層隔離的兩個網絡,有不同的廣播域。

在主機A上創建4個Docker容器,test1、test2、test3、test4

docker run -itd --name test1 ubuntu /bin/bash 
docker run -itd --name test2 ubuntu /bin/bash
docker run -itd --name test3 ubuntu /bin/bash
docker run -itd --name test4 ubuntu /bin/bash

將test1,test2劃分到一個vlan中,vlan在mac地址後加@指定,此處mac地址省略。

pipework ovs0 test1 192.168.0.1/24 @100 
pipework ovs0 test2 192.168.0.2/24 @100

將test3,test4劃分到另一個vlan中

pipework ovs0 test3 192.168.0.3/24 @200 
pipework ovs0 test4 192.168.0.4/24 @200

完成上述操作後,使用docker attach連到容器中,然後用ping命令測試連通性,發現test1和test2可以相互通信,但與test3和test4隔離。這樣,一個簡單的VLAN隔離容器網絡就已經完成。

由於OpenVswitch本身支持VLAN功能,所以這裏pipework所做的工作和之前介紹的基本一樣,只不過將Linux bridge替換成了OpenVswitch,在將veth pair的一端加入ovs0網橋時,指定了tag。底層操作如下:

ovs-vsctl add-port ovs0 veth* tag=100

2.3 多主機Docker容器的VLAN劃分

上面介紹完了單主機上VLAN的隔離,下面我們將情況延伸到多主機的情況。有了前面兩個例子做鋪墊,這個也就不難了。爲了實現這個目的,我們把宿主機上的網卡橋接到各自的OVS網橋上,然後再爲容器配置IP和VLAN就可以了。我們實驗環境如下,主機A和B各有一塊網卡eth0,IP地址分別爲10.10.101.105/24、10.10.101.106/24。在主機A上創建兩個容器test1、test2,分別在VLAN 100和VLAN 200上。在主機B上創建test3、test4,分別在VLAN 100和VLAN 200 上。最終,test1可以和test3通信,test2可以和test4通信。

在主機A上

創建Docker容器

docker run -itd --name test1 ubuntu /bin/bash 
docker run -itd --name test2 ubuntu /bin/bash

劃分VLAN

pipework ovs0 test1 192.168.0.1/24 @100 
pipework ovs0 test2 192.168.0.2/24 @200

將eth0橋接到ovs0上

ip addr add 10.10.101.105/24 dev ovs0
ip addr del 10.10.101.105/24 dev eth0
ovs-vsctl add-port ovs0 eth0
ip route del default
ip route add default gw 10.10.101.254 dev ovs0

在主機B上

創建Docker容器

docker run -itd --name test3 ubuntu /bin/bash 
docker run -itd --name test4 ubuntu /bin/bash

劃分VLAN

pipework ovs0 test1 192.168.0.3/24 @100 
pipework ovs0 test2 192.168.0.4/24 @200

將eth0橋接到ovs0上

ip addr add 10.10.101.106/24 dev ovs0
ip addr del 10.10.101.106/24 dev eth0
ovs-vsctl add-port ovs0 eth0
ip route del default
ip route add default gw 10.10.101.254 dev ovs0

完成上面的步驟後,主機A上的test1和主機B上的test3容器就劃分到了一個VLAN中,並且與主機A上的test2和主機B上的test4隔離(主機eth0網卡需要設置爲混雜模式,連接主機的交換機端口應設置爲trunk模式,即允許VLAN 100和VLAN 200的包通過)。拓撲圖如下所示(省去了Docker默認的eth0網卡和主機上的docker0網橋):

VB3iayF.png!web

除此之外,pipework還支持使用macvlan設備、設置網卡MAC地址等功能。不過,pipework有一個缺陷,就是配置的容器在關掉重啓後,之前的設置會丟失。

總結

通過上面的介紹,我相信大家對Docker的網絡已經有了一定的瞭解。對於一個基本應用而言,Docker的網絡模型已經很不錯了。然而,隨着雲計算和微服務的興起,我們不能永遠停留在使用基本應用的級別上,我們需要性能更好且更靈活的網絡功能。pipework正好滿足了我們這樣的需求,從上面的樣例中,我們可以看到pipework的方便之處。但是,同時也應注意到,pipework並不是一套解決方案,它只是一個網絡配置工具,我們可以利用它提供的強大功能,幫助我們構建自己的解決方案。



     2.2 flannel

         Flannel是CoreOS團隊針對Kubernetes設計的一個網絡規劃服務,簡單來說,它的功能是讓集羣中的不同節點主機創建的Docker容器都具有全集羣唯一的虛擬IP地址。

     在Kubernetes的網絡模型中,假設了每個物理節點應該具備一段“屬於同一個內網IP段內”的“專用的子網IP”。例如:

節點A:10.0.1.0/24
節點B:10.0.2.0/24
節點C:10.0.3.0/24


     但在默認的Docker配置中,每個節點上的Docker服務會分別負責所在節點容器的IP分配。這樣導致的一個問題是,不同節點上容器可能獲得相同的內外IP地址。並使這些容器之間能夠之間通過IP地址相互找到,也就是相互ping通。

     Flannel的設計目的就是爲集羣中的所有節點重新規劃IP地址的使用規則,從而使得不同節點上的容器能夠獲得“同屬一個內網”且”不重複的”IP地址,並讓屬於不同節點上的容器能夠直接通過內網IP通信。

01.png

     這張圖的信息量很全,下面簡單的解讀一下。

     數據從源容器中發出後,經由所在主機的docker0虛擬網卡轉發到flannel0虛擬網卡,這是個P2P的虛擬網卡,flanneld服務監聽在網卡的另外一端。

     Flannel通過Etcd服務維護了一張節點間的路由表,在稍後的配置部分我們會介紹其中的內容。

     源主機的flanneld服務將原本的數據內容UDP封裝後根據自己的路由表投遞給目的節點的flanneld服務,數據到達以後被解包,然後直接進入目的節點的flannel0虛擬網卡,然後被轉發到目的主機的docker0虛擬網卡,最後就像本機容器通信一下的有docker0路由到達目標容器。

     這樣整個數據包的傳遞就完成了,這裏需要解釋三個問題。

     三、docker自有的跨主機通信網絡解決方案:macvlan、overlay network

     3.1 macvlan

  Macvlan工作原理

  • Macvlan是Linux內核支持的網絡接口。要求的Linux內部版本是v3.9–3.19和4.0+。

  • 通過爲物理網卡創建Macvlan子接口,允許一塊物理網卡擁有多個獨立的MAC地址和IP地址。虛擬出來的子接口將直接暴露在底層物理網絡中。從外界看來,就像是把網線分成多股,分別接到了不同的主機上一樣。

  • Macvlan有四種工作模式:Private、VEPA、Bridge和Passthru。最常用和默認的模式是Bridge模式。

  • 物理網卡收到包後,會根據收到包的目的MAC地址判斷這個包需要交給哪個虛擬網卡。

U7nQJb.png!web

  • 如果配合Network Namespace 使用,可以構建這樣的網絡:

7v6zaef.png!web

  四種模式

  • private mode:過濾掉所有來自其他 macvlan 接口的報文,因此不同 macvlan 接口之間無法互相通信

  • vepa(Virtual Ethernet Port Aggregator) mode: 需要主接口連接的交換機支持 VEPA/802.1Qbg 特性。所有發送出去的報文都會經過交換機,交換機作爲再發送到對應的目標地址(即使目標地址就是主機上的其他 macvlan 接口),也就是 hairpin mode 模式,這個模式用在交互機上需要做過濾、統計等功能的場景。

  • bridge mode:通過虛擬的交換機講主接口的所有 macvlan 接口連接在一起,這樣的話,不同 macvlan 接口之間能夠直接通信,不需要將報文發送到主機之外。這個模式下,主機外是看不到主機上 macvlan interface 之間通信的報文的。

  • passthru mode:暫時沒有搞清楚這個模式要解決的問題

 環境準備 

一共兩臺機器:兩臺機器都安裝Docker且內核版本>3.9。

主機名IP地址軟件環境
dev-master-01192.168.2.210kernel>3.9,Docker
dev-node-01192.168.2.211kernel>3.9,Docker

 啓用網卡混雜模式

兩臺機器設置使用橋接模式,網卡混雜模式開啓全部允許。

主機上配置的enp0s5網口或者創建的vlan網口,均需要開啓混雜模式。如果不開啓混雜模式會導致macvlan網絡無法訪問外界,具體在不使用vlan時,表現爲無法ping通路由,無法ping通同一網絡內其他主機。

設置混雜模式可以通過ip或ifconfig指令實現。

   通過ip指令設置enp0s5爲混雜模式

$ ip link set enp0s5  promisc on

取消enp0s5的混雜模式

$ ip link set enp0s5  promisc off
  • 通過ifconfig指令

設置enp0s5爲混雜模式

$ ifconfig enp0s5 promisc

取消enp0s5的混雜模式

$ ifconfig enp0s5 -promisc

驗證網卡混雜模式是否設置成功

$ ifconfig enp0s5
enp0s5    Link encap:Ethernet  HWaddr 00:1c:42:97:53:2a
         inet addr:192.168.2.210  Bcast:192.168.2.255  Mask:255.255.255.0
         inet6 addr: fe80::21c:42ff:fe97:532a/64 Scope:Link
         UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
         RX packets:1059321 errors:0 dropped:145 overruns:0 frame:0
         TX packets:15030 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1000
         RX bytes:785317867 (785.3 MB)  TX bytes:1039141 (1.0 MB)

其中 UP BROADCAST RUNNING PROMISC MULTICAST的PROMISC 說明網卡enp0s5已經設置成混雜模式。 

使用Macvlan構建Docker網絡 

兩臺主機上均使用enp0s5網卡創建一個192.168.2.0網段的macvlan網絡。macvlan驅動實際上是利用的Linux macvlan內核驅動,這意味着這樣子運行的容器,網絡通訊將會直接送到下層vlan。這是目前最高網絡效率的驅動。這裏沒有NAT,沒有端口映射,通訊直接通過VLan送出。

   master主機

創建macvlan網絡

$ docker network create -d macvlan --subnet 192.168.2.0/24 --gateway 192.168.2.1 -o parent=enp0s5 -o macvlan_mode=bridge macnet0ab39da89dd66238a1e9c75edbb70afa9b09d13dc5f1a041f5dd46c369856225

macvlan是kernel的模塊名。

192.168.2.0/24是宿主機所在網絡的網段。

192.168.2.1是網關。

enp0s5是宿主機接入192.168.2.0/24的網絡設備。

查看macvlan是否創建成功

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e13c13e22f73        bridge              bridge              locala56cfbac20ed        docker_gwbridge     bridge              local0b703c3d9cb8        host                host                localabdb4b9f751c        none                null                local0ab39da89dd6        macnet              macvlan             local856b6dbf7e83        weave               weavemesh           local

創建兩個使用macvlan容器

創建容器c1

$ docker run -id --net macnet --ip 192.168.2.220 --name c1 busybox sh6120c05c90ae75658f6703a269da453a4c516686144cc53dad027af7410cc93c# 查看容器IP$ docker exec c1 ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever30: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
   link/ether 02:42:c0:a8:02:dc brd ff:ff:ff:ff:ff:ff
   inet 192.168.2.220/24 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::42:c0ff:fea8:2dc/64 scope link
      valid_lft forever preferred_lft forever# 查看容器route$ docker exec c1  route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth0192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

創建容器c2

$ docker run -id --net macnet --ip 192.168.2.221 --name c2 busybox sh
f8bcf7a103ac483fd46ee27ac675b23255bf64ad49c7e70be8785737add1ce06# 查看容器IP$ docker exec c2 ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever31: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
   link/ether 02:42:c0:a8:02:dd brd ff:ff:ff:ff:ff:ff
   inet 192.168.2.221/24 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::42:c0ff:fea8:2dd/64 scope link
      valid_lft forever preferred_lft forever# 查看容器route$ docker exec c2  route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth0192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
  • node主機

創建macvlan網絡

$ docker network create -d macvlan --subnet 192.168.2.0/24 --gateway 192.168.2.1 -o parent=enp0s5 -o macvlan_mode=bridge macnetad869482ddc115acf6ee004a500ce7c28386e976c4bb5eccdffaaa1afbcd07e1

macvlan是kernel的模塊名。

192.168.2.0/24是宿主機所在網絡的網段。

192.168.2.1是網關。

enp0s5是宿主機接入192.168.2.0/24的網絡設備。

查看macvlan是否創建成功

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e13c13e22f73        bridge              bridge              locala56cfbac20ed        docker_gwbridge     bridge              local0b703c3d9cb8        host                host                local2b2067e669d4        macnet              macvlan             localabdb4b9f751c        none                null                local856b6dbf7e83        weave               weavemesh           local

創建兩個使用macvlan容器

創建容器c3

$ docker run -id --net macnet --ip 192.168.2.222 --name c3 busybox sh8b6a83f73af9dd54ef24be80bf946f0e10959e48ead12a09514d3c59a287927c# 查看容器IP$ docker exec c3 ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever18: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
   link/ether 02:42:c0:a8:02:ca brd ff:ff:ff:ff:ff:ff
   inet 192.168.2.222/24 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::42:c0ff:fea8:2ca/64 scope link
      valid_lft forever preferred_lft forever# 查看容器route$ docker exec c3  route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth0192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

創建容器c4

$ docker run -id --net macnet --ip 192.168.2.223 --name c4 busybox sh
c7be679190467564023aec1fd908bb7418a55f41ab548d59d77cabf187dc665c# 查看容器IP$ docker exec c4 ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever20: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
   link/ether 02:42:c0:a8:02:df brd ff:ff:ff:ff:ff:ff
   inet 192.168.2.223/24 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::42:c0ff:fea8:2df/64 scope link
      valid_lft forever preferred_lft forever# 查看容器route$ docker exec c4  route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth0192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

測試網絡連通情況

BzmuiyY.png!web

所有測試在master主機上進行。

  • ping網關

$ docker exec c1 ping -c 3 192.168.2.1PING 192.168.2.1 (192.168.2.1): 56 data bytes64 bytes from 192.168.2.1: seq=0 ttl=255 time=1.594 ms64 bytes from 192.168.2.1: seq=1 ttl=255 time=0.659 ms64 bytes from 192.168.2.1: seq=2 ttl=255 time=0.753 ms

--- 192.168.2.1 ping statistics ---3 packets transmitted, 3 packets received, 0% packet lo***ound-trip min/avg/max = 0.659/1.002/1.594 ms

測試結果:通

  • 使用容器名ping本主機容器

$ docker exec c1 ping -c3 c1
PING c1 (192.168.2.220): 56 data bytes64 bytes from 192.168.2.220: seq=0 ttl=64 time=0.053 ms64 bytes from 192.168.2.220: seq=1 ttl=64 time=0.073 ms64 bytes from 192.168.2.220: seq=2 ttl=64 time=0.048 ms

--- c1 ping statistics ---3 packets transmitted, 3 packets received, 0% packet lo***ound-trip min/avg/max = 0.048/0.058/0.073 ms

測試結果:通

  • ping本主機容器

$ docker exec c1 ping -c3 192.168.2.220PING 192.168.2.220 (192.168.2.220): 56 data bytes64 bytes from 192.168.2.220: seq=0 ttl=64 time=0.069 ms64 bytes from 192.168.2.220: seq=1 ttl=64 time=0.172 ms64 bytes from 192.168.2.220: seq=2 ttl=64 time=0.079 ms

--- 192.168.2.220 ping statistics ---3 packets transmitted, 3 packets received, 0% packet lo***ound-trip min/avg/max = 0.069/0.106/0.172 ms

測試結果:通

  • ping另一主機容器

$ docker exec c1 ping -c2  192.168.2.222PING 192.168.2.222 (192.168.2.222): 56 data bytes64 bytes from 192.168.2.222: seq=0 ttl=255 time=0.788 ms64 bytes from 192.168.2.222: seq=1 ttl=255 time=0.383 ms

--- 192.168.2.222 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.383/0.585/0.788 ms

測試結果:通

  • 使用容器名ping另一主機容器:

$ docker exec c1 ping -c2 c3
ping: bad address 'c3'

測試結果:不通

  • 本主機ping本主機容器: 不通

$ ping -c 2 192.168.2.220PING 192.168.2.220 (192.168.2.220) 56(84) bytes of data.From 192.168.2.210 icmp_seq=1 Destination Host UnreachableFrom 192.168.2.210 icmp_seq=2 Destination Host Unreachable--- 192.168.2.220 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1000ms

測試結果:不通

  • 本主機ping另一主機容器

$ ping -c 2 192.168.2.222PING 192.168.2.222 (192.168.2.222) 56(84) bytes of data.64 bytes from 192.168.2.222: icmp_seq=1 ttl=255 time=0.308 ms64 bytes from 192.168.2.222: icmp_seq=2 ttl=255 time=0.343 ms

--- 192.168.2.222 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.308/0.325/0.343/0.025 ms

測試結果:通

  • 本主機上容器到另一臺宿主IP

$ docker exec c2 ping -c 2 192.168.2.211PING 192.168.2.211 (192.168.2.211): 56 data bytes64 bytes from 192.168.2.211: seq=0 ttl=64 time=0.494 ms64 bytes from 192.168.2.211: seq=1 ttl=64 time=0.495 ms

--- 192.168.2.211 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.494/0.494/0.495 ms

使用Macvlan+VLAN構建Docker網絡 

VLAN簡介

VLAN(Virtual Local Area Network)又稱虛擬局域網,是指在局域網的基礎上,採用網絡管理軟件構建的可跨越不同網段、不同網絡的端到端的邏輯網絡。

一個VLAN組成一個邏輯子網,即一個邏輯廣播域,它可以覆蓋多個網絡設備,允許處於不同地理位置的網絡用戶加入到一個邏輯子網中。使用VLAN功能後,能夠將網絡分割成多個廣播域。

Linux支持在物理網卡上創建vlan子接口。每個vlan子接口屬於不同的二層域,所有的vlan子接口擁有相同的MAC地址。這點是和Macvlan子接口不同的地方。

  • master主機

創建VLAN

# 爲物理網卡enp0s5創建Macvlan子接口
$ ip link add link enp0s5 name enp0s5.200 type vlan id 200# 將MACVLAN設備加入到容器的network space
$ ip link list enp0s5.20033: ip enp0s5.200@enp0s5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
   link/ether 00:1c:42:97:53:2a brd ff:ff:ff:ff:ff:ff

# 啓用enp0s5.200$ ip link set enp0s5.200 up$ ip link list enp0s5.20033: enp0s5.200@enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
   link/ether 00:1c:42:97:53:2a brd ff:ff:ff:ff:ff:ff

# 設置enp0s5.200爲混雜模式
$ ip link set enp0s5.200  promisc on$ ifconfig enp0s5.200enp0s5.200 Link encap:Ethernet  HWaddr 00:1c:42:97:53:2a
         inet6 addr: fe80::21c:42ff:fe97:532a/64 Scope:Link
         UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
         RX packets:0 errors:0 dropped:0 overruns:0 frame:0
         TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:1000
         RX bytes:0 (0.0 B)  TX bytes:648 (648.0 B)

設置macvlan的ip和網關

$ ip addr add 192.168.200.10/24 dev enp0s5.200# 刪除原默認路由,否則下面加默認路由時會報錯。$ ip route del default
$ ip route add default via 192.168.200.1 dev enp0s5.200

創建Docker macvlan網絡

$ docker network create -d macvlan --subnet=192.168.200.0/24 --gateway=192.168.200.1 -o parent=enp0s5.200 -o macvlan_mode=bridge macvlan200b2fb555bbcdc1f0b724cc9e76b154630e632184566b9e8bb314cde825ad9ff9d


# 查看macvlan是否創建成功

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE6dc2160d4026        bridge              bridge              locala56cfbac20ed        docker_gwbridge     bridge              local0b703c3d9cb8        host                host                local9282605b5107        macnet              macvlan             locald129db56fcc1        macvlan200          macvlan             localabdb4b9f751c        none                null                local856b6dbf7e83        weave               weavemesh           local

創建兩個使用macvlan容器

創建容器c5

$ docker run --net=macvlan200 --ip=192.168.200.100 -id --name c5 busybox sh28ee719d4784696eff10805f1f9d992b245b7b886b031c1781dbaf4037bbb231

創建容器c6

$ docker run --net=macvlan200 --ip=192.168.200.101 -id --name c6 busybox sh7bd2a36e24846b383ab3aca6b9b48227600aed7352956c2c974db1ceb97efb54
  • node主機

創建Vlan

# 爲物理網卡enp0s5創建Macvlan子接口
$ ip link add link enp0s5 name enp0s5.200 type vlan id 200# 將MACVLAN設備加入到容器的network space
$ ip link list enp0s5.20024: enp0s5.200@enp0s5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
   link/ether 00:1c:42:67:23:07 brd ff:ff:ff:ff:ff:ff

# 啓用enp0s5.200$ ip link set enp0s5.200 up$ ip link list enp0s5.20024: enp0s5.200@enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
   link/ether 00:1c:42:67:23:07 brd ff:ff:ff:ff:ff:ff

# 設置enp0s5.200爲混雜模式
$ ip link set enp0s5.200  promisc on$ ifconfig enp0s5.200enp0s5.200 Link encap:Ethernet  HWaddr 00:1c:42:67:23:07
         inet6 addr: fe80::21c:42ff:fe67:2307/64 Scope:Link
         UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
         RX packets:0 errors:0 dropped:0 overruns:0 frame:0
         TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:1000
         RX bytes:0 (0.0 B)  TX bytes:648 (648.0 B)

設置macvlan的ip和網關

$ ip addr add 192.168.200.11/24 dev enp0s5.200# 刪除原默認路由,否則下面加默認路由時會報錯。$ ip route del default
$ ip route add default via 192.168.200.1 dev enp0s5.200

創建Docker macvlan網絡

$ docker network create -d macvlan --subnet=192.168.200.0/24 --gateway=192.168.200.1 -o parent=enp0s5.200 -o macvlan_mode=bridge macvlan200b2fb555bbcdc1f0b724cc9e76b154630e632184566b9e8bb314cde825ad9ff9d


# 查看macvlan是否創建成功
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE4886f72179a8        bridge              bridge              local0b703c3d9cb8        host                host                local149f5dcc20b3        macnet              macvlan             local8ee3174430ab        macvlan200          macvlan             localabdb4b9f751c        none                null                localbce1daa0a925        weave               weavemesh           local

創建兩個使用macvlan容器

創建容器c7

$ docker run --net=macvlan200 --ip=192.168.200.102 -id --name c7 busybox sh28ee719d4784696eff10805f1f9d992b245b7b886b031c1781dbaf4037bbb231

創建容器c8

$ docker run --net=macvlan200 --ip=192.168.200.103 -id --name c8 busybox sh7bd2a36e24846b383ab3aca6b9b48227600aed7352956c2c974db1ceb97efb54

測試網絡連通情況

所有測試在master主機上進行。

  • ping網關

$ docker exec c5 ping -c2 192.168.200.1

測試結果:不通

  • ping本地macvlannet地址

$ docker exec c5 ping -c2 192.168.200.10PING 192.168.200.10 (192.168.200.10): 56 data bytes--- 192.168.200.10 ping statistics ---2 packets transmitted, 0 packets received, 100% packet loss

測試結果:不通

  • ping另一個主機的macvlannet地址

$ docker exec c5 ping -c2 192.168.200.11PING 192.168.200.11 (192.168.200.11): 56 data bytes64 bytes from 192.168.200.11: seq=0 ttl=64 time=0.535 ms64 bytes from 192.168.200.11: seq=1 ttl=64 time=0.368 ms

--- 192.168.200.11 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.368/0.451/0.535 ms

測試結果:通

  • ping本主機容器

$ docker exec c5 ping -c2 192.168.200.100PING 192.168.200.100 (192.168.200.100): 56 data bytes64 bytes from 192.168.200.100: seq=0 ttl=64 time=0.091 ms64 bytes from 192.168.200.100: seq=1 ttl=64 time=0.046 ms

--- 192.168.200.100 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.046/0.068/0.091 ms

測試結果:通

  • ping另一主機容器

$ docker exec c5 ping -c2 192.168.200.102PING 192.168.200.102 (192.168.200.102): 56 data bytes64 bytes from 192.168.200.102: seq=0 ttl=64 time=0.815 ms64 bytes from 192.168.200.102: seq=1 ttl=64 time=1.051 ms

--- 192.168.200.102 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.815/0.933/1.051 ms

測試結果:通

  • 使用容器名ping本主機容器

$ docker exec c5 ping -c2 c6
PING c6 (192.168.200.101): 56 data bytes64 bytes from 192.168.200.101: seq=0 ttl=64 time=0.152 ms64 bytes from 192.168.200.101: seq=1 ttl=64 time=0.108 ms

--- c6 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.108/0.130/0.152 ms

測試結果:通

  • 使用容器名ping另一主機容器

$ docker exec c5 ping -c2 c7
ping: bad address 'c7'

測試結果:不通

  • ping跨網絡主機

$ docker exec c5 ping -c2 192.168.200.102PING 192.168.200.102 (192.168.200.102): 56 data bytes64 bytes from 192.168.200.102: seq=0 ttl=64 time=0.518 ms64 bytes from 192.168.200.102: seq=1 ttl=64 time=0.458 ms

--- 192.168.200.102 ping statistics ---2 packets transmitted, 2 packets received, 0% packet lo***ound-trip min/avg/max = 0.458/0.488/0.518 ms

測試結果:通

  • 本主機ping本主機容器

$ ping 192.168.200.100 -c2PING 192.168.200.100 (192.168.200.100) 56(84) bytes of data.From 192.168.200.10 icmp_seq=1 Destination Host UnreachableFrom 192.168.200.10 icmp_seq=2 Destination Host Unreachable--- 192.168.200.100 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1006mspipe 2

測試結果:不通

  • 本主機ping另一主機容器

$ ping 192.168.200.102 -c2
PING 192.168.200.102 (192.168.200.102) 56(84) bytes of data.64 bytes from 192.168.200.102: icmp_seq=1 ttl=64 time=0.625 ms64 bytes from 192.168.200.102: icmp_seq=2 ttl=64 time=0.319 ms

--- 192.168.200.102 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.319/0.472/0.625/0.153 ms

測試結果:通

一些問題 

  • macvlan網絡在創建時要指定parent.其中parent僅能使用一次,即eth0在創建一個macvlan網絡時使用了,則在創建另一個的時候就無法再使用了。

  • 兩種模式下都有測試網絡不通的情況,不知道是不是虛擬機網絡環境問題。理論上應該是通的。待在真實環境驗證後才得知。


   3.2 overlay network

見:http://www.tuicool.com/articles/eURfqu      


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章