Docker系列(十二):Docker 跨主機容器間網絡通信(一)

在之前的文章中已經介紹過單主機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.41docker01.contoso.com
1.13.1CentOS 7(3.10.0-693.el7.x86_64) 
節點2192.168.49.42docker02.contoso.com1.13.1CentOS 7(3.10.0-693.el7.x86_64)


橋接模式:

對橋接模式而言,宿主機位於同一個局域網,將每一個宿主機上的容器網絡橋接到宿主機網絡中,容器和宿主機同在一個局域網中,因而可以互相通信。

1)在宿主機上創建網橋(如不特別指明,以下命令均需在兩臺主機上執行)

yum -y install bridge-utils
brctl addbr br0
brctl addif br0 eth0

2)給網橋配置IP地址

docker01:
        ifconfig eth0 0.0.0.0
        ifconfig br0 192.168.49.41 up
docker02:
        ifconfig eth0 0.0.0.0
        ifconfig br0 192.168.49.42 up

3)查看網橋信息

[root@docker01 ~]# brctl show br0
bridge namebridge idSTP enabledinterfaces
br08000.000c2952f550noeth0
[root@docker02 ~]# brctl show br0
bridge namebridge idSTP enabledinterfaces
br08000.000c29efedb3noeth0

4)配置Docker啓動選項

[root@docker01 ~]# cat /etc/sysconfig/docker-network 
# /etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS="-b=br0 --fixed-cidr=192.168.49.64/27"    
# 這裏我使用--fixed-cidr指定了容器的IP地址範圍,因爲我是用VMware虛擬機的NAT網絡模式,如果不指定容器會從192.168.49.1的地址開始獲取,\
# 而這個地址是我VMware宿主機的網卡地址,會導致SSH無法連接到Docker主機,所以這裏指定一下容器的IP地址範圍。
[root@docker02 ~]# cat /etc/sysconfig/docker-network 
# /etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS="-b=br0 --fixed-cidr=192.168.49.96/27"
# 這裏爲了兩臺Docker主機上的容器不會獲取相同的IP地址,所以在兩臺Docker主機上配置不同的CIDR地址段,這樣就不會產生IP地址衝突。

5)重啓docker服務

systemctl restart docker

6)創建容器並驗證

在Docker01上執行:

[root@docker01 ~]# docker run -itd --name node01 centos:latest /bin/bash
d0e17f02f815d639aab538f4541ff93650db056eda75b35c026ccf5bfa35bc3d
[root@docker01 ~]# docker exec -it node01 /bin/bash
[root@d0e17f02f815 /]# ifconfig eth0 |grep -A1 eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.49.64  netmask 255.255.255.0  broadcast 0.0.0.0

在Docker02上執行:

[root@docker02 ~]# docker run -itd --name node02 centos:latest /bin/bash
15376d306ef5c302ebe98439dba40d75230ad0ebe8037941b39823b01c19d561
[root@docker02 ~]# docker exec -it node02 /bin/bash
[root@15376d306ef5 /]# ifconfig eth0 |grep -A1 eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.49.96  netmask 255.255.255.0  broadcast 0.0.0.0

在Docker01上上驗證:

[root@d0e17f02f815 /]# ping 192.168.49.96 -c 2
PING 192.168.49.96 (192.168.49.96) 56(84) bytes of data.
64 bytes from 192.168.49.96: icmp_seq=1 ttl=64 time=0.664 ms
64 bytes from 192.168.49.96: icmp_seq=2 ttl=64 time=0.377 ms
--- 192.168.49.96 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.377/0.520/0.664/0.145 ms
[root@d0e17f02f815 /]# ping 192.168.49.41 -c 2
PING 192.168.49.41 (192.168.49.41) 56(84) bytes of data.
64 bytes from 192.168.49.41: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 192.168.49.41: icmp_seq=2 ttl=64 time=0.037 ms
--- 192.168.49.41 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.029/0.033/0.037/0.004 ms

在Docker02上上驗證:

