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      


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