概述

在裸kubernetes的集群中是没有LB的功能,该功能一般由云厂商提供。如果集群不是部署在云厂商的提供服务上,则使用到LB功能Service的状态始终都是​​pendding​​​状态。只能通过​​NodePort​​​方式和​​externalIPs​​方式将外部流量引入集群中。这在生产系统中进行部署带来很多的不便,在kuberntes的生态中给人一种二等公民的感觉。 


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_路由协议


 如上图所示,MetalLB监听Service的变化通过Speaker组件采用对应的模式将外部流量引流到kubernetes集群node节点的可达路径。而具体到pod中则是通过kuber-proxy依据转发模式(iptables或ipvs)将流量转发到pod中。MetaLB均衡负载负责从主机维度实现负载均衡,而pod副本间的负载是通过​​kube-proxy​​实现。MetalLB负责IP地址分配、依据设定的广播模式进行广播、节点选举、节点失效切换等功能。而引流的过程则通过ARP、NDP和BGP标准路由协议实现。

地址分配

MetalLB在kubernetes集群中启动后,MetalLB不会凭空产生出来IP。因此需要使用者配置IP地址池及相应地址池使用的广播方式。MetalLB会在Service的状态发生变化时进行响应的分配IP、回收IP,状态的变化包括Service的添加、删除、修改。

而IP的来源主要有两种方式,方式一是采用公网IP或局域网IP,方式二是虚拟IP。如果局域网拥有富裕的IP,或者从云厂商处能购买到IP段,可采用方式方式一。方式一广播则采用layer2模式的ARP和NDP方式实现。如果出于成本考虑,可使用和网络不冲突IP段的情况下可采用方式二。方式二需要支持BGP网络,或者路由器支持BGP路由协议。

广播模式

在IP池中的IP被分配后,需要需要将分配后的IP通知集群以外的网络访问IP可达。在MetalLB中使用标准的路由协议实现,分别是ARP、NDP或者BGP。其中ARP负责IPv4的广播,NDP负责IPv6的广播。MetalLB采用两种模式,分别是Layer2模式和BGP模式。

Layer2模式

在Layer2模式中,集群中确保主机与service建立关系,并通过标准的ARP或NDP协议实现IP可达。在Layer2模式中,通过集群中所有主机选举Leader作为对外暴露服务的主机。从网络上来看相当于这台主机上拥有多个IP。

在系统运行期间,如果出现节点丢失或故障,会自动发起leader节点选举,并将节点ip路由到新的节点上。因此在Layer2模式下,该功能类似于keepalived的功能。不过keepalived采用的是vrrp协议实现。节点的选举由memberlist工程提供。

从前面可以了解到,在Layer2模式下会将所有节点中进行选举一个leader节点作为暴露节点。从而导致整个集群对外暴露服务的带宽取决于Leader节点的带宽。有的操作系统会存在缓存问题最终导致leader节点发生故障时无法快速切换到新的leader节点主机上,会出现短暂的服务请求失败情况。

BGP模式

BGP模式是以集群中的主机与对等体进行共享路由信息,从而实现集群外部的服务能够访问到集群内部的服务。

BGP模式的流量的转发到主机的均衡负载取决于路由器来决定,一般常见的路由器都是基于数据包哈希值来平衡每个连接。如果一个连接中的TCP和UDP包会统一发到一个node节点上,不会发生由于数据到散发到不同节点上而引发的网络重排问题,而流量扩散的情况出现在不同的连接上,不会发生在同一个连接上。

在一些高性能的路由器中转发时会从数据包中提出去​​seed​​​数据作为关键值计算哈希,从而选择转发到不同的主机上。经典的模型做法一般是三元组和五元组。三元组使用​​(协议,源IP,目标IP )​​作为关键值来确保同一连接中的数据到达同一后端主机。五元组则在此技术长添加源端口和目标端口作为关键值,五元组较三元组能确保来自同一客户端的数据包到同一主机上。

BGP模式的优势在于可以使用外部的硬件路由器,而不是定制的负载能力。当然这也是BGP模式的最大的缺点。如果集群中的主机出现故障,这时又想快速断开所有服务是,路由器会无法快速做出响应。

基于BGP的无状态服务负载均衡采用数据包中固定字段进行哈希计算,将特定的数据包转发到特定的下一跳中。然而这也是BGP模式的一个弊端。如果BGP会话中断或其他原因导致后端主机集合发生变化时,数据包转发的哈希值会被重新计算,转发另外一台后端主机上。导致新接受数据包的主机出现数据错误问题。如果服务IP发生变化导致服务IP于节点映射发生变化,也会导致数据包丢失的显现发生。要解决以这些问题可依据自身的场景进行选择解决方法:

  • 路由器选择更稳定的​​ECMP​​​哈希算法(有时候成为​​弹性ECPM​​​或者​​弹性LAG​​),在后端主机发生变化时,这种算法会大大减少影响的连接数。
  • 将服务部署到固定的尽可能小、觉得可信任的主机池里。
  • 尽可能在流量低谷期间进行部署服务
  • 将每个服务拆分成为两个使用不一样IP的kubernetes的Service,并且通过DNS优雅地将用户的流量逐步迁移到新的服务上
  • 在客户端增加失败重试功能,特别是在移动端或者富客户端特别有用
  • 将服务放置到Ingress控制器后端。Ingress控制台采用MetalLB来接受流量,相当于在BGP和服务之间有一个状态服务层,因此无需担心服务的改变。只需要关注ingress控制器的部署。
  • 如果是一些使用很少的内部服务,偶尔连接重置的情况是可以接受的。