[root@15376d306ef5 /]# ping 192.168.49.64 -c 2
PING 192.168.49.64 (192.168.49.64) 56(84) bytes of data.
64 bytes from 192.168.49.64: icmp_seq=1 ttl=64 time=0.347 ms
64 bytes from 192.168.49.64: icmp_seq=2 ttl=64 time=0.400 ms
--- 192.168.49.64 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.347/0.373/0.400/0.032 ms
[root@15376d306ef5 /]# ping 192.168.49.42 -c 2
PING 192.168.49.42 (192.168.49.42) 56(84) bytes of data.
64 bytes from 192.168.49.42: icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from 192.168.49.42: icmp_seq=2 ttl=64 time=0.039 ms
--- 192.168.49.42 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.039/0.045/0.052/0.009 ms

結論:橋接模式是跨主機容器網絡互聯較簡答的一種方式,直接將容器網絡橋接到局域網中,這樣容器和宿主機就在同一網段,方便進行容器操作。但因爲每臺主機上的容器都直接從局域網中獲取IP地址,卻沒有統一對不同主機上容器獲取的IP地址進行登記,很容易導致IP地址衝突,雖然可以通過使用--fixed-cidr來指定,但是這樣隔離網段也不太方便,網絡劃分需注意。


端口映射:

端口映射,顧名思義就是將容器的服務所運行的端口映射到宿主機的某一個端口,然後其他的容器通過宿主機的對應端口進行訪問。

1)創建帶端口映射的容器

因爲使用端口映射的方式,所以不需要單獨創建容器網絡,我們使用默認的docker0網絡即可。

[root@docker01 ~]# docker run -itd --name nat01 -p 4180:80 mynginx:v1 
edc990164c797213a866bdd09a5f914360cbd6308fe3142325ea7013a0ea0a69
[root@docker02 ~]# docker run -itd --name nat02 -p 4280:80 mynginx:v1
bea87fe30cd4e56e7048305e0b0cef4a0886c9e24e33fe34a37244a509ab6325

2)在宿主機的防火牆中查看端口映射

[root@docker01 ~]# iptables -t nat -nL |grep 4180
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:4180 to:172.17.0.2:80
[root@docker02 ~]# iptables -t nat -nL |grep 4280
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:4280 to:172.17.0.2:80

3)測試容器間通信

在nat01上執行:

[root@docker01 ~]# docker exec -it nat01 /bin/bash
[root@edc990164c79 nginx]# curl -I http://192.168.49.42:4280
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 21 Apr 2019 08:27:30 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 03 Mar 2019 06:18:30 GMT
Connection: close
ETag: "5c7b71b6-264"
Accept-Ranges: bytes

在nat02上執行:

[root@docker02 ~]# docker exec -it nat02 /bin/bash
[root@bea87fe30cd4 nginx]# curl -I http://192.168.49.41:4180
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sun, 21 Apr 2019 08:28:43 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 03 Mar 2019 06:18:30 GMT
Connection: close
ETag: "5c7b71b6-264"
Accept-Ranges: bytes

結論:使用端口映射的方式,只是將容器的端口通過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

wget https://releases.hashicorp.com/consul/1.4.4/consul_1.4.4_linux_amd64.zip 
unzip consul_1.4.4_linux_amd64.zip 
mv consul /usr/bin/
chmod +x /usr/bin/consul

2)在節點1上啓動consul服務

nohup consul agent -server -bootstrap -ui -data-dir /var/lib/consul -client=192.168.49.41 -bind=192.168.49.41 &>/var/log/consul.log &

3)修改節點1上的docker守護進程

[root@docker01 ~]# vi /etc/sysconfig/docker
[root@docker01 ~]# tail -1 /etc/sysconfig/docker
OPTIONS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.49.41:8500 --cluster-advertise 192.168.49.41:2375"
# 這裏是CentOS 7上的修改方法,並不適用於Ubuntu
[root@docker01 ~]# systemctl daemon-reload
[root@docker01 ~]# systemctl restart docker
[root@docker01 ~]# ps -ef|grep docker
root       4201      1  0 22:38 ?        00:00:00 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.49.41:8500 --cluster-advertise 192.168.49.41:2375 --storage-driver overlay2
root       4206   4201  0 22:38 ?        00:00:00 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true

4)同樣的方法修改節點2的docker守護進程

