CNI存在的意义


为了对接第三方的网络组件,提供一种接口,实现接口逻辑的松耦合

网络组件之Calico



Calico是一个纯三层(基于路由的)的数据中心网络方案,Calico支持广泛的平台,包括Kubernetes、OpenStack等。

Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的虚拟路由器( vRouter) 来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己上运行的 workl oad 的路由信息向整个 Calico 网络内传播。(工作的时候在每个节点跑代理程序来负责该节点的路由规则和网络配置,也会将这个节点当作虚拟路由器看待,实现跨界点的数据包的转发)此外,Calico 项目还实现了 Kubernetes 网络策略,提供ACL功能。

实际上,Calico项目提供的网络解决方案,与Flannel的host-gw模式几乎一样。也就是说,Calico也是基于路由表实现容器数据包转发,但不同于Flannel使用flanneld进程来维护路由信息的做法,而Calico项目使用BGP协议来自动维护整个集群的路由信息。(一个是通过进程之间来维护路由表,一个是通过BGP协议来维护路由表)

BGP英文全称是Border Gateway Protocol,即边界网关协议,它是一种自治系统间的动态路由发现协议,与其他 BGP 系统交换网络可达信息

Calico最核心的设计思想是把负责的主机当作路由器,直接是路由的转发。

路由器的路由表是由BGP去负责,相互的学习和同步的,同时也支持网络策略,提供pod的acl。

K8s网络组件之Calico:BGP介绍




Kubernetes CNI组件Calico:IPIP工作模式_ico



在这个图中,有两个自治系统(autonomous system,简称为AS):AS 1 和 AS 2。 在互联网中,一个自治系统(AS)是一个有权自主地决定在本系统中应采用何种路由协议的小型单位。这



个网络单位可以是一个简单的网络也可以是一个由一个或多个普通的网络管理员来控制的网络群体,它是一个单独的可管理的网络单元(例如一所大学,一个企业或者一个公司个体)。一个自治系统有时也 被称为是一个路由选择域(routing domain)。一个自治系统将会分配一个全局的唯一的16位号码,有时我们把这个号码叫做自治系统号(ASN)。




在正常情况下,自治系统之间不会有任何来往。如果两个自治系统里的主机,要通过 IP 地址直接进行通信,我们就必须使用路由器把这两个自治系统连接起来。BGP协议就是让他们互联的一种方式。



在这里你可以理解为两个公司,这两个公司的网络是没有任何来往的,要让as1中的机器访问as2中的机器,显然是无法通信的

有了bgp将两个公司路由器通过BGP协议去打通,相互学习对方的路由表添加到自己的里面,这样就可以将两个公司的网络连接起来

现在192.168.1.10要访问172.17.1.20,现在上层的路由器配置了BGP协议,那么就会交换双方的路由信息,将对方学到的路由信息写到自己里面。

上面黄色部分就是学到的路由表,目标172.17.1.20在路由表显示的是router2,在真实路由表里面是这个路由器的IP,这里就是下一跳,然后从B口出去到达router2的路由器,router2又有路由表,目标172.17.1.20是从A口出去,然后到达二层交换机通过ARP协议获取mac地址去通信,最终到达172.17.1.20机器。



同样的道理,公司2要访问公司1里面某台机器要保证有最后一条路由表。上面其实看到BGP就是将两个网络连接起来,所以形象的就称之为边界网关。

BGP边界网关,BGP多线连接着多条线路

BGP实现了路由共享的协议,BGP在calico这里取代了flannel通过进程维护的功能,BGP针对于大规模网络的协议可靠性扩展性远比flannel强的多。

BGP用于在大规模的网络当中实现的路由共享的协议,BGP协议在calico这里取代了flanneld进程维护的那种功能。

在了解了 BGP 之后,Calico 项目的架构就非常容易理解了。

Calico主要由三个部分组成


在了解了 BGP 之后,Calico 项目的架构就非常容易理解了。