工作过程

MetalLB分为两部分组成,分别是Controller和Speaker。两者的分工如下所示:

  • Controller负责监听service变化,依据对应的IP池进行IP分配。
  • Speaker负责监听Service的变化,并依据具体的协议发起相应的广播或应答、节点的Leader选举。

资源名称\组件名称

Controler

Speaker

ConfigMap



Node

X


Service



Endpoint

X


如以上列表显示,列出Controller和Speaker两个组件监听的资源情况。 


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_路由协议_02


 如上图所示,Controller与Speaker之间没有直接的通讯,而彼此的写作主要依赖于Service的变化。节点之间可使用​​memberlist​​​开源项目进行选举,从而实现​​keepalived​​的效果。下面对SVC和Node发生变化时Controler和Speaker协作实现Load-Balance。

新增与更新Service

Controller过程


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_数据_03


如上图所示,Controller端接收到Service带有LoadBalance的事件处理过程,具体步骤如下所示:

  1. apiserver将更新添加事件发送给Controller;
  2. Controller接收到消息后深度复制一份出来;
  3. Controller在当前分配的IP列表中清理该Service的分配IP情况;
  4. Controller根据当前的IP池计算用于LoadBalance的IP;
  5. Controller将该IP添加到Service中,并将Service的信息更新给Apiserver;
  6. kube-proxy接收到更新信息后,在主机上进行相应的规则修改。

从以上的步骤可以看到Controller只是与Apiserver进行交互,最终两者的交互通过Apiserver对Service的监听实现协作。

Speaker过程


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_网络_04


 Speaker关于Service发生变化时的工作过程,具体步骤如下所示:

  1. kube-apiserver收到Service新增或更新后,将事件发送给Speaker;
  2. Speaker组件收到消息后,复制一份消息;
  3. Speaker根据Service中的Ingress字段的IP计算出协议;
  4. Speaker采用策略模式对Layer2和BGP实现对地址做出应答或同步路由规则给对等体;
  5. Speaker增加promethues指标项。

在新增或更新时,使用到BGP模式时会添加路由规则到列表中,并将其同步给所有的对等体。而在Layer2模式中则添加到应答列表中。

删除SVC操作

在Service发生变化时,也会发起Controller和Speaker也会发起相应的操作。

Controller过程


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_容器_05


 如上图所示,在删除Service时Controller和kube-proxy都会发起相应的工作,具体步骤如下所示:

  1. kube-apiserver收到Service的删除后形成事件发送给监听者;
  2. kube-proxy接收到消息后,对主机上的转发规则进行更新;
  3. Controller接收到消息后复制一份信息;
  4. Controller删除IP列表;
  5. Controller对IP进行回收。

Speaker过程


K8S MetalLB工作原理详解:地址分配、广播模式(Layer2模式、BGP模式)、工作過程_路由协议_06


 如图所示,Speaker在接收Service删除操作后,会相应的判断协议以及取消应答或发起路由规则同步,具体步骤如下所示:

  1. Apiserver将Service的删除事件发送给Speaker;
  2. Speaker接收到消息后复制一份;
  3. Speaker收到消息后将Service的获取广播对象;
  4. Speaker调用广播模式的对象发起删除操作。 在BGP模式下,针对Service的操作会将当前删除的Service进行从广播列表中移除,同时发起同步操作将路由规则同步到AS中。而在Layer2模式下,则直接从应答列表中移除。

节点状态变化

节点的状态变化对于Speaker来说至关重要。在节点出现故障无法提供服务是,在使用Layer2模式和BGP模式都需要做出相应的操作,将LB的IP及时切换到其他主机上,降低节点故障事件。MetalLB的节点间也会发起选举操作,这个选举实现采用memberlist实现。下面我们讨论节点的变化和节点发生的情况。

而在节点发生添加、删除、更新时,Speaker收到消息后,会调用协议列表进行轮训,逐个发起相关操作。在BGP模式下,会重新强制同步路由规则给AS。在Layer2模式下会强制发起重新加入member操作。

总结

MetalLB负责将流量引流到kubernetes集群的主机上,在其中提供两种模式,分别是Layer2模式和BGP模式。Layer2模式满足局域网内拥有富裕的IP。但是Layer2只能将所有外部流量引流到集群中的某台主机上,从而导致集群对外暴露的流量受限于单台主机的流量限制。BGP模式是一种较为理想的实现。BGP需要支持BGP路由协议的软路由或者硬件路由器设备,而无需定制的负载均衡器。在使用BGP协议时,需要路由器采用哈希等方式确保单个连接上的数据包转发到同一台主机上。由此也引发BGP模式的一个最大的缺点,在主机发生故障时无法快速切换到新的主机上,从而引发同一连接的不同数据包发送到不同主机上导致网络重排问题发生。解决该弊端的方法没有太理想的解决办法,只能通过尽量选择稳定的哈希算法、流量低谷更新服务、失败重试、服务在Ingress Controller后端等方法解决。

在高流量情况下的性能主要取决于网络的情况和集群主机的转发速度(ipvs或iptable的转发),MetalLB的能做的均衡只能是采用BGP,将不同的请求转发到不同的主机上来扩展带宽和提升性能。

从其代码和实践的过程中来看,MetalLB 0.9.5版本来看存在以下几点弊端:

  • 如果已经存在已经使用LoadBalance的Service不会在第一次启动时重新广播;
  • BGP路由规则同步是在使用LoadBalance的Service或者node节点发生变化时发起同步,其他时间不会发生同步,如果MetalLB或路由器出现故障时间过长,对已经创建的Service无法触发同步。