[root@docker02 ~]# vi /etc/sysconfig/docker
[root@docker02 ~]# tail -1 /etc/sysconfig/docker
OPTIONS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.49.41:8500 --cluster-advertise 192.168.49.42:2375"
[root@docker02 ~]# systemctl daemon-reload
[root@docker02 ~]# systemctl restart docker
[root@docker02 ~]# ps -ef|grep docker
root       2442      1  0 22:39 ?        00:00:01 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.49.41:8500 --cluster-advertise 192.168.49.42:2375 --storage-driver overlay2
root       2447   2442  0 22:39 ?        00:00:00 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true

5)到consul的UI界面查看節點是否添加

        001.png

6)在docker主機上創建overlay網絡

[root@docker01 ~]# docker network create -d overlay overlay_net
edf675e1a8b58a0b8fee9888ebd380690d022b1b4c02bf8da710f5fad96ce9be
# 只需在其中一臺docker主機上創建overlay網絡即可,它會自動同步到另外一個節點上。如果嘗試到另外一個節點創建overlay網絡,就會出現如下錯誤:
[root@docker02 ~]# docker network create -d overlay overlay_net
Error response from daemon: network with name overlay_net already exists

7)分別在兩個節點上創建容器

[root@docker01 ~]# docker run -it --net=overlay_net --name busybox01 busybox:latest 
[root@docker02 ~]# docker run -it --net=overlay_net --name busybox02 busybox:latest

檢測容器是否可以互相通信:

        002.png

        

       003.png

工作原理:

在講解原理之前,先看看容器上的網絡信息,這會給我們容器間通信的一些提示。

節點1上的容器網絡:

004.png

節點2上的容器網絡:

005.png

我們看到每個容器都有2張網卡,而這個172.20.0.0/24的網段是哪裏來的呢?再來看看docker主機的網絡信息:

在節點1上:

