昨天,我在研究容器网络的时候,同事忽然问了我一个问题: Kubernetes 上的容器能支持跨主机二层通讯?这个问题一下把我问住了,我感受本身这几天的容器网络都白学了,我居然无言以对。。但这个问题也激起了我强烈的好奇心,我怎么也要弄个明白。node
在被问到这个问题后,我开始进行了思考。首先不管是 IaaS 平台的网络或者是 PaaS 平台的网络架构跨宿主机通讯的方式主要也就如下几种方式:网络
其实从根本上看,我认为只有 Overlay 网络和 Host-gw 这两种。Overlay 在我看来就是和隧道协议的原理是差很少的,就是在承载网络协议上面再定义新的协议。而 Host-gw 则是经过配置路由了,使宿主机成为一个路由器,像是把网络架构从三维压缩到了二维,从而让容器和宿主机展开在同一平面上。架构
但因为 Host-gw 经过宿主机进行了路由转发, 天然两个宿主机上把原始容器的 mac 地址也修改了,无疑是没法进行二层通讯的。而 UDP 封装的是三层的数据包,因此也是没法进行链路层通讯的。那么只剩下 VXLAN 了。tcp
VXLAN 相比 UDP 和其余的一些隧道协议的好处如数据包内核态封装解封装,24位 VXLANID,支持组播和二层通讯等等。因此我把但愿所有寄托在 VXLAN 上了。加上以前有搭建过 OpenStack 而且平时也常用云主机,同一 VPC 内的云主机能够二层通讯这我是知道的。因此我认为在 Kubernetes 上使用 VXLAN 也是能够二层通讯的。学习
然而,事实并无这么简单。首先让咱们看一下 IaaS 平台上 VXLAN 是如何工做的。spa
在 IaaS 平台上,VXLAN 的协议格式以下图所示:插件
能够看到跨宿主机通讯的报文就是 外层数据帧 + VXLAN 头 + 内层数据帧。
那么问题来了,两台虚拟机通讯,一台是是 A,一台是 B,他们通讯存在以下问题:blog
答案是 VTEP,全部宿主机上的 VTEP 都在一个组播组内,他们之间经过组播通讯,因此上面的这几件事都是 VTEP 负责干。那么天然 VTEP 知道各台虚拟机在哪台宿主机上了,不知道就在组播组内问一下,而后本身学习记住 mac 地址。以下图所示:进程
在 VTEP 的帮助下,各个虚拟机就能达到了跨宿主机通讯的目的。ip
Kubernetes 上的网络管理须要经过第三方的插件,如 Flannel,weave,calico 等。这里咱们使用 Flannel VXLAN。在Kubernetes 上使用 VXLAN 一样也要新建一个 VTEP 设备,如 flannel.1。
本觉得,在 IaaS 平台上,使用 VXLAN 协议能够跨主机二层通讯,那么一样在 Kubernetes 上 使用 VXLAN ,容器也能够实现二层通讯啦?然而事实证实我仍是太年轻了。
在容器里面用 tcpdump 抓包发现,内层报文的源 mac 地址和目的 mac 地址并非容器的的 mac 地址,而是源宿主机和目标宿主机 flannel.1 的 mac 地址,以下图所示:
这就让人很困惑了,这又是为啥呢。原来 VTEP 是个链路层的端点设备,在 OpenStack 等 IaaS 平台上可能是用 OpenvSwitch 来实现 VTEP 的功能,OpenvSwitch 的功能很是强大,他能够自动的学习各个宿主机上的虚拟机的 mac 地址,而且经过 openflow 协议的流表作数据包的操做。
而在 Kubernetes 上就不同了, VTEP 他并非经过组播的方式来学习容器的 Mac 地址。而是每台 Kubernetes node 启动时,flannel 进程会把他的子网, flannel.1 网卡 mac 地址写入到 Etcd 里面,并下发到每台 node 上,从而每台主机上都会创建发往目标网段的路由,并由 flannel.1 发出。以下图所示:
然而此时 flannel.1 只知道发送目标 flannel.1 的 mac 地址,并不知道对方的宿主机 ip,那么怎么封装外层帧呢?这个时候 flannel 设备会查到 FBD,根据 mac 地址找到对方的宿主机地址 ip。同时,VTEP 还把 VNI 设置为 1,这个也是 VTEP 识别是否是归本身处理的数据帧的一个重要的标识,并最终组装成以下所示的包发往对方:
那么也就能够解释为何内部数据帧的 mac 地址为何是 VTEP 设备的 mac 地址了。
至此,咱们能够得出结论了。Kubernetes 没法保证二层网络互通,由于 flannel.1 设备并无学习到容器的 mac 地址,因此若是一个容器 A 发往容器 B ,那么容器 A 并不知道容器 B 的 mac 地址。
那么若是想要实现容器跨主机二层通讯,那么可能须要像 OpenvSwtich 同样,全部的 VTEP 设备加入到一个组播组中,而且要具备学习 mac 的能力。
VXLAN 的一些功能 flannel 都没有用到,好比flannel 上 VXLAN 的VNI 都是设置为 1,没法对网络作一个隔离。总的来讲在 flannel 使用 VXLAN更多的只是做为 UDP 模式的一种替代,只是把封装、解封装放在内核态了,而且从三层降为二层。固然,通常状况下容器网络三层互通也够用了。