上一篇文章我演示了docker bridge网络模型的实验,这次我将展示如何利用Overlay 网络实现跨主机容器的通信。

两个容器docker1和docker2分别位于节点Node-1和Node-2,如何实现容器的跨主机通信呢?一般来说有两种实现方式:
- 封包模式:利用
Overlay网络协议在节点间建立“隧道”,容器之间的网络包被封装在外层的网络协议包中进行传输。 - 路由模式:容器间的网络包传输全部用三层网络的路由转发来实现。
本文主要介绍封包模式。Overlay网络主要有两种方式,一种是使用UDP在用户态封装,一种是利用VXLAN 在内核态封装。由于减少了用户态到内核态的切换,封包解包逻辑都在内核态进行,VXLAN 的性能更好,成为了容器网络的主流方案。
关于路由模式,会在下一篇文章介绍。
# VXLAN
VXLAN(Virtual Extensible LAN)是一种网络虚拟化技术,它将链路层的以太网包封装到UDP包中进行传输。VXLAN最初是由VMware、Cisco开发,主要解决云环境下多租户的二层网络隔离。我们常听到公有云厂商宣称支持VPC(virtual private cloud),实际底层就是使用VXLAN实现的。
VXLAN packet的结构:

我们可以看到,最内部是原始的二层网络包,外面加上一个VXLAN header,其中最重要的是VNI(VXLAN network identifier)字段,它用来唯一标识一个VXLAN。也就是说,使用不同的VNI来区分不同的虚拟二层网络。VNI有24位,基本够公用云厂商使用了。要知道原先用来网络隔离的虚拟局域网VLAN只支持4096个虚拟网络。
在 VXLAN header外面封装了正常的UDP包。VXLAN在UDP之上,实现了一个虚拟的二层网络,连接在这个虚拟二层网络上的主机,就像连接在普通的局域网上一样,可以互相通信。
介绍完背景知识,我们可以开始动手实验了。
# 实现方案一
参照Flannel的实现方案:

- 配置内核参数,允许IP forwarding
分别在Node-1、Node-2上执行:
|
|
- 创建“容器”
在Node-1上执行:
|
|
在Node-2上执行:
|
|
为什么创建个Namesapce就说是“容器”?请参考上一篇文章。
- 创建Veth pairs
分别在Node-1、Node-2上执行:
|
|
- 将Veth的一端放入“容器”
在Node-1上执行:
|
|
在Node-2上执行:
|
|
- 创建bridge
分别在Node-1、Node-2上创建bridge br0:
|
|
- 将Veth的另一端接入bridge
分别在Node-1、Node-2上执行:
|
|
- 为"容器“内的网卡分配IP地址,并激活上线
在Node-1上执行:
|
|
在Node-2上执行:
|
|
- Veth另一端的网卡激活上线
分别在Node-1、Node-2上执行:
|
|
- 为bridge分配IP地址,激活上线
在Node-1上执行:
|
|
在Node-2上执行:
|
|
- 将bridge设置为“容器”的缺省网关
在Node-1上执行:
|
|
在Node-2上执行:
|
|
- 创建VXLAN虚拟网卡
VXLAN需要在宿主机上创建一个虚拟网络设备对 VXLAN 的包进行封装和解封装,实现这个功能的设备称为 VTEP(VXLAN Tunnel Endpoint)。宿主机之间通过VTEP建立“隧道”,在其中传输虚拟二层网络包。
在Node-1创建vxlan100:
|
|
为vxlan100分配IP地址,然后激活:
|
|
为了让Node-1上访问172.18.20.0/24网段的数据包能进入“隧道”,我们需要增加如下的路由规则:
|
|
在Node-2上执行相应的命令:
|
|
- 手动更新ARP和FDB
虚拟设备vxlan100会用ARP和FDB (forwarding database) 数据库中记录的信息,填充网络协议包,建立节点间转发虚拟网络数据包的“隧道”。
我们知道,在二层网络上传输IP包,需要先根据目的IP地址查询到目的MAC地址,这就是ARP(Address Resolution Protocol)协议的作用。我们应该可以通过ARP查询到其他节点上容器IP地址对应的MAC地址,然后填充在VXLAN内层的网络包中。
FDB是记录网桥设备转发数据包的规则。虚拟网络数据包根据上面定义的路由规则,从br0进入了本机的vxlan100“隧道”入口,应该可以在FDB中查询到“隧道”出口的MAC地址应该如何到达,这样,两个VTEP就能完成”隧道“的建立。
vxlan为了建立节点间的“隧道”,需要一种机制,能让一个节点的加入、退出信息通知到其他节点,可以采用multicast的方式进行节点的自动发现,也有很多Unicast的方案,这篇文章<VXLAN & Linux>有很详细的介绍。总之就是要找到一种方式,能够更新每个节点的ARP和FDB数据库。
如果是使用Flannel,它在节点启动的时候会采用某种机制自动更新其他节点的ARP和FDB数据库。现在我们的实验只能在两个节点上手动更新ARP和FDB。
首先在两个节点上查询到设备vxlan100的MAC地址,例如在我当前的环境:
Node-1上vxlan100的MAC地址是3a:8d:b8:69:10:3e
Node-2上vxlan100的MAC地址是0e:e6:e6:5d:c2:da
然后在Node-1上增加ARP和FDB的记录:
|
|
我们可以确认下执行结果:

ARP中已经记录了Node-2上容器IP对应的MAC地址。再看看FDB的情况:

根据最后一条新增规则,我们可以知道如何到达Node-2上“隧道”的出口vxlan100。“隧道”两端是使用UDP进行传输,即容器间通讯的二层网络包是靠UDP在宿主机之间通信。
类似的,在Node-2上执行下面的命令:
|
|
- 测试容器的跨节点通信
现在,容器docker1和docker1之间就可以相互访问了。
我们从docker1访问docker2,在Node-1上执行:
|
|
同样可以从docker2访问docker1,在Node-2上执行:
|
|
在测试过程中如果需要troubleshooting,可以使用tcpdump在veth1、br0、vxlan100等虚拟设备上抓包,确认网络包是按照预定路线在转发:
|
|
- 测试环境恢复
在两个节点上删除我们创建的虚拟设备:
|
|
# 实现方案二
Docker原生的overlay driver底层也是使用VXLAN技术,但实现方案和Flannel略有不同:

我们可以看到,vxlan100被“插”在了虚拟交换机br0上,虚拟网络数据包从br0到vxlan100不是通过本机路由,而是vxlan100根据FDB直接进行了转发。
执行的命令略有差异,我不再赘述过程,直接提供了命令,大家自己实验吧:
|
|
相信通过亲自动手实验,容器网络对你来说不再神秘。希望本文对你理解容器网络有所帮助。
下一篇我将动手实验容器跨主机通信的路由模式。