[root@docker01 ~]# ifconfig 
......
docker_gwbridge: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:f1ff:fe59:46c  prefixlen 64  scopeid 0x20<link>
        ether 02:42:f1:59:04:6c  txqueuelen 0  (Ethernet)
        RX packets 12  bytes 894 (894.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12  bytes 1024 (1024.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
......

在節點2上:

[root@docker02 ~]# ifconfig
......
docker_gwbridge: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:d0ff:fe7e:b42  prefixlen 64  scopeid 0x20<link>
        ether 02:42:d0:7e:0b:42  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
......

或許我們查看網橋信息會更直接一些:

[root@docker01 ~]# brctl show docker_gwbridge
bridge name     bridge id        STP enabled   interfaces
docker_gwbridge  8000.0242f159046c no             vethf22303e
[root@docker02 ~]# brctl show docker_gwbridge
bridge name     bridge id        STP enabled   interfaces
docker_gwbridge  8000.0242d07e0b42 no             vetheb307a8

我們再查看namespace:

由於容器和overlay的網絡的網絡命名空間文件不在操作系統默認的/var/run/netns下,只能手動通過軟連接的方式查看。

ln -s/var/run/docker/netns /var/run/netns

可以看見兩個節點主機上都有這個“1-”開頭的的namespace

[root@docker01 ~]# ip netns
90ead4cedbe0 (id: 1)
1-edf675e1a8 (id: 0)
[root@docker02 ~]# ip netns
eba2816aa5c4 (id: 1)
1-edf675e1a8 (id: 0)

查看這個namespace中的網卡信息(以其中一臺爲例):

[root@docker01 ~]# ip netns exec 1-edf675e1a8 ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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 forever
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP 
    link/ether 76:eb:2a:ac:a8:2c brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::f80b:63ff:feb9:5229/64 scope link 
       valid_lft forever preferred_lft forever
8: vxlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN 
    link/ether 8e:92:3d:8f:48:28 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::8c92:3dff:fe8f:4828/64 scope link 
       valid_lft forever preferred_lft forever
10: veth2@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UP 
    link/ether 76:eb:2a:ac:a8:2c brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::74eb:2aff:feac:a82c/64 scope link 
       valid_lft forever preferred_lft forever

我們看到namespace中有一個網橋br0,再查看這個網橋的信息:

[root@docker01 ~]# ip netns exec 1-edf675e1a8 brctl show
bridge namebridge id                STP enabledinterfaces
br0        8000.76eb2aaca82cno        veth2
                                vxlan1

查看VNI(Vxlan Network identifier):

[root@docker01 ~]# ip netns exec 1-edf675e1a8 ip -d link show vxlan1
8: vxlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN mode DEFAULT 
    link/ether 8e:92:3d:8f:48:28 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 1 
    vxlan id 256 srcport 0 0 dstport 4789 proxy l2miss l3miss ageing 300 
    bridge_slave state forwarding priority 32 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.76:eb:2a:ac:a8:2c designated_root 8000.76:eb:2a:ac:a8:2c hold_timer    0.00 message_age_timer    0.00 forward_delay_timer    0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on addrgenmode eui64

查看vlan設備上的靜態mac地址表:

[root@docker01 ~]# ip netns exec 1-edf675e1a8 bridge fdb show vxlan1
33:33:00:00:00:01 dev br0 self permanent
01:00:5e:00:00:01 dev br0 self permanent
33:33:ff:b9:52:29 dev br0 self permanent
8e:92:3d:8f:48:28 dev vxlan1 master br0 permanent
8e:92:3d:8f:48:28 dev vxlan1 vlan 1 master br0 permanent
02:42:0a:00:00:03 dev vxlan1 dst 192.168.49.42 link-netnsid 0 self permanent
76:eb:2a:ac:a8:2c dev veth2 master br0 permanent
76:eb:2a:ac:a8:2c dev veth2 vlan 1 master br0 permanent
33:33:00:00:00:01 dev veth2 self permanent
01:00:5e:00:00:01 dev veth2 self permanent
33:33:ff:ac:a8:2c dev veth2 self permanent

綜上,overlay網絡的拓補如下:

006.png

這裏數據包的發送流程如下(以從左側的容器發送到右側的容器爲例):

  1. 容器Container1會通過Container eth0 將這個數據包發送到 10.0.0.1 的網關。

  2. 網關將數據包發送出去後到達br0網橋。

  3. br0網橋針對VXLAN設備,主要用於捕獲對外的數據包通過VETP進行數據包封裝。

  4. 封裝好將VXLAN格式數據包交給eth0,通過UDP方式交給Container2的eth0。

  5. Container2收到數據包後通過VETP將數據包解封裝。

  6. 網橋通過網關將解封裝的數據包轉發給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:

[root@docker01 ~]# docker network create -d macvlan --subnet=172.24.100.0/24 --gateway=172.24.100.1 -o parent=eth0 macvlan_net 
3482af4cb39408840e6ee46225acf2754cfa4632d8ace28c34e7912fe4208946
[root@docker01 ~]# docker network ls |grep macvlan
3482af4cb394        macvlan_net             macvlan             local

節點2:

[root@docker02 ~]# docker network create -d macvlan --subnet=172.24.100.0/24 --gateway=172.24.100.1 -o parent=eth0 macvlan_net
94b4f197fd20f96a3cf3d7e363e16760a43e42a3d806eed9e1814ba649470d9f
[root@docker02 ~]# docker network ls |grep macvlan
94b4f197fd20        macvlan_net             macvlan             local

2)創建容器並指定IP地址

節點1:

[root@docker01 ~]# docker run -it --net macvlan_net --ip=172.24.100.41 --name busybox01 busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:18:64:29  
          inet addr:172.24.100.41  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:acff:fe18:6429/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:508 (508.0 B)

節點2:

[root@docker02 ~]# docker run -it --net macvlan_net --ip=172.24.100.42 --name busybox02 busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:18:64:2A  
          inet addr:172.24.100.42  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:acff:fe18:642a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:508 (508.0 B)

3)測試容器通信

節點1:

[root@docker01 ~]# docker exec -it busybox01 ping 172.24.100.42
PING 172.24.100.42 (172.24.100.42): 56 data bytes
64 bytes from 172.24.100.42: seq=0 ttl=64 time=0.327 ms
64 bytes from 172.24.100.42: seq=1 ttl=64 time=0.550 ms
64 bytes from 172.24.100.42: seq=2 ttl=64 time=3.868 ms
^C
--- 172.24.100.42 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.327/1.581/3.868 ms

節點2:

[root@docker02 ~]# docker exec -it busybox02 ping 172.24.100.41
PING 172.24.100.41 (172.24.100.41): 56 data bytes
64 bytes from 172.24.100.41: seq=0 ttl=64 time=0.483 ms
64 bytes from 172.24.100.41: seq=1 ttl=64 time=0.375 ms
64 bytes from 172.24.100.41: seq=2 ttl=64 time=0.436 ms
^C
--- 172.24.100.41 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.375/0.431/0.483 ms

