Kubernetes(三)—Flannel和K8s的网络通信

Docker的单机网络

在一个宿主机上,运行多个Docker容器,Docker会通过Linux的桥接方式,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过<宿主机IP>:<容器映射到宿主机的端口>来访问容器。

以上对于单个宿主机Docker的网络解决方案。对于一个K8s集群,包含了许多个Node(宿主机),每个Node上都通过Docker运行了很多容器。Flannel是K8s的一个网络解决方案,主要用于解决容器的跨主机通信问题,让集群中的容器通过内网ip就可以互相访问。

Flannel

简介

Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务。在默认的Docker配置中,每个Node的Docker服务会分别负责所在节点容器的IP分配。Node内部的容器之间可以相互访问,但是跨主机(Node)网络相互间是不能通信。Flannel设计目的就是为集群中所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得”同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。而且它还能在这些集群的IP地址之间建立一个覆盖网络(Overlay NetWork),通过这个覆盖网络,将数据包原封不动地传递到目标容器内。

Flannel只需要在Node节点安装,Master节点无需安装。

原理

Flannel 使用etcd存储网络配置数据和子网分配信息。
Flannel 启动之后,后台进程首先检索配置和正在使用的子网列表,然后选择一个可用的子网,并尝试去注册它。
etcd也存储这个每个主机对应的ip。Flannel 使用etcd的watch机制监视/coreos.com/network/subnets下面所有元素的变化信息,并且根据它来维护一个所有Pod节点的路由表。

在Flannel的GitHub页面有如下的一张原理图:

说明:在节点上启动了一个Flannel服务之后,会有一个Flanneld进程,该进程会去监听一个用来接收和转发数据包的端口。并且这个进程启动时会开启一个叫做Flannel0的网桥,Flannel0网桥可以去收集docker0网桥转发出来的数据报文(可以理解为勾子函数,强行获取数据报文)。

现在假设两个Pod之间要互相通信,分两种情况:

Pod1和Pod2在同一台主机上

这种情况下,Pod1和Pod2是docker0网桥下的子ip,直接通过docker0网桥就可以直接通信。

Pod1和Pod2不再同一台主机

这种情况,比如Pod1的IP是10.1.15.2,Pod2的IP是10.1.20.3。

  1. 因为Pod1和Pod2不在同一个网段,Pod1先将请求发送到它的网关docker0,docker0上有对应的勾子函数,把这个包抓到Flannel0网桥。
  2. Flanneld服务会监听Flannel0网卡的端口,Flannel0抓取到数据之后,根据etcd中保存的集群节点的路由表,判断应该发往哪个节点。 在etcd上保存了集群中各个ip对应的路由表,Flanneld根据路由表数据,判断应该发往哪个节点。
  3. 源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的Flanneld服务,数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一样的由docker0路由到达目标容器。
------ 本文完 ------