Calico网络插件介绍

Calico 的全称为 Project Calico

Calico 是三层虚拟网络解决方案(BGP)。每一个节点都是一个 vRouter。每个节点上的 pod 都被当作该路由器后端的一个终端设备为其分配一个 IP 地址。而各节点上的 vRouter 都需要通过 BGP 协议学习生成路由规则,从而实现各节点上的 pod 之间互联互通。

BGP通信模型

BGP 通信模型有两种:

  • BGP peer(小规模网络使用):点对点BGP,如果一个网络中有10个BGP,那是1:9的通信模型,这样将形成 n*(n-1) 个通信网络。所以在次模型下如果网络规模较大BGP路由学习报文将会占据很大的网络带宽,因而在大规模网络下需要使用另外一种通信模型
  • BGP Reflector(大规模网络使用):反射器模型,所有节点都将自己所有拥有的路由信息汇总给 Reflector,由 Reflector 用 1:n-1 的方式向外进行反射,所以称之为 BGP 反射器。

小规模网络中 BGP peer 不存在单点问题,BGP peer 宕机会有其他的进行替代。

大规模网络中 BGP Reflector 需要做冗余。

BGP 模型要求所有节点在同一个二层网络中。不一定所有的底层网络都支持 BGP,如在阿里云上购买了虚拟机自己部署 k8s 网络时,阿里云底层的网络不支持 BGP 协议。

为了确保公有云上也能使用 calico,calico 还提供了另外两种解决方案:

  • Overlay Network:
    • IPIP:用IP报文来封装IP报文,因此其开销更小。
    • VXLAN:类似于Flannel的VXLAN启用DirectRouting的网络模型,Calico也支持混合使用路由和叠加网络模型。如果节点在同一子网内使用BGP,如果跨子网则使用VxLan。

Calico的架构


Calico网络插件介绍



在整个 k8s 集群上有多个节点,每个节点存在多个 pod,这些 Pod 与 Flannel 插件中 host-gw 模型的 Pod 有一个不同之处在于 flannel 的 pod 在连如网络时使用的是将网卡一半在 pod 一半接入网桥实现的,而 calico 在接入网络时并非使用一对虚拟网卡来接入,而是直接接入了宿主机的内核。其需要借助内核中的 IptablesRoutes 表来完成其中的部分功能。

整个 Calico 有以下几个组件组成:

  1. 每个节点都需要运行以下组件:
    • BGP客户端(默认启用):需要运行于每个节点,负责将Felix生成的路由信息载入内核并通告到整个网络中;
    • BGP Reflector:专用反射各BGP客户端发来路由信息;将  N –> N-1  转为  N –> 1 的模型
    • Felix:需要运行于各节点之上的守护进程,主要负责完成接口管理、路由规划、acl规划(也就是网络策略,其需要借助iptables来实现)、状态报告。
    • BIRD:是vRouter的关键实现,整个BGP的路由表是由BIRD生成的,而路由规划是Felix完成的。而BIRD自身可以扮演两种角色,默认之启用了一种:
  2. 在节点之外需要运行以下组件:
    • etcd:Calico也和Flannel一样需要依靠etcd来存一些自身的状态数据,其也可以像Flannel一样将API Server当为自身的存储后端。大规模集群中建议额外部署etcd专用于Calico集群,以免和k8s性能上冲突。
    • Route Reflector:路由反射器
    • Calico编排系统插件:Calico自己不仅仅支持给k8s提供虚拟网络,它也支持openshift、openstack。所以Calico是一个通用的虚拟网络,不仅仅能适用到k8s上。要让calico能适用于k8s,需要一个calico的编排系统插件让etcd和calico插件之间能都双向转换通信。

Calico部署组件

Calico 部署到 K8S 集群上时,需要用到两个组件:

  • calico-node:类似于 Flanneld 需要运行于每个节点之上。calico-node 中封装了 Felix 和 BIRD。
  • calico-kube-controller:运行于k8s集群上的中央控制系统。由它来负责 Calico 和整个 kubernetes 的协同,也包括其他核心功能的实现。


Calico网络插件介绍




Calico部署

Calico 有两种部署方式,一是让 calico/node 独立运行于 Kubernetes 集群之外,但 calico/kube-controllers 依然需要以 Pod 资源运行中集群之上;另一种是以 CNI 插件方式配置 Calico 完全托管运行于 Kubernetes 集群之上,类似于我们前面曾经部署托管 Flannel 网络插件的方式。对于后一种方式,Calico 提供了在线的部署清单,它分别为 50 节点及以下规模和 50 节点以上规模的 Kubernetes 集群使用 Kubernetes API 作为 Datastore 提供了不同的配置清单,也为使用独立的 etcd 集群提供了专用配置清单。但这3种类型的配置清单中,Calico 默认启用的是基于 IPIP 隧道的叠加网络,因而它会在所有流量上使用 IPIP 隧道而不是 BGP 路由。以下配置定义在部署清单中 DaemonSet/calico-node 资源的 Pod 模板中的 calico-node 容器之上。