Macvlan VLAN Bridge模式:

因爲之前的操作都是在VMware Workstation虛擬機中進行,自己嘗試在VMware中的Centos7中做macvlan網卡子接口vlan網絡容器互通的測試,但是無一例外全部都無法通信,即使是開啓了網卡的混雜模式,也都不行。網上給出的方案是使用VirtualBox,但是個人使用VirtualBox+CentOS7仍然無法通信,所以改用VirtualBox+Ubuntu 16.04,測試成功,所以下面改用Ubuntu 16.04進行演示。

環境準備:


IP地址主機名Docker版本系統(內核版本)
節點1
172.16.3.11docker01
17.05.0-ceUbuntu 16.04.3 LTS(4.4.0-87-generic) 
節點2172.16.3.22docker0217.05.0-ceUbuntu 16.04.3 LTS(4.4.0-87-generic) 

1)創建vlan

在兩個節點上操作:

ip link add link enp0s3 name enp0s3.10 type vlan id 10
ip link add link enp0s3 name enp0s3.20 type vlan id 20

2)創建macvlan網絡

在兩個節點上操作:

docker network create -d macvlan --subnet=192.168.10.0/24 --gateway=192.168.10.1 -o parent=enp0s3.10 macvlan_net10
docker network create -d macvlan --subnet=192.168.20.0/24 --gateway=192.168.20.1 -o parent=enp0s3.20 macvlan_net20
# 創建完畢後,執行ifconfig看能否看到enp0s3.10和enp0s3.20這兩個虛擬網卡,如果沒有則需要重啓一下節點

3)使用macvlan創建容器

在節點1上:

docker run -itd --net=macvlan_net10 --ip=192.168.10.11 --name bbox01 busybox:latest
docker run -itd --net=macvlan_net20 --ip=192.168.20.11 --name bbox02 busybox:latest

在節點2上:

docker run -itd --net=macvlan_net10 --ip=192.168.10.22 --name bbox03 busybox:latest
docker run -itd --net=macvlan_net20 --ip=192.168.20.22 --name bbox04 busybox:latest

4)測試網絡是否能通信

在節點1上:

root@docker01:~# docker exec -it bbox01 ping 192.168.10.22 -c2 -w2
PING 192.168.10.22 (192.168.10.22): 56 data bytes
64 bytes from 192.168.10.22: seq=0 ttl=64 time=0.444 ms
64 bytes from 192.168.10.22: seq=1 ttl=64 time=0.544 ms
--- 192.168.10.22 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.444/0.494/0.544 ms
root@docker01:~# docker exec -it bbox02 ping 192.168.20.22 -c2 -w2
PING 192.168.20.22 (192.168.20.22): 56 data bytes
64 bytes from 192.168.20.22: seq=0 ttl=64 time=0.417 ms
64 bytes from 192.168.20.22: seq=1 ttl=64 time=0.381 ms
--- 192.168.20.22 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.381/0.399/0.417 ms

在節點2上:

root@docker02:~# docker exec -it bbox03 ping 192.168.10.11 -c2 -w2
PING 192.168.10.11 (192.168.10.11): 56 data bytes
64 bytes from 192.168.10.11: seq=0 ttl=64 time=0.335 ms
64 bytes from 192.168.10.11: seq=1 ttl=64 time=0.263 ms
--- 192.168.10.11 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.263/0.299/0.335 ms
root@docker02:~# docker exec -it bbox04 ping 192.168.20.11 -c2 -w2
PING 192.168.20.11 (192.168.20.11): 56 data bytes
64 bytes from 192.168.20.11: seq=0 ttl=64 time=0.280 ms
64 bytes from 192.168.20.11: seq=1 ttl=64 time=0.336 ms
--- 192.168.20.11 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.280/0.308/0.336 ms

這裏,同一個vlan的兩個節點上的容器可以通信,不同vlan的容器(無論是同一個節點還是不同節點)均不能通信,當然可以通過添加路由的方式讓不同vlan的容器通信,但是vlan劃分的目的就是隔絕網絡,所以這裏不再演示讓不同vlan容器通信的方法,網上類似的教程也很多,大家自行查找即可。

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