Calico 架构及BGP实现

Calico 架构及BGP实现

BGP是互联网上一个核心的去中心化自治路由协议,它通过维护IP路由表或“前缀”表来实现自治系统AS之间的可达性,属于矢量路由协议。不过,考虑到并非所有的网络都能支持BGP,以及Calico控制平面的设计要求物理网络必须是二层网络,以确保 vRouter间均直接可达,路由不能够将物理设备当作下一跳等原因,为了支持三层网络,Calico还推出了IP-in-IP叠加的模型,它也使用Overlay的方式来传输数据。IPIP的包头非常小,而且也是内置在内核中,因此理论上它的速度要比VxLAN快一点 。Calico 3.x的默认配置使用的是IPIP类型的传输方案而非BGP。

 

CalicoKubernetes生态系统中另一种流行的网络选择。虽然Flannel被公认为是最简单的选择,但Calico以其性能、灵活性而闻名。Calico的功能更为全面,不仅提供主机和pod之间的网络连接,还涉及网络安全和管理。Calico CNI插件在CNI框架内封装了Calico的功能。

Calico是一个基于BGP的纯三层的网络方案,与OpenStackKubernetesAWSGCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的虚拟路由器vRouter来负责数据转发。每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。

 

上面并不是什么严重的问题。但是有一点,Calico控制平面的上述设计中,物理网络最好是L2 Fabric,这样vRouter间都是直接可达的,路由不需要把物理设备当做下一跳。如果是L3 Fabric,控制平面的问题就来了:物理设备如果要存32位的路由,路由表将变得巨大无比。

因此,为了解决以上问题,Calico不得不采取了妥协,为了支持L3 Fabric,Calico推出了IPinIP的选项,用作cross-subnet下容器间通讯,但是有一定性能损耗。另一种方案是回退到L3 Hierarchy(calico目前支持),如果对容器迁移保持IP不变的需求不大,可以选择这种,这也是我们最后选择的方案。不过,对于使用L2 Fabric、没有多租户需求的企业来说,用calico上生产环境应该最理想选择。

Calico最理想的部署方式是基于L2 Fabrics的,官方也有相应说明([Calico over an Ethernet interconnect fabric](http://docs.projectcalico.org/ ... abric "Calico over an Ethernet interconnect fabric")),这里就不做详细说明了。由于我们数据中心规模比较大,显然L2 Fabrics不是理想的选择。事实也是如此,我们多个数据中心组成的网络是以BGP为控制层面组成的L3 Fabrics。每个数据中心为一个AS。这里不讨论跨数据中心的问题,大家只需知道我们跨数据中心在L3上是互通的便可以。

 

Calico是一个用于容器、虚拟机和基于本机主机的工作负载的开源网络和网络安全解决方案。Calico支持广泛的平台,包括Kubernetes, OpenShift, Docker EE, OpenStack和裸机服务。Calico支持多种网络架构,其中IPIP和BGP两种网络架构较为常用。这里简单说明一下这两种模式。
这两种模式下的calico所管理的容器内部联通主机外部网络的方法都是一样的,用linux支持的veth-pair,一端在容器内部一般名称是eth0@if66,这个66表示的是主机网络命名空间下的66号ip link.另一端是主机网络空间下的cali97e45806449,这个97e45806449是VethNameForWorkload函数利用容器属性计算的加密字符的前11个字符。每个Calico容器内部的路由如下所示:

default via 169.254.1.1 dev eth0 
169.254.1.1 dev eth0 scope link 

再去看Calico所有的veth-pair在主机空间的calixxx的MAC地址,无一例外都是ee:ee:ee:ee:ee:ee, 这样的配置简化了操作,使得容器会把报文交给169.254.1.1来处理,但是这个地址是本地保留的地址也可以说是个无效地址,但是通过veth-pair会传递到对端calixxx上,注意,因为calixxx网卡开启了arpproxy,所以它会代答所有的ARP请求,让容器的报文都发到calixxx上,也就是发送到主机网络栈,再有主机网络栈的路由来送到下一站. 可以通过cat /proc/sys/net/ipv4/conf/calixxx/proxy_arp/来查看,输出都是1.

这里注意,calico要响应arp请求还需要具备三个条件,否则容器内的ARP显示异常:

  1. 宿主机的arp代理得打开
  2. 宿主机需要有访问目的地址的明确路由,这里我理解为宿主机要有默认路由
  3. 发送arp request的接口与接收arp request的接口不能是相同,即容器中的默认网关不能是calico的虚拟网关

IPIP模式

IPIP模式是calico的默认网络架构,其实这也是一种overlay的网络架构,但是比overlay更常用的vxlan模式相比更加轻量化。IPinIP就是把一个IP数据包又套在一个IP包里,即把 IP 层封装到 IP 层的一个 tunnel它的作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来.

IPIP通信原理

calico中用环境变量CALICO_IPV4POOL_IPIP来标识是否开启IPinIP Mode. 如果该变量的值为Always那么就是开启IPIP,如果关闭需要设置为Never(大小写不敏感,代码里有strings.ToLower操作)。

IPIP的calico-node启动后会拉起一个linux系统的tunnel虚拟网卡tunl0, 并由二进制文件allocateip给它分配一个calico IPPool中的地址,log记录在本机的/var/log/calico/allocate-tunnel-addrs/目录下。tunl0是linux支持的隧道设备接口,当有这个接口时,出这个主机的IP包就会本封装成IPIP报文。同样的,当有数据进来时也会通过该接口解封IPIP报文。然后IPIP模式的网络通信模型如下图所示。

上图所示的通信如下:

  1. Pod-1 -> calixxx -> tunl0 -> eth0 <----> eth0 -> calixxx -> tunl0 -> Pod-2 1.c1访问c2时,ip包会出现在calixxx
  2. 根据c1宿主机中的路由规则中的下一跳,使用tunl0设备将ip包发送到c2的宿主机
  3. tunl0是一种ip隧道设备,当ip包进入该设备后,会被Linux中的ipip驱动将该ip包直接封装在宿主机网络的ip包中,然后发送到c2的宿主机
  4. 进入c2的宿主机后,该ip包会由ipip驱动解封装,获取原始的ip包,然后根据c2宿主机中路由规则发送到calixxx。
posted @ 2023-04-06 13:10  滴滴滴  阅读(473)  评论(0编辑  收藏  举报