Pipework配置Docker容器macvlan网络

      访问: 6,093 次      2 条评论    

一、macvlan 介绍(some-notes-on-macvlanmacvtap

一般来说,我们在自定义Docker与外部网络通信的网络,除了NAT,还有Linux Bridge、Open vSwitch、MacVLAN几种选择。MacVLAN相对于前两者,拥有更好的性能。

macvlan可以看做是物理网卡的子接口,每个macvlan子接口有其自己的MAC地址(跟物理网卡的也不同),而且可以为每个macvlan子接口设置IP地址。

即在同一个物理网卡上设置多个不同的IP+MAC地址的子接口,我们称macvlan子接口所依附的物理网卡为lower device。

MacVLAN有4种模式,参考这里。 VEPA需要接入交换机支持hairpin mode。相对而言,Bridge mode更加常用。

 

macvlan可以工作在四种模式下:


  • VEPA(Virtual Ethernet Port Aggregator)mode:default 模式,If the lower device receives data from a macvlan in VEPA mode, this data is always sent "out" to the upstream switch or bridge, even if it's destined for another macvlan in the same lower device.


  • Brideg mode:this works almost like a traditional bridge, in that data received on a macvlan in bridge mode and destined for another macvlan of the same lower device is sent directly to the target (if the target macvlan is also in bridge mode), rather than being sent outside.

  • Private mode:this is essentially like VEPA mode, but with the added feature that no macvlans on the same lower device can communicate, regardless of where the packets come from (so even if inter-VM traffic is sent back by a hairpin switch or an IP router, the target macvlan is prevented from receiving it).

  • Passthru mode:this mode was added later, to work around some limitation of macvlans (more details  here ).


MACVLAN工作方式补充:

有时我们可能需要一块物理网卡绑定多个 IP 以及多个 MAC 地址,虽然绑定多个 IP 很容易,但是这些 IP 会共享物理网卡的 MAC 地址,可能无法满足我们的设计需求,所以有了 MACVLAN 设备,其工作方式如下:

MACVLAN 会根据收到包的目的 MAC 地址判断这个包需要交给哪个虚拟网卡。单独使用 MACVLAN 好像毫无意义,但是配合容器的 network namespace 使用,我们可以构建这样的网络:

由于 macvlan 与 eth0 处于不同的 namespace,拥有不同的 network stack,这样使用可以不需要建立 bridge 在 virtual namespace 里面使用网络。

二、Docker容器实践macvlan网络配置

测试环境介绍:

  • 宿主机:192.168.1.11/24,网关192.168.1.1,网卡名称为enp2s0

  • 容器1:192.168.1.101/24,网关192.168.1.1

  • 容器2:192.168.1.102/24,网关192.168.1.1

  • 效果:容器接入宿主所在的本地网络,容器间可以通信,并可以和本地网络的其他主机和macvlan容器通信(但默认情况下宿主和容器不能通信)

 

Pipework是由Docker的工程师Jérôme Petazzoni开发的一个Docker网络配置工具,由200多行shell实现,方便易用。

下面我们就使用pipework来演示为容器配置macvlan设备的网卡。


1、安装Pipework(方便我们配置容器网络)
# wget https://github.com/jpetazzo/pipework/archive/master.zip
# unzip master.zip 
# cp pipework-master/pipework /usr/local/bin/ -a
2、使用Pipework 配置容器的IP
# docker run -it --name=busy_netnone --net=none busybox
# pipework enp2s0  busy_netnone 192.168.1.102/24@192.168.1.1

 

3、Pipework 工作原理分析

那么容器到底发生了哪些变化呢?我们docker attach到容器busy_netnone上,发现容器中多了一块eth1的网卡,并且配置了192.168.1.102/24的IP,而且默认路由也改为了192.168.1.1。这些都是pipework帮我们配置的。通过查看源代码,可以发现命令 pipework enp2s0  busy_netnone 192.168.1.102/24@192.168.1.1 是由以下命令完成的(这里只列出了具体执行操作的代码)。

#第一个参数以 br开头,则创建linux网桥:brctl addbr $IFNAME
#第一个参数若ovs开头,则创建Open vSwitch网桥:ovs-vsctl add-br ovs*
#第一个参数是主机上的一块网卡,则创建macvlan设备
# If it's a physical interface, create a macvlan subinterface
ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge
ip link set "$IFNAME" up
 
#找到Docker容器busy_netnone在主机上的PID,创建容器网络命名空间的软连接到/var/run/netns/目录下
#这么做的目的是,方便在主机上使用ip netns命令配置容器的网络
#因为,在Docker容器中,我们没有权限配置网络环境
DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' $GUESTNAME)
ln -s /proc/$NSPID/ns/net /var/run/netns/$NSPID
 
#将macvlan设备放入Docker容器中,并设置正确的名字(默认是eth1)
ip link set "$GUEST_IFNAME" netns "$NSPID"
ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME"
 
 
#为新增加的容器配置IP和路由
ip netns exec $NSPID ip addr add $IPADDR dev $CONTAINER_IFNAME
ip netns exec $NSPID ip link set $CONTAINER_IFNAME up
ip netns exec $NSPID ip route delete default
ip netns exec $NSPID ip route add $GATEWAY/32 dev $CONTAINER_IFNAME

 

命令 pipework enp2s0 busy_netnone 192.168.1.102/24@192.168.1.1  ,这里pipework的第一个参数是主机上的一块以太网卡,而非网桥。pipework不会再创建veth pair设备来连接容器和网桥,转而采用macvlan设备作为busy_netnone容器的网卡,操作过程如下:

  1. 从主机的enp2s0上创建一块macvlan设备,将macvlan设备放入到busy_netnone容器中并命名为eth1(可以 -i 参数指定名字);

  2. 为busy_netnone容器中新添加的网卡配置IP地址为192.168.1.102/24;

  3. 若busy_netnone容器中已经有默认路由,则删掉,把192.168.1.1设为默认网关。

 

注:从enp2s0上创建出的macvlan设备放入busy_netnone容器后, busy_netnone容器可以和本地网络中的其他主机通信了。但是,如果在busy_netnone所在的宿主机上却不能访问busy_netnone,因为进出macvlan设备的流量被主网卡enp2s0隔离了,宿主机不能通过enp2s0访问macvlan设备。要解决这个问题,需要在enp2s0上再创建一个macvlan设备,并设置一个IP(或将宿主网卡enp2s0的IP地址移到)到这个macvlan设备上。示例如下:


示例:让宿主机访问macvlan模式的容器

# 设置一个跟宿主机网卡enp2s0同网段的IP,配置到新创建的macvlan设备上:
# ip link add enp2s0macvlan0 link enp2s0 type macvlan mode bridge
# ip addr add 192.168.1.12/24 dev eth0macvlan0
# ip link set eth0macvlan0 up


现在,在宿主机上就可以ping通使用macvlan设备的容器的IP了。查看宿主机路由表:

经由 macvlan 设备的路由的metric更低,所以这条路由优先于原物理网卡路由。

 

参考链接:

网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP

Docker网络详解及pipework源码解读与实践

已有 2 条评论

  1. nilin nilin

    最后一句话,怎么操作啊,使得容器和宿主机互通

    1. 我补充在后面了,你参考下。

添加新评论