• Felix:以DaemonSet方式部署,运行在每一个Node节点上,主要负责维护宿主机上路由规则以及ACL规则。(从别的节点学习路由表的信息)

• BGP Client(BIRD):主要负责把 Felix 写入 Kernel 的路由信息分发到集群 Calico 网络。(新启动了一个节点加入集群,会新启动一个agent,agent里面就包括了felix还有bgp client,会从其他的集群网路当中以BPG协议获取除本节点集群涉及到的网络,都将其学习过来,通过BPG clicent写到宿主机上面)

• Etcd:分布式键值存储,保存Calico的策略和网络配置状态。

• calicoctl:命令行管理Calico。

Kubernetes CNI组件Calico:IPIP工作模式_ico_02

Calico存储有两种方式


 • 数据存储在etcd

​https://docs.projectcalico.org/v3.9/manifests/calico-etcd.yaml​

• 数据存储在Kubernetes API Datastore服务中

​https://docs.projectcalico.org/manifests/calico.yaml​

数据存储在etcd中还需要修改yaml:

• 配置连接etcd地址,如果使用https,还需要配置证书。(ConfigMap和Secret位置)

• 根据实际网络规划修改Pod CIDR(CALICOIPV4POOLCIDR)

部署:

# kubectl apply -f calico.yaml
# kubectl get pods -n kube-system

K8s节点大于100台,建议数据存储在etcd当中,注意pod的网段,要与实际规划的网络保持一致

[root@k8s-master manifests]# vim kube-controller-manager.yaml 
[root@k8s-master manifests]# pwd
/etc/kubernetes/manifests
- --allocate-node-cidrs=true
- --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
- --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
- --bind-address=127.0.0.1
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --cluster-cidr=10.244.0.0/16

要想存储在外部的etcd当作

etcd_ca: ""   # "/calico-secrets/etcd-ca"
etcd_cert: "" # "/calico-secrets/etcd-cert"
etcd_key: "" # "/calico-secrets/etcd-key"

写上etcd的私钥,数字证书,CA,配置连接集群的字符串

etcd_endpoints: "http://<ETCD_IP>:<ETCD_PORT>"

修改网段和你规划的保持一致,yml文件里面只需要修改这个

            - name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"

K8s网络组件之Calico:管理工具


calicoctl工具用于管理calico,可通过命令行读取、创建、更新和删除 Calico 的存储对象。

项目地址:https://github.com/projectcalico/calicoctl

calicoctl 在使用过程中,需要从配置文件中读取 Calico 对象存储地址等信息。默认配置文件路径 /etc/calico/calicoctl.cfg

二进制程序

[root@k8s-master ~]# chmod o+x calicoctl 
[root@k8s-master ~]# mv calicoctl /usr/bin/
[root@k8s-master ~]# mkdir -p /etc/calico/
[root@k8s-master ~]# cd /etc/calico/
[root@k8s-master calico]# cat calicoctl.cfg
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
datastoreType: "kubernetes"
kubeconfig: "/root/.kube/config"

如果你使用kubeadm部署的话,这就是一个默认路径。如果使用的是二进制部署的话kube config是需要手动生成

查看Calico状态:

可以查看calico bgp的一个网格,这里会显示除了自己之外的其他的节点,这个网络连接就是为了同步路由信息走的是BGP协议。

[root@k8s-master ~]# calicoctl get node
NAME
k8s-master
k8s-node1
k8s-node2

[root@k8s-master ~]# calicoctl get node -o wide
NAME ASN IPV4 IPV6
k8s-master (64512) 192.168.179.102/24
k8s-node1 (64512) 192.168.179.103/24
k8s-node2 (64512) 192.168.179.104/24

