树袋熊|十分钟漫谈容器网络方案01—Flannel

【树袋熊|十分钟漫谈容器网络方案01—Flannel】在《Docker和Kubernetes的前世今生(下)》中我们介绍了作为目前主流的容器编排系统 , Kubernetes支持的功能和为容器集群业务带来的便利 。 而为了设计并保障编排系统运作 , Kubernetes对容器集群进行了这样的要求:任何pods之间的通信都可以在不使用NAT的情况下进行 , 即设定集群内所有容器都是连通的 。 但Docker容器通过Namespace隔离 , 无法直接相互通信 , 默认可以通过共用宿主机的Network Namespace的方式 , 凭借宿主机的网络栈进行通讯 。 这样的方式也导致了一系列问题 , 比如征用宿主机端口时使端口资源很快不足使得通信规模受限 , 以及容器与宿主机共享的网络会暴露宿主机信息 , 致使网络传输存在安全隐患 。
— 为什么需要Overlay Network —
为了不影响隔离性并实现容器间的网络通信 , Docker通过虚拟网桥“连接”容器 , 使容器得以像物理节点一样经过“交换机”通讯 。 Docker在宿主机上创建名为docker0的虚拟网桥 , 对于每一个创建的容器均创建一对虚拟网卡设备 , 其中一端在docker0 , 另一端映射到容器内的eth0 , 并对容器内网卡分配一个容器网络IP 。 通过这一对虚拟网卡 , 容器就相当于“连接”到网桥上 , 虚拟网卡接在网桥上时只负责接受数据包 , 不再调用网络协议栈进行处理 , 因此只具有类似端口的作用 。 当容器A要访问容器B时 , 只需要广播ARP协议 , 通过docker0转发请求到对应”端口” , 就实现了数据的转发 。
然而 , 虽然虚拟网桥解决了同一宿主机下的容器间通信问题 , 以及容器与外部世界之间的通信 , 但是跨节点的容器通信依然存在问题 。 集群中每个节点的docker0都是独立的 , 不同节点分配的容器IP之间存在冲突的可能 , 因此需要有一个具有全局视角的上层网络以实现跨节点的容器网络 , 这便是Overlay Network解决方案的由来 。
— Flannel容器集群网络方案的出现 —
Flannel是由CoreOS提出的跨主通信容器网络解决方案 , 通过分配和管理全局唯一容器IP以及实现跨组网络转发的方式 , 构建基于Overlay Network的容器通信网络 。 作为最早出现的网络编排方案 , Flannel是最简单的集群编排方案之一 , 为容器跨节点通信提供了多种网络连接方式 , 后续很多插件的方案也是基于Flannel的方案进行扩展 。
Flannel的框架包含以下组件:每个节点上的代理服务flanneld , 负责为每个主机分配和管理子网;全局的网络配f置存储etcd(或K8S API)负责存储主机和容器子网的映射关系;多种网络转发功能的后端实现 。 本文主要介绍三种最常见的模式:UDP、VXLAN和Host-gateway(以下简称host-gw) 。
树袋熊|十分钟漫谈容器网络方案01—FlannelFlannel在Kubernetes集群中的架构图
— Flannel数据转发模式之UDP —
UDP是与Docker网桥模式最相似的实现模式 。 不同的是 , UDP模式在虚拟网桥基础上引入了TUN设备(flannel0) 。 TUN设备的特殊性在于它可以把数据包转给创建它的用户空间进程 , 从而实现内核到用户空间的拷贝 。 在Flannel中 , flannel0由flanneld进程创建 , 因此会把容器的数据包转到flanneld , 然后由flanneld封包转给宿主机发向外部网络 。
UDP转发的过程为:Node1的container-1发起的IP包(目的地址为Node2的container-2)通过容器网关发到docker0 , 宿主机根据本地路由表将该包转到flannel0 , 接着发给flanneld 。 Flanneld根据目的容器容器子网与宿主机地址的关系(由etcd维护)获得目的宿主机地址 , 然后进行UDP封包 , 转给宿主机网卡通过物理网络传送到目标节点 。 在UDP数据包到达目标节点后 , 根据对称过程进行解包 , 将数据传递给目标容器 。


推荐阅读