当前位置: 首页 > 科技观察

如何在BGP模式下完美整合Calico和MetalLB

时间:2023-03-22 00:17:25 科技观察

最近,我公司扩大了业务,在机房开了一个新的区域。折腾了一阵CalicoBGP,为了让整个过程更简单明了,我决定把这个过程记录下来。无论是对当下的总结,还是对未来规划的重新审视,都是值得的。大家都知道,Yunnative下的网络架构堪称百花齐放的Kubernetes,各有所长,这无形中导致了网络始终是广大K8S爱好者走向高端的少数几座高山之一。级管理。通常,在公有云上使用厂商提供的CNI组件,你可能感觉不到它的复杂性,但是一旦你想在IDC中搭建自己的集群,就会面临Kubernetes网络架构选择的问题。Calico作为Kubernetes上使用最广泛的KubernetesCNI之一,自然拥有众多的追随者。本文是对自建机房BGP组网的总结。在CNI选型上,云原生的CNI组件非常多,比如老牌的Flannel、Calico、WeaveNet、Kube-Router,以及近两年兴起的Antrea、Kube-OVN、Cilium。他们在各自的场景中都有自己的优势。Beforechoosing,wecanmakeasimplefunctionalcomparisonofthem:FlannelCalicoCiliumWeaveNetAntreaKube-OVNdeploymentmodeDaemonSetDaemonSetDaemonSetDaemonSetDaemonSetDaemonSetpacketencapsulationandroutingVxLANIPinIP,BGP,eBPFVxLAN,eBPFVxLANVxlanVlan/Geneve/BGPNetworkPolicyNoYesYesYesYesYesYesStorageEngineEtcdEtcdEtcdNoEtcdEtcdTransmissionEncryptionYesYesYesYesYesNoOperationalModelCommunityTigeraCommunityWeaveWorksVMwareLingqueyunExplanation:Transmission加密主要通过支持WireGuard或IPSec来评估另外,关于CNI性能,我们也可以通过一份2020年的CNI性能测试报告《Benchmark results of Kubernetes network plugins (CNI) over 10Gbit/s network》来选择。以上性能测试的原始数据:https://docs.google.com/spreadsheets/d/12dQqSGI0ZcmuEy48nA0P_bPl7Yp17fNg7De47CYWzaM/edit?ouid=118246426051561359914&usp=sheets_home&ths=true使用Calico作为云网络方案。这里简单说明一下选择Calico的原因:支持BGP广播,Calico通过BGP协议广播路由信息,架构非常简单。meshtomesh或者RR模式在kubernetes中很容易实现,后期也很容易实现容器的跨集群网络通信。Calico配置简单,配置在Kubernetes中通过CRD集中管理。通过操作CR资源,我们可以直接实现集群中容器的联网和配置的实时变化。丰富的功能和兼容性,考虑在集群中,需要兼容三方应用,比如配置多租户网络,固定容器IP,网络策略等功能,或者兼容Istio,MetalLB,和纤毛。Calico的表现非常好。高性能,Calico的数据平面采用HostGW方式,由于是纯三方数据通信,实际使用中性能和主机资源占用不会太差,至少可以排在第一梯队。结合我司机室的新区,我购买的H3CS9系列交换机支持在接入层交换机侧直接启用路由反射器。所以最后我们选择了Calico,使用BGPRR模型作为Kubernetes的CNI组件,这是水到渠成的事情。关于MetalLB在谈MetalLB之前,我们先回顾一下应用在Kubernetes中是如何部署的,以及它的下游服务是如何访问的。集群内请求通常有以下几种情况:直接通过KubernetesServices访问应用。集群外请求:通过NodePort将流量以nat方式转发到宿主机上的容器。优点是配置简单,可以提供简单的负载均衡功能。缺点也很明显,下游应用只能通过主机地址+端口来寻址。通过Ingress-Nginx用于应用层的七层转发。优点是路由规则灵活,流量只经过一层代理直接到达容器,效率更高。缺点是ingress-nginx本身的服务还需要NodePort或者HostNetwork的支持。可以看出,在引入外部负载均衡器之前,应用部署在kubernetes集群中,对于南北流量的地址寻址还是不太友好。可能有同学说了,我在公有云上使用Kubernetes的时候,设置Service类型为LoadBalancer,集群可以自动为我的应用创建一个带负载均衡器地址的IP,用于对外服务调用,那我们自己部署是不是有什么类似的东西可以为Kubernetes集群实现这个目标吗?当然有!MetalLB是为裸机服务器下的Kubernetes集群而生的负载均衡器项目。事实上,当然,MetalLB并不是唯一的。开源界还有PureLB、OpenELB等其他负载均衡产品。不过本文的目的是使用BGP协议实现负载均衡,所以重点放在MetelLB上。简单来说,MetalLB由两个组件组成,用于操作Service资源变化的Controller和IPAM。扬声器用于外部广播地址和BGP连接。它支持两种流模式模式即:layer2和BGP。Layer2模式也称为ARP/NDP模式。在这种模式下,Kubenretes集群中运行Speaker的机器通过leader选举获得Service的LoadBalancerIP的所有权,并使用ARP协议广播自己的IP和MAC,使得这些IP在本地网络上可以访问。使用二层的方式对现网没有太多要求,甚至不需要路由器的支持。但是,缺点也很明显。LoadBalancerIP所在的Node节点承载了所有的流量,会造成一定的网络瓶颈。另外,Layer2模式我们可以简单理解为类似于Keepalived的原理,唯一不同的是Layer2的leader选举不使用VRRP组播进行通信。BGP模式MabelLB在BGP模式下,集群中所有运行Speaker的主机都会与上层交换机建立BGP连接,广播其LoadBalancer的IP地址。优点是真正实现了网络负载均衡,缺点是配置比较复杂,上层路由器需要支持BGP。MetalLBwithCalico通过上面的介绍,你可能发现了一个问题:在BGP模式场景下,Calico和MetalLB都需要运行一个DaemonSetbgpclient来与宿主机上的router建立bgppeer,在Calico中是Bird,MetalLB中的扬声器。这导致它们在使用中出现一些问题。BGP只允许每个节点一个会话,如果使用Calico并建立BGP路由器会话,MetalLB无法建立自己的会话。因为这个BGP会话会被路由器视为冲突而拒绝连接。其实我们传统的fabric网络在使用上述方案的时候也会遇到这个问题。MetalLB社区也给出了3种方案来解决:BGP和Tor切换连接本方案即MetalLB放弃在Node节点上部署Speaker服务,主机上BGP路由的广播交给CalicoBird进行处理。这也是Calico社区建议的方法。BGP与spine交换机的连接,使得MetalLBSpeaker的BGPPeer绕过Tor路由,直达上层核心路由器。虽然解决了BGP连接问题,但带来了额外的配置复杂度和BGP连接扩展性的损失,这在大型数据中心是不被认可的!启用VRF——虚拟路由转发如果你的网络硬件支持VRF(虚拟路由转发),你可以通过虚拟化为CalicoBird和MetalLBSpeaker创建单独的路由表,建立BGP连接。那么,两个VRF之间的路由理论上是可行的,但是笔者的数据中心没有支持VRF功能的路由器,受限于不同网络设备厂商的实现方式不同导致的操作差异。控制。因此,具体实现方式需要各用户自行决定。具体操作上面讲了很多关于Calico和MetalLB的使用。在本节中,我们将通过简单的部署和配置来完成前面的内容。网络的一些基本信息:规划CIDR使用关联服务10.52.1.0/24Kubernetes主机物理网络,也是Kubernetes通过IBGP连接的承载网络,Calico10.59.0.0/16Kubernetes容器默认IP地址池Calico10.96.0.0/12KubenretesService内部地址池,即ClusterIP区Kubernetes10.60.0.0/21KubenretesService负载均衡器地址池,即LoadBalancerIP区Calico,BGP信息BGP信息MetalLBIDC中心AS域65001BGPpeer10.52.1.253,10.52。1.254Calico部分下载并部署CalicoManifest文件,将文件内容中的PODCIDR修改为自己环境中的配置curlhttps://projectcalico.docs.tigera.io/manifests/calico.yaml-O----containers:-image:harbor.cloudminds.com/kubegems/calico-node:v3.22.1name:calico-nodeenv:-name:CALICO_IPV4POOL_CIDRvalue:10.59.0.0/16配置BGPPeering,可以选择GlobalBGPPeerandPer-Node根据规模机房同行。它们的区别在于GlobalBGPPeer的连接拓扑是星型的,所有节点都在一个AS域中。Per-NodePeer可以使用主机标签进行灵活访问。这里因为我们的服务器规模较小(<50台),所以可以直接采用全局BGP连接方式。apiVersion:projectcalico.org/v3kind:BGPPeermetadata:名称:tor-router-253spec:peerIP:10.52.1.253asNumber:65001---apiVersion:projectcalico.org/v3kind:BGPPeermetadata:名称:tor-router-254spec:peerIP:10.52.1.254asNumber:65001考虑到BGP连接的冗余性,实际中可以创建两个BGPPeer来防止路由器单点故障。如果需要按照机架划分AS域,可以使用Per-NodePeer模式,通过nodeSelector实现个性化连接配置。apiVersion:projectcalico.org/v3kind:BGPPeermetadata:name:rack1-torspec:peerIP:192.20.30.40asNumber:64567nodeSelector:rack=='rack-1'禁用CalicoNodeToNodeMeshcalicoctl补丁bgpconfigurationdefault-p'{"spec":{"nodeToNodeMeshEnabled":false}}'禁用ipipMode和vxlanModeapiVersion:projectcalico.org/v3kind:IPPoolmetadata:name:default-ipv4-ippoolspec:allowedUses:-WorkloadblockSize:26cidr:10.59.0.0/16ipipMode:NevernatOutgoing:truenodeSelector:all()vxlanMode:Never此时我们使用calicoctl查看BGP状态。如果STATE为up,说明集群内主机的BGP连接正常。如果MetalLB的Kube-Proxy使用IPVS,则必须启用严格的ARP学习设置。kubectleditconfigmap-nkube-systemkube-proxy----apiVersion:kubeproxy.config.k8s.io/v1alpha1kind:KubeProxyConfigurationmode:"ipvs"ipvs:strictARP:true如果多个用户主机发送大量ARP包到设备同时发送伪造的ARP报文,或者攻击者向设备发送伪造的ARP报文,可能会出现以下问题:处理ARP报文会消耗大量的CPU资源。设备学习到大量无效ARP表项,耗尽ARP表项资源。导致设备无法学习到合法用户的ARP报文中的ARP表项,导致用户通信中断。设备收到伪造的ARP报文后,错误地修改了ARP表项。这会阻止用户相互通信。为避免上述问题,启用strictARP后,设备只对发送的ARP请求报文学习ARP回复报文的ARP表项。这样,设备就可以抵御大部分的ARP攻击。下载并安装MetalLBkubectlapply-fhttps://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yamlkubectlapply-fhttps://raw.githubusercontent.com/metallb/metallb/v0。12.1/manifests/metallb.yaml注意,由于我们不需要MetalLB的Speaker服务,所以MetalLBController运行成功后可以删除speaker服务。kubectldeletedaemonsetspeaker-nmetallb-system在MetalLB中配置需要广播的BGP地址范围,也就是后面KubernetesService中LoadBalancer的地址。apiVersion:v1kind:ConfigMapmetadata:namespace:metallb-systemname:configdata:config:|address-pools:-name:defaultprotocol:bgpaddresses:-10.60.0.0/21Calico广播Kubernetes服务地址(包括MetalLB地址)得益于BGP使用Calico,很容易将Kubernetes的集中服务IP地址发布到像PodIP这样的Intranet。真正的负载平衡是通过使用ECMP(等价多路径路由)实现的。通常,Kubenretes中Service中的地址涉及3种类型,分别是ClusterIP、ExternalIP和LoadBalancerIP。考虑到我们只需要通过LoadBalancerIP暴露有限的服务。(虽然直接发布ClusterIP很酷,但在某些网络受限的场景中是不可接受的)。所以Calico的BGP只需要配置如下。apiVersion:projectcalico.org/v3kind:BGPConfigurationmetadata:name:defaultspec:logSeverityScreen:InfonodeToNodeMeshEnabled:falseasNumber:65001serviceLoadBalancerIPs:-cidr:10.60.8.0/21如果我们需要从广播中排除Kubernetes控制节点,那么只需要在控制平面的主机上添加如下标签:kubectllabelnodecontrol-plane-01node.kubernetes.io/exclude-from-external-load-balancers=trueRouter原则上在路由器上启用BGP协议是以上应该在所有操作中首先启动的作业。不过由于每个读者环境中支持BGP的交换机厂商不尽相同,所以我将这部分移到最后进行说明。我不是网络专家。这里我只简单介绍一下我们CalicoBGP网络的架构。读者在规划自己的BGP网络时可以与网络工程师合作。最后,当交换机上的路由反射器和BGP邻居创建完成后,Calico的Bird服务就可以与反射器建立对等连接。此时连接状态如下。路由表信息如下。此时容器的子网路由既指定了下一跳的主机地址,也指定了LoadBalancerCIRD公布的下一跳地址。关于EMCP等价多路径路由ECMP(Equal-CostMulti-Pathrouting)实现了等价多路径负载均衡和链路备份的目的。多用于三层负载均衡,用于解决“负载均衡服务器”的单点和扩缩容问题。既然我们内部有一个BGP网络,当然也可以在路由器上启用此功能。启用该功能后,我们可以在路由表中看到有目的地址到LoadBalancerCIRD网段的路由,下一跳地址可以是多台CalicoNode主机。但是,在决定启用ECMP之前,您需要了解它背后仍然面临一些应用程序限制。当我们使用BGP进行三层负载均衡时,当一台主机发生故障时,交换机上通过连接三元组/五元组作为hashkey进行负载均衡的数据包会重新发送给新的主机。目的地址,当数据包到达新的主机时,会直接丢弃,导致连接断开。这就是应用层反映出来的现象,就是“Connectionresetbypeer”。当然,我们可以使用一些其他的方法来避免和减少上述现象的影响,例如:调整更稳定的等价多路径路由ECMP(Equal-CostMulti-Pathrouting)算法。后端集群变化时受影响较小的连接数。A。逐包负载均衡可以提高ECMP的带宽利用率,使等价多路径路由共享更均匀,但存在数据包乱序的问题。需要保证接收流量的设备或终端支持封包乱序封包功能,实际使用场景很少。b.逐流负载均衡可以保证报文的顺序,保证同一数据流的帧在同一下一跳路由上转发,而不同的数据流在不同的下一跳路由上转发。在部署和调度服务时,尽量选择固定在较小范围或较稳定的主机组。上层应用需要支持网络连接断开重试逻辑,在MeltalLB和应用之间增加一层流量控制器(如ingress-nginx)来保持连接状态的一致性。这样只有当ingress-nginx的规模发生变化时,才会出现上述问题。小结本文主要介绍在传统自建数据中心使用Calico和MetalLB构建内部BGP网络。并利用它为Kubernetes提供与Pod-Pod、Node-Pod和Node-Loadbalancer网络通信的能力。

最新推荐
猜你喜欢