[root@k8s-master ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+-----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+-----------------+-------------------+-------+----------+-------------+
| 192.168.179.103 | node-to-node mesh | up | 09:57:38 | Established |
| 192.168.179.104 | node-to-node mesh | up | 09:56:54 | Established |
+-----------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

查看当前网段
[root@k8s-master ~]# calicoctl get ippool
NAME CIDR SELECTOR
default-ipv4-ippool 10.244.0.0/16 all()

[root@k8s-master ~]# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 10.244.0.0/16 true Always Never false all()

K8s网络组件之Calico:工作模式


Calico工作模式:

• IPIP:Overlay Network方案,源数据包封装在宿主机网络包里进行转发和通信。(默认)

• BGP:基于路由转发,每个节点通过BGP协议同步路由表,写到宿主机。

• CrossSubnet:同时支持BGP和IPIP,即根据子网选择转发方式。(折中方案,集群当中是有两个网段,又想使用路由的高性能)

通过调整参数改变工作模式:

- name: CALICO_IPV4POOL_IPIP
value: "Always"

K8s网络组件之Calico:IPIP工作模式


和flannel的vxlan实现的原理类似,都是一种网络虚拟化技术,将原始的数据包封装在书主机网络数据包里面转发

IPIP模式:采用Linux IPIP隧道技术实现的数据包封装与转发。

IP 隧道(IP tunneling)是将一个IP报文封装在另一个IP报文的技术,Linux系统内核实现的

IP隧道技术主要有三种:IPIP、GRE、SIT。

Kubernetes CNI组件Calico:IPIP工作模式_kubernetes_03

当容器发出数据包就会到达宿主机上面,也是通过veth的设备对一端放在容器当中,另外一端放在宿主机上面,实现从容器当中的数据到达到宿主机上面的网络命名空间,宿主机上面的网络命名空间根据路由表信息转发

[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-6799fc88d8-drb2s 1/1 Running 3 78d 10.244.169.137 k8s-node2 <none> <none>
[root@k8s-master ~]# ip route
default via 192.168.179.2 dev ens32 proto static metric 100
10.244.36.64/26 via 192.168.179.103 dev tunl0 proto bird onlink
10.244.169.128/26 via 192.168.179.104 dev tunl0 proto bird onlink

10.244.169.128/26 via 192.168.179.104 dev tunl0 proto bird onlink
从tunl0这个虚拟的隧道设备进行出去

这个就是calio ipip隧道模式先创建的一个设备,这个设备和flannel的flannel.1这个设备非常类似,完成数据包的封装,将源容器的数据包封装好之后通过宿主机发出去,收到看到是tunl0封装,需要解开。

这里网桥用的是cali。

在这里可以看到像flannel一样使用cni网卡做网桥,tunl0通过数据包引到容器的veth这里。

[root@k8s-node1 ~]# ip route
default via 192.168.179.2 dev ens32 proto static metric 100
blackhole 10.244.36.64/26 proto bird
10.244.36.73 dev calib98307d9f10 scope link
10.244.36.74 dev califb92f94764a scope link
10.244.36.75 dev cali10e5fc0b45a scope link
10.244.36.76 dev calid4dc2dc6ef3 scope link

Kubernetes CNI组件Calico:IPIP工作模式_路由表_04

在这个节点上有多少个pod,就有多少个路由表,这样会导致有大量的路由表产生,会给网络造成复杂程度。

下面可以看到有vlan1 vlan2,主要是说明可以通过跨网段,实现两个节点通信,两个节点两个机房,不在一个局域网,主要宿主机的网络打通就行,因为数据包最后还是走宿主机,二层数据包还是走三层网络。

Kubernetes CNI组件Calico:IPIP工作模式_ico_05

Pod 1 访问 Pod 2 大致流程如下:



1. 数据包(原始数据包)从容器出去到达宿主机,宿主机根据路由表发送到tunl0设备(IP隧道设备)



2. Linux内核IPIP驱动将原始数据包封装在宿主机网络的IP包中(新的IP包目的地之是原IP包的下一跳地址,即192.168.31.63)



3. 数据包根据宿主机网络到达Node2



4. Node2收到数据包后,使用IPIP驱动进行解包,从中拿到原始数据包



5. 然后根据路由规则,根据路由规则将数据包转发给cali设备,从而到达容器2