Calico 组网方式

Calico提供了一种纯三层的网络模型,任意两个Pod都是基于IP地址进行通信,不存在Pod在同一子网,通过二层交换数据的情形。

Calico网络有以下特点,在Pod的网络命名空间,可以看到:

  • Pod在独立的子网中,IP为xx.xx.xx.xx/32
  • Pod的默认路由指向一个虚拟地址169.254.1.1

在宿主机的网络命名空间中,可以看到:

  • 宿主机上没有网桥设备,veth的一端直接暴露在宿主机上
  • Pod在宿主机有一条独立的路由记录,报文到达宿主机后根据目的地址直接从veth进入容器

calico将IPPool地址池划分为多个子网,并分配给每台主机。但是每台主机上的veth没有在宿主机上接入网桥或者虚拟交换机中,Pod之间没有打通二层网络。 子网只是作为划分路由信息的依据,并且用户可以通过nodeSelect对子网进行非常灵活的划分。

以下是某个Kubernetes节点上的路由信息:

假设veth0和veth1是一对veth pair,分别位于Pod网络命名空间和宿主机网络命名空间。

Calico为了让veth0发出的报文能够在宿主机网络命名空间中被正确路由,利用了veth1的Proxy ARP功能。Proxy ARP能够让veth1响应针对本网络不存在的IP地址的ARP查询,并以自己的MAC地址进行响应。当veth1收到169.254.1.1的ARP请求时会向veth0回复一个虚假的MAC地址,veth0收到ARP回复后将报文发出。在宿主机网络中veth1接受到报文后,会根据报文目的地址以及宿主机上的路由表,再将报文转发到其他网卡中。

由于veth两端是直通的,因此网关地址169.254.1.1以及响应的MAC可以是任意值。

通 ip neigh 可以查看主机的arp缓存

开启网络设备的Proxy ARP echo 1 » /proc/sys/net/ipv4/conf/<设备名称>/proxy_arp

BGP 协议

Calico 作为一个纯三层的网络插件,其核心在于每个Node上拥有整个集群的完整路由信息,而这一能力正是基于BGP协议实现的。

BGP全称是Border Gateway Protocol,对应中文是边界网关协议,是当今互联网中最为核心的去中心化自治路由协议。

关于路由协议,包括以下几个概念:

  • AS:自治系统,即一个独立的整体网络,每个AS都有自己唯一的编号(在互联网场景中,每个AS的编号都是需要专门申请的,全球唯一)。
  • IGP:内部网关协议。IGP是用在AS内部的一种路由协议。AS内部可能并非2层互通,而是包含了多个路由器。在这种情形下,AS内部可以借助IGP协议实现网络互通。常见的IGP协议包括:RIP和OSPF。
  • EGP:外部网关协议,在多个AS之间使用的一种路由协议。BGP是当前最新的EGP协议!

虽然BGP是为了替代EGP而创建的,但是他同样可以应用在AS内部。因此BGP包括:

  • IBGP
  • EBGP

BGP是一种路径矢量协议。在应用BGP的网络中,若干台运行的着BGP服务的设备构成网络拓扑。可以将拓扑中每个BGP服务角色称为BGP Router,而与BGP Router连接的对端叫BGP peer

BGP Router 主要完成以下工作:

  • 每个BGP Router会接受对端发来的路由信息,并根据本地的Policy对路由信息进行合并、筛选并存储到本地BGP路由表中或者同步这些信息到主机的主路由表中。
  • BGP Router还会修改收到的路由信息,将自己加入到信息中,并对其他BGP Peer发送。

BGP协议使用TCP作为数据传输层,默认端口号为179。

BGP是应用在互联网场景的标准协议,为了将其运用在数据中心或者Kubernetes中,Calico、OpenStack等开源项目实际上对其作出了相当多的修改和优化。

当前BGP的开源实现包括:

BGP in the Data Center:https://www.oreilly.com/library/view/bgp-in-the/9781491983416/

中文翻译:https://arthurchiao.art/blog/bgp-in-data-center-zh/

BIRD