官方部署文档:

https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises

需要注意:

calico 的部署以50个节点为界限,分为3种部署方式

  • [Install Calico with Kubernetes API datastore, 50 nodes or less] https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico-with-kubernetes-api-datastore-50-nodes-or-less
  • [Install Calico with Kubernetes API datastore, more than 50 nodes] https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico-with-kubernetes-api-datastore-more-than-50-nodes
  • [Install Calico with etcd datastore] https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico-with-etcd-datastore

此处以50个节点方式来部署calico:

  1. 下载 calico 的资源清单
curl https://docs.projectcalico.org/manifests/calico.yaml -O
  1. 应用配置清单

在应用配置清单前需要注意如果 Pod 的 CIDR 为 192.168.0.0/16,那么此配置清单可以直接 kubectl apply 进行部署,如果非此网段则需要对 calico.yaml 进行修改。

此前部署 k8s 集群时,部署了 flannel 并且使用的 Pod 的 CIDR10.244.0.0/16,现在则需要将其配置清单内的 CALICO_IPV4POOL_CIDR 进行修改,以确保其和 Pod 网段相同。

root@k8s-master01:~# vim calico.yaml
# 在 IPv4 类型的地址池上启用的 IPIP 及其类型,支持3种可用值 Always(全局流量)、Cross-SubNet(跨子网流量) 和 Never3 种可用值
        - name: CALICO_IPV4POOL_IPIP
          value: "Always"
# 是否在 IPV4 地址池上启用 VXLAN 隧道协议,取值及意义与 Flannel 的 VXLAN 后端相同;但在全局流量启用 VXLAN 时将完全不再需要 BGP 网络,建议将相关的组件禁用
        - name: CALICO_IPV4POOL_VXLAN
          value: "Never"


# 需要注意的是,Calico 分配的地址池需要同 Kubernetes 集群的 Pod 网络的定义保持一致。Pod 网络通常由 kubeadm init 初始化集群时使用 --pod-network-cidr 选项指定的网络,而 Calico 在其默认的配置清单中默认使用 192.168.0.0/16 作为 Pod 网络,因而部署 Kubernetes 集群时应该规划好要使用的网络地址,并设定此二者相匹配。对于曾经使用了 flannel 的默认的 10.244.0.0/16 网络的环境而言,我们也可以选择修改资源清单中的定义,从而将其修改为其他网络地址。以下配置片断取自 Calico 的部署清单,它定义在 DaemonSet/calico-node 资源的 Pod 模板中的 calico-node 容器之上。

# IPV4 地址池的定义,其值需要与 kube-controller-manager的 “--cluster-network” 选项的值保持一致,以下环境变量默认处于注释状态
    - name: CALICO_IPV4POOL_CIDR
      value: "10.244.0.0/16"
      
# Calico 默认以 26 位子网掩码切分地址池并将各子网配置给集群中的节点,若需要使用其他的掩码长度,则需要定义如下环境变量
    - name: CALICO_IPV4POOL_BLOCK_SIZE
      value: "24"
          
# Calico 默认并不会从 Node.Spec.PodCIDR 中分配地址,但可通过将如下变量设置为 “true” 并结合 host-local 这一 IPAM 插件以强制从 PodCIDR 中分配地址
    - name: USE_POD_CIDR
      value: "true"
 
# 在地址分配方面,Calico 在 JSON 格式的 CNI 插件配置文件中使用专有的 calico-ipam 插件,该插件并不会使用 Node.Spec.PodCIDR 中定义的子网作为节点本地用于为 Pod 分配地址的地址池,而是根据 Calico 插件为各节点的配置的地址池进行地址分配。若期望为节点真正使用地址池吻合 PodCIDR 的定义,则需要在部署清单中 DaemonSet/calico-node 资源的 Pod 模板中的 calico-node 容器之上将 USE_POD_CIDR 环境变量的值设置为 true,并修改 ConfigMap/calico-config 资源中 cni_network_config 键中的 plugins.ipam.type 的值为 host-local,且使用 podCIDR 为子网,具体配置如下所示。

  "ipam": {
      "type""host-local",
      "subnet""usePodCidr"
  },
  1. 资源清单修改完毕后可以进行部署,但若之前使用了 flannel 插件则需要将其删除。
root@k8s-master01:~# kubectl apply -f calico.yaml

# 需要注意若原先安装了 flannel 插件,部署完 calico 后需要重启节点,否则会有 flannel 的规则残留。

IPIP模型

calico 默认使用的是 IPIP 模型

# 查看路由信息
root@k8s-master01:~# ip route list
default via 172.16.11.1 dev eth0 proto static
blackhole 10.244.0.0/24 proto bird         # blackhole 表示当前节点。
10.244.0.2 dev calib670545fd4e scope link
10.244.0.3 dev calibd15e6c1979 scope link
10.244.0.4 dev cali5411bb555f9 scope link  # 此处可以看到 pod 的数据流出是直接到达内核的
10.244.0.5 dev caliddaf626788e scope link
10.244.0.6 dev cali0db5c029d8e scope link
10.244.1.0/24 via 172.16.11.81 dev tunl0 proto bird onlink
10.244.2.0/24 via 172.16.11.82 dev tunl0 proto bird onlink
10.244.3.0/24 via 172.16.11.83 dev tunl0 proto bird onlink
172.16.11.0/24 dev eth0 proto kernel scope link src 172.16.11.71
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown

