Docker容器跨主机访问之macvlan网络
Docker跨主机访问
macvlan
创建macvlan网络
打开网卡的混杂模式,并查看网卡状态up且promisc模式已经生效
在两个主机上创建macvlan网络macvlan_net1
在另一台主机上执行相同的命令
-d macvlan指定driver为macvlan
macvlan网络是local网络,为了保证跨主机能够通信,用户需要自己管理IP subnet
与其他网络不同,docker不会为macvlan创建网关,这里的网关应该是真实存在的,否则容器无法路由
-o parent指定使用的网络接口
在第一台主机上运行容器test1并连接到macvlan_net1
由于两台主机中的macvlan_net1本质上是独立的,为了避免自动分配造成IP冲突,最好通过--ip指定test的地址
在第二台主机上运行容器test2,指定IP为172.16.86.11
验证test1与test2的通信,由结果可以得出macvlan实现了跨主机访问的功能
test2可以ping到test1的IP 172.16.86.10,但无法解析test1主机名,可见docker没有为macvlan提供DNS服务
macvlan的网络结构
查看容器test1的网络设备
除了lo,容器只有一个eth0,eth0 后面的@if2表明该interface有一个对应的interface,其全局的编号为2。根据macvlan的原理,我们有理由猜测这个interface 就是主机的enp0s5,确认如下
可见,容器的eth0就是enp0s5通过macvlan虚拟出来的interface。容器的interface直接与主机的网卡连接,这种方案使得容器无需通过NAT和端口映射就能与外网直接通信(只要有网关),在网络上与其他独立主机没有区别
用sub-interface 实现多macvlan 网络
macvlan会独占主机的网卡,也就是说一个网卡只能创建一个macvlan网络,否则会报错
但主机的网卡数量是有限的,如何支持更多的macvlan网络呢?Linux 的网卡也能支持VLAN(apt-get install vlan),同一个interface可以收发多个VLAN的数据包,不过前提是要创建VLAN的sub-interface。比如希望enp0s5同时支持VLAN10和VLAN20,则需创建sub-interface enp0s5.10和enp0s5.20。
下面演示如何在enp0s5.10和enp0s5.20上创建macvlan 网络。
(1)首先编辑两台主机的/etc/network/interfaces,配置sub-
auto enp0s5 iface enp0s5 inet manual auto enp0s5.10 iface enp0s5.10 inet manual vlan-raw-device enp0s5 auto enp0s5.20 iface enp0s5.20 inet manual vlan-raw-device enp0s5
(2)然后启用sub-interface
sudo ifup enp0s5.10 sudo ifup enp0s5.20
(3)创建macvlan 网络
sudo docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=enp0s5.10 mac_net10 sudo docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=enp0s5.20 mac_net20
(4)在第一台主机上中运行容器
sudo docker run -itd --name test5 --ip=172.16.10.10 --network mac_net10 busybox sudo docker run -itd --name test6 --ip=172.16.20.10 --network mac_net20 busybox
(5)在第二台主机中运行容器
sudo docker run -itd --name test7 --ip=172.16.10.11 --network mac_net10 busybox sudo docker run -itd --name test8 --ip=172.16.20.11 --network mac_net20 busybox
验证macvlan之间的连通性
为了方便验证网络的通信,先对所创建的容器进行相应的说明:test5与test7这两个容器处于mac_net10下,IP分别为172.16.10.10和172.16.10.11;test6与test8处于mac_net20下,IP分别为172.16.20.10和172.16.20.11
让处于同一macvlan网络下的容器互ping,由结果可以看出同一macvlan网络下的容器之间是可以通信的
让处于不同macvlan网络下的容器互ping
由结果可以看出不同macvlan之间不能通信。准确的说是不同macvlan网络不能在二层上通信,在三层上可以通过网关将macvlan连通,下面我们就启用网关。我们将第三台主机配置成一个虚拟路由器,设置网关并转发VLAN10和VLAN20的流量,首先确保IP Forwarding已经启用
输出为1则表示启用,如果为0可通过如下命令启用
sudo sysctl -w net.ipv4.ip_forward=1
在 /etc/network/interfaces中配置vlan sub-interface
auto enp0s5 iface enp0s5 inet manual auto enp0s5.10 iface enp0s5.10 inet manual vlan-raw-device enp0s5 auto enp0s52.20 iface enp0s5.20 inet manual vlan-raw-device enp0s5
启用sub-interface
sudo ifup enp0s5.10 sudo ifup enp0s5.20
将网关IP配置到sub-interface
sudo ifconfig enp0s5.10 172.16.10.1 netmask 255.255.255.0 up sudo ifconfig enp0s5.20 172.16.20.1 netmask 255.255.255.0 up
添加iptables规则,转发不同VLAN的数据包
iptables -t nat -A POSTROUTING -o enp0s5.10 -j MASQUERADE iptables -t nat -A POSTROUTING -o enp0s5.20 -j MASQUERADE iptables -A FORWARD -i enp0s5.10 -o enp0s5.20 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i enp0s5.20 -o enp0s5.10 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i enp0s5.10 -o enp0s5.20 -j ACCEPT iptables -A FORWARD -i enp0s5.20 -o enp0s5.10 -j ACCEPT
现在第一台主机上位于mac_net10的test5已经可以与第二台主机上位于mac_net20的test8通信了
下面分析数据包是如何从test5(172.16.10.10)到达test8(172.16.20.11)的
(1)因为test5与test8在不同的IP网段,根据test5的路由表,数据包将发送到网段172.16.10.1
(2)路由器从enp0s5.10收到数据包,发现目的地址是172.16.20.11,查看自己的路由表,并将数据包从enp0s5.20转发出去
(3)通过ARP记录的信息,路由器能够得知172.16.20.11在第二台主机上,于是将数据包发送给第二台主机
(4)第二台主机根据目的地址和VLAN信息将数据包发送给test8
macvlan网络的连通性和隔离完全依赖VLAN、IP subnet和路由,docker本身不做任何限制,用户可以像管理传统VLAN网络那样管理macvlan