k8s网络原理之Calico
之前整理总结过有关flannel的相关原理以及详细的传输过程,一直都想总结一篇通俗易懂的有关calico的相关原理和传输过程的,因为平常事情较多,没想到一拖就是这么久,这回借着复习的机会,将calico的原理,传输过程,以及各组件的作用还有两种模式进行了细致的讲解和分析对比,也是对自己之前学习的一个总结,希望对大家有帮助。
什么是Calico:
Calico是一个基于BGP的纯三层网络方案,其会为每个容器(pod)分配一个可路由的IP,在通信时不需要解包和拆包,因此网络性能损耗小,易于排查和水平扩展。Calico网络功能强大,可以与istio集成。Calico IPIP模式与Vxlan类似,也是通过网络隧道技术实现的,与Vxlan的差别就是,VXLAN本质上本质上是一个UDP包,而IPIP则将包封装在本身的报文包上。它其实是利用了Linux 的tun/tap设备,对IP层的报文再加了一层IP层的封装实现的一种overlay模式。因为IPIP模式比BGP模式多了一层封包与拆包,所以性能会有所损耗。既然如此,为什么不直接使用BGP模式就行了呢?因为BGP模式是需要通过路由广播交换容器网络的路由信息,而路由广播只能在局域网中进行,在BGP模式下,如果kubernetes集群中的工作节点不在同一个子网,则跨子网的工作节点上的POD无法正常通信,下面就来详细讲解calico的这两种网络模式的原理以及他们各自的优缺点和适用场景
Calico的两种模式:
ipip模式:
Calico 的ipip模式是适用于node节点处于不同网段之间的pod的通信模式,也就是pod节点所在的node节点不在同一个二层网络中,在VXLAN中的报头里VNI标记不同
BGP模式:
Calico 的BGP模式是适用于node节点处于相同网段之间的pod的通信模式,是把每个node节点都当成是路由器的一种模式(将节点之间的路由规则配置在node节点上),每个node节点都维护着到其他节点的路由转发表(由felix进行维护,BIRD将路由表向其他节点进行广播和转发)
Calico 网络模型的设计思路:
相同网段转发原理(BGP模式):
我们看图中的两台物理机。它们的物理网卡是同一个二层网络里面的。由于两台物理机的容器网段不同,我们完全可以将两台物理机配置成为路由器,并按照容器的网段配置路由表。
例如,在物理机 A 中,我们可以这样配置:要想访问网段 172.17.9.0/24,下一跳是 192.168.100.101,也即到物理机 B 上去。
这样在容器 A 中访问容器 B,当包到达物理机 A 的时候,就能够匹配到这条路由规则,并将包发给下一跳的路由器,也即发给物理机 B。在物理机 B 上也有路由规则,要访问 172.17.9.0/24,从 docker0 的网卡进去即可。
当容器 B 返回结果的时候,在物理机 B 上,可以做类似的配置:要想访问网段 172.17.8.0/24,下一跳是 192.168.100.100,也即到物理机 A 上去。
不同网段转发原理(IPIP模式):
跨网段访问问题
上面的 Calico 模式还有一个问题,就是跨网段问题,这里的跨网段是指物理机跨网段。
前面我们说的那些逻辑成立的条件,是我们假设物理机可以作为路由器进行使用。例如物理机 A 要告诉物理机 B,你要访问 172.17.8.0/24,下一跳是我 192.168.100.100;同理,物理机 B 要告诉物理机 A,你要访问 172.17.9.0/24,下一跳是我 192.168.100.101。
之所以能够这样,是因为物理机 A 和物理机 B 是同一个网段的,是连接在同一个交换机上的。那如果物理机 A 和物理机 B 不是在同一个网段呢?
例如,物理机 A 的网段是 192.168.100.100/24,物理机 B 的网段是 192.168.200.101/24,这样两台机器就不能通过二层交换机连接起来了,需要在中间放一台路由器,做一次路由转发,才能跨网段访问。
本来物理机 A 要告诉物理机 B,你要访问 172.17.8.0/24,下一跳是我 192.168.100.100 的,但是中间多了一台路由器,下一跳不是我了,而是中间的这台路由器了,这台路由器的再下一跳,才是我。这样之前的逻辑就不成立了。
我们看刚才那张图的下半部分。物理机 B 上的容器要访问物理机 A 上的容器,第一跳就是物理机 B,IP 为 192.168.200.101,第二跳是中间的物理路由器右面的网口,IP 为 192.168.200.1,第三跳才是物理机 A,IP 为 192.168.100.100。
这是咱们通过拓扑图看到的,关键问题是,在系统中物理机 A 如何告诉物理机 B,怎么让它才能到我这里?物理机 A 根本不可能知道从物理机 B 出来之后的下一跳是谁,况且现在只是中间隔着一个路由器这种简单的情况,如果隔着多个路由器呢?谁能把这一串的路径告诉物理机 B 呢?
我们能想到的第一种方式是,让中间所有的路由器都来适配 Calico。本来它们互相告知路由,只互相告知物理机的,现在还要告知容器的网段。这在大部分情况下,是不可能的。
第二种方式,还是在物理机 A 和物理机 B 之间打一个隧道,这个隧道有两个端点,在端点上进行封装,将容器的 IP 作为乘客协议放在隧道里面,而物理主机的 IP 放在外面作为承载协议。这样不管外层的 IP 通过传统的物理网络,走多少跳到达目标物理机,从隧道两端看起来,物理机 A 的下一跳就是物理机 B,这样前面的逻辑才能成立。
calico架构图:
BGP模式下各组件的作用:
Felix作用:Calico Agent,运行在每一台 Host 的 agent 进程,主要负责网络接口管理和监听、路由、ARP 管理、ACL 管理和同步、状态上报等,保证跨主机容器的网络互通。
BGP Client(BIRD)作用:在 Calico 的角色是监听 Host 上由 Felix 注入的路由信息,然后通过 BGP 协议广播告诉剩余 Host 节点,从而实现网络互通。
BGP Route Reflector:在大型网络规模中,如果仅仅使用 BGP client 形成 mesh 全网互联的方案就会导致规模限制,因为所有节点之间俩俩互联,需要 N^2 个连接,为了解决这个规模问题,可以采用 BGP 的 Router Reflector 的方法,使所有 BGP Client 仅与特定 RR 节点互联并做路由同步,从而大大减少连接数。
Calico BGP模式的优点:CalicoBGP模式是一种纯三层的实现,因此可以避免与二层方案相关的数据包封装的操作,中间没有任何的NAT,没有任何的overlay,所以它的转发效率可能是所有方案中最高的,因为它的包直接走原生TCP/IP的协议栈,它的隔离也因为这个栈而变得好做。因为TCP/IP的协议栈提供了一整套的防火墙的规则,所以它可以通过IPTABLES的规则达到比较复杂的隔离逻辑。
二层网络通讯需要依赖广播消息机制,广播消息的开销与 host 的数量呈指数级增长,Calico 使用的三层路由方法,则完全抑制了二层广播,减少了资源开销。
另外,二层网络使用 VLAN 隔离技术,天生有 4096 个规格限制,即便可以使用 vxlan 解决,但 vxlan 又带来了隧道开销的新问题。而 Calico 不使用 vlan 或 vxlan 技术,使资源利用率更高。
IPIP模式数据包传输流程:
测试环境:
一个msater节点,ip 172.171.5.95,一个node节点 ip 172.171.5.96 :
创建一个daemonset的应用,pod1落在master节点上 ip地址为192.168.236.3,pod2落在node节点上 ip地址为192.168.190.203:
pod1 ping pod2:
数据包传输的具体流程如下:
pod1上的路由信息:
根据路由信息,ping 192.168.190.203,会匹配到第一条。第一条路由的意思是:去往任何网段的数据包都发往网管169.254.1.1,然后从eth0网卡发送出去。
路由表中Flags标志的含义:
U up表示当前为启动状态
H host表示该路由为一个主机,多为达到数据包的路由
G Gateway 表示该路由是一个网关,如果没有说明目的地是直连的
D Dynamicaly 表示该路由是重定向报文修改
M 表示该路由已被重定向报文修改
master节点上的路由信息:
当ping包来到master节点上,会匹配到路由tunl0。该路由的意思是:去往192.169.190.192/26的网段的数据包都发往网关172.171.5.96。因为pod1在5.95,pod2在5.96。所以数据包就通过设备tunl0发往到node节点上。
node节点上路由信息:
当node节点网卡收到数据包之后,发现发往的目的ip为192.168.190.203,于是匹配到红线的路由。该路由的意思是:192.168.190.203是本机直连设备,去往设备的数据包发往caliadce112d250。
那么该设备是什么呢?如果到这里你能猜出来是什么,那说明你的网络功底是不错的。这个设备就是veth pair的一端。在创建pod2时calico会给pod2创建一个veth pair设备。一端是pod2的网卡,另一端就是我们看到的caliadce112d250。下面我们验证一下。在pod2中安装ethtool工具,然后使用ethtool -S eth0,查看veth pair另一端的设备号。
pod2 网卡另一端的设备好号是18,在node上查看编号为18的网络设备,可以发现该网络设备就是caliadce112d250。
所以,node上的路由,发送caliadce112d250的数据其实就是发送到pod2的网卡中。ping包的旅行到这里就到了目的地。
查看一下pod2中的路由信息,发现该路由信息和pod1中是一样的。
顾名思义,IPIP网络就是将IP网络封装在IP网络里。IPIP网络的特点是所有pod的数据流量都从隧道tunl0发送,并且在tunl0这增加了一层传输层的封包。
在master网卡上抓包分析该过程:
打开ICMP 285,pod1 ping pod2的数据包,能够看到该数据包一共5层,其中IP所在的网络层有两个,分别是pod之间的网络和主机之间的网络封装:
根据数据包的封装顺序,应该是在pod1 ping pod2的ICMP包外面多封装了一层主机之间的数据包:
之所以要这样做是因为tunl0是一个隧道端点设备,在数据到达时要加上一层封装,便于发送到对端隧道设备中。
两层IP封装的具体内容:
BGP模式数据包传输流程:
测试环境:
在安装calico网络时,默认安装是IPIP网络。calico.yaml文件中,将CALICO_IPV4POOL_IPIP的值修改成 "off",就能够替换成BGP网络。
BGP网络相比较IPIP网络,最大的不同之处就是没有了隧道设备 tunl0。 前面介绍过IPIP网络pod之间的流量发送tunl0,然后tunl0发送对端设备。BGP网络中,pod之间的流量直接从网卡发送目的地,减少了tunl0这个环节。
master节点上路由信息。从路由信息来看,没有tunl0设备。
同样创建一个daemonset,pod1在master节点上,pod2在node节点上。
数据包传输的具体流程如下:
pod1 ping pod2。
根据pod1中的路由信息,ping包通过eth0网卡发送到master节点上。
master节点上路由信息。根据匹配到的 192.168.190.192 路由,该路由的意思是:去往网段192.168.190.192/26 的数据包,发送网段172.171.5.96。而5.96就是node节点。所以,该数据包直接发送了5.96节点。
node节点上的路由信息。根据匹配到的192.168.190.192的路由,数据将发送给 cali6fcd7d1702e设备,该设备和上面分析的是一样,为pod2的veth pair 的一端。数据就直接发送给pod2的网卡。
当pod2对ping包做出回应之后,数据到达node节点上,匹配到192.168.236.0的路由,该路由说的是:去往网段192.168.236.0/26 的数据,发送给网关 172.171.5.95。数据包就直接通过网卡ens160,发送到master节点上。
通过在master节点上抓包,查看经过的流量,筛选出ICMP,找到pod1 ping pod2的数据包。
可以看到BGP网络下,没有使用IPIP模式,数据包是正常的封装。
值得注意的是mac地址的封装。192.168.236.0是pod1的ip,192.168.190.198是pod2的ip。而源mac地址是 master节点网卡的mac,目的mac是node节点的网卡的mac。这说明,在 master节点的路由接收到数据,重新构建数据包时,使用arp请求,将node节点的mac拿到,然后封装到数据链路层。
两种模式的对比:
区别主要有两个:
1.BGP模式适用于同网段之间node节点上的不同Pod的通信,而IPIP模式适用于不同网段之间的通信
2.BGP模式将容器所在节点化身为路由器(vRouter),提供了路由的功能,并通过BGP协议将路由规则进行分发,再通过路由器上的路由规则,将包转发到目的地。在这个过程中,没有IPIP模式隧道的封包解包,仅仅是单纯的路由转发,性能会好很多。