# 可以看到出现 tunl0 接口,现在报文发送时会发送给 tunl0 接口

查看 calico 的地址池

root@k8s-master01:~# kubectl get ippools -o yaml
apiVersion: v1
items:
- apiVersion: crd.projectcalico.org/v1
  kind: IPPool
  metadata:
    annotations:
      projectcalico.org/metadata: '{"uid":"fecd039d-88d1-4d69-ba56-3d24173d4652","creationTimestamp":"2024-05-05T08:02:43Z"}'
    creationTimestamp: "2024-05-05T08:02:44Z"
    generation: 1
    name: default-ipv4-ippool
    resourceVersion: "4394285"
    uid: 76b6e014-3b0b-4625-9fd7-9f6fb2d3a284
  spec:
    blockSize: 24       # 地址块大小为24位
    cidr: 10.244.0.0/16    # pod网段为 10.244.0.0/16
    ipipMode: Always     # ipipMode 为 Always
    natOutgoing: true
    nodeSelector: all()
    vxlanMode: Never          # vxlanMode 为 Never
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

# 结合 ipipMode 和 vxlanMode 可以看出当前模型为 ipip

验证ipip工作逻辑

在 k8s-node01 上进行抓包

root@k8s-node01:~# tcpdump -i eth0 -nn ip host k8s-node01 and host k8s-node03
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:33:55.805615 IP 172.16.11.81 > 172.16.11.83: IP 10.244.1.16.49490 > 10.244.3.16.10016: Flags [P.], seq 1133911456:1133911482, ack 3769557439, win 85, options [nop,nop,TS val 3535292140 ecr 2812652948], length 26 (ipip-proto-4)
02:33:55.806152 IP 172.16.11.83 > 172.16.11.81: IP 10.244.3.16.10016 > 10.244.1.16.49490: Flags [P.], seq 1:27, ack 26, win 84, options [nop,nop,TS val 2812654948 ecr 3535292140], length 26 (ipip-proto-4)
02:33:55.806235 IP 172.16.11.81 > 172.16.11.83: IP 10.244.1.16.49490 > 10.244.3.16.10016: Flags [.], ack 27, win 85, options [nop,nop,TS val 3535292140 ecr 2812654948], length 0 (ipip-proto-4)
02:33:55.825457 IP 172.16.11.81 > 172.16.11.83: IP 10.244.1.16.33862 > 10.244.3.16.10001: Flags [P.], seq 1753095916:1753095942, ack 3391595475, win 3524, options [nop,nop,TS val 3535292159 ecr 2812652968], length 26 (ipip-proto-4)
02:33:55.825894 IP 172.16.11.83 > 172.16.11.81: IP 10.244.3.16.10001 > 10.244.1.16.33862: Flags [P.], seq 1:27, ack 26, win 4091, options [nop,nop,TS val 2812654968 ecr 3535292159], length 26 (ipip-proto-4)
02:33:55.825975 IP 172.16.11.81 > 172.16.11.83: IP 10.244.1.16.33862 > 10.244.3.16.10001: Flags [.], ack 27, win 3524, options [nop,nop,TS val 3535292160 ecr 2812654968], length 0 (ipip-proto-4)
02:33:57.513265 IP 172.16.11.81 > 172.16.11.83: IP 10.244.1.10.45486 > 10.244.3.16.10015: Flags [S], seq 494496574, win 43200, options [mss 1440,sackOK,TS val 2265387489 ecr 0,nop,wscale 9], length 0 (ipip-proto-4)
02:33:57.513602 IP 172.16.11.83 > 172.16.11.81: IP 10.244.3.16.10015 > 10.244.1.10.45486: Flags [S.], seq 2229381908, ack 494496575, win 42840, options [mss 1440,sackOK,TS val 185191869 ecr 2265387489,nop,wscale 9], length 0 (ipip-proto-4)


# 从以上抓包结果中可以看出 ipip 在通信时,分为外部 ip 和内部 ip 2层。
# ipip-proto-4 表示此报文为 ipip 报文。

IPIP模型总结

Pod 接入网络的方式与 Flannel 不同,它不使用网桥接入,而是直接放入宿主机内核并直接关联到宿主机上。因此它需要路由条目来支撑,每一个 Pod 都有个单独的路由条目,指明自己的报文要通过对端的接口(calixxxx)出来后到达宿主机上,而接口都是内核管理的,所有接口已经在宿主机内核中(tunl0),接下来由内核决定如何路由。IPIP 模式下其要经过 tunl0 接口出去。


原文始发于微信公众号(TechOps之窗):Calico网络插件介绍

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/292009.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!