Kubernetes部署Calico时,会在Node节点部署以下三个进程:

  • BIRD:一个守护进程,它使用 BGP 协议将路由信息分发到其他节点
  • Felix:监视 Felix 数据存储,构建POD的路由信息,并配置当前节点的Iptables或者IPVS
  • Confd:监视 Calico 数据存储以获取配置更改,并更新 BIRD 配置文件

BIRD是一款可运行在Linux和其他类Unix系统上的路由软件,它实现了包括BGP、OSPF、RIP在内的多种路由协议,是Calico中最核心组件。

关于BIRD一些简单介绍可以参考:https://blog.csdn.net/alex_yangchuansheng/article/details/116810677?spm=1001.2014.3001.5501

Calico/Node容器集成了bird客户端birdcl,使用该工具我们可以查看对应节点的bird运行状态。

BGP Peer

默认情况下Calico工作在IBGP模式中,并且在IBGP Peer中学习到的路由信息不会再次被转发(BGP协议为了避免在AS内部出现环路),因此默认情况下Calico工作在nodeToNodeMesh模式中,所有Node之间两两形成Peer,以此来收集集群的完整路由信息。

通过以下命令,可以查看当前Peer的连接状态

1
calicoctl node status

输出如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Calico process is running.

IPv4 BGP status
+-----------------+-------------------+-------+------------+-------------+
|  PEER ADDRESS   |     PEER TYPE     | STATE |   SINCE    |    INFO     |
+-----------------+-------------------+-------+------------+-------------+
| 192.168.121.153 | node-to-node mesh | up    | 2021-11-15 | Established |
| 192.168.121.192 | node-to-node mesh | up    | 2021-11-15 | Established |
| 192.168.121.13  | node-to-node mesh | up    | 2021-11-15 | Established |
+-----------------+-------------------+-------+------------+-------------+

IPv6 BGP status
No IPv6 peers found.

BGP Speaker RR模式

NodeMesh模式下,网络中BGP总连接数是按照O(n^2)增长的,有太多Kubernetes节点时会消耗大量的连接。因此在大集群中通常使用BGP Speaker RR模式,来同步整个集群的路由信息。

BGP Speaker RR模式下,用户指定一个或多个Calico Node作为Router Reflection,RR与其他所有Node建立连接。其他Node只需要通过RR就可以获取整个集群完整的路由信息。

通过以下命令为Calico创建配置信息,并关闭nodeToNodeMeshEnabled开关:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
calicoctl create -f - <<EOF
 apiVersion: projectcalico.org/v3
 kind: BGPConfiguration
 metadata:
   name: default
 spec:
   logSeverityScreen: Info
   nodeToNodeMeshEnabled: false
   asNumber: 64512
EOF

# 查看当前Calico配置
calicoctl get bgpconfig

关闭NodeMesh之后可以运行calicoctl node status发现节点BGP Session全部消失,Pod已经无法跨节点Ping通。

假设Kubernetes中选择node1和node2作为RR服务器,我们需要手动为这两个Node指定routeReflectorClusterID,并打上指定的Label:

1
2
3
4
calicoctl patch node node1 -p '{"spec": {"bgp": {"routeReflectorClusterID" : "244.0.0.1"}}}'
calicoctl patch node node2 -p '{"spec": {"bgp": {"routeReflectorClusterID" : "244.0.0.1"}}}'
kubectl label node node1 route-reflector=true
kubectl label node node2 route-reflector=true

routeReflectorClusterID 通常是未使用过的IP地址

创建BGPPeer,含义是:所有节点(nodeSelector:all())都和包含指定标签的节点(peerSelector: route-reflector == ‘true’)建立BGP连接:

1
2
3
4
5
6
7
8
9
calicoctl create -f - <<EOF
 apiVersion: projectcalico.org/v3
 kind: BGPPeer
 metadata:
   name: peer-with-rr
 spec:
   nodeSelector: all()
   peerSelector: route-reflector == 'true'
EOF

关于CRD的字段含义可以参考:https://docs.projectcalico.org/reference/resources/overview