简介
在裸金属上(这里是相对云上环境来说,不是说无操作系统)部署的Kubernetes集群,是无法使用LoadBalancer类型的Service的,因为Kubernetes本身没有提供针对裸金属集群的负载均衡器。Kubernetes仅仅提供了针对部分IaaS平台(GCP, AWS, Azure……)的胶水代码,以使用这些平台的负载均衡器。
为了从外部访问集群,对于裸金属集群,只能使用NodePort服务或Ingress。前者的缺点是每个暴露的服务需要占用所有节点的某个端口,后者的缺点是仅仅能支持HTTP协议。
MetalLB是一个负载均衡器,专门解决裸金属K8S集群无法使用LoadBalancer类型服务的痛点,它使用标准化的路由协议。该项目目前处于Beta状态。MetalLB和kube-proxy的IPVS模式存在兼容性问题,在K8S 1.12.1上此问题已经解决。
1. 地址分配
在云环境中,当你请求一个负载均衡器时,云平台会自动分配一个负载均衡器的IP地址给你,应用程序通过此IP来访问经过负载均衡处理的服务。
使用MetalLB时,MetalLB自己负责IP地址的分配工作。你需要为MetalLB提供一个IP地址池供其分配(给K8S服务)。
2. IP宣告
MetalLB将IP分配给某个服务后,它需要对外“宣告”此IP地址,并让外部主机可以路由到此IP。
2.1 L2模式
在任何以太网环境均可使用该模式。当在第二层工作时,将由一台机器获得IP地址(即服务的所有权)。MetalLB使用标准的第地址发现协议(对于IPv4是ARP,对于IPv6是NDP)宣告IP地址,是其在本地网路中可达。从LAN的角度来看,仅仅是某台机器多配置了一个IP地址。
L2模式下,服务的入口流量全部经由单个节点,然后该节点的kube-proxy会把流量再转发给服务的Pods。也就是说,该模式下MetalLB并没有真正提供负载均衡器。尽管如此,MetalLB提供了故障转移功能,如果持有IP的节点出现故障,则默认10秒后即发生故障转移,IP被分配给其它健康的节点。
L2模式的缺点:
- 单点问题,服务的所有入口流量经由单点,其网络带宽可能成为瓶颈
- 需要ARP客户端的配合,当故障转移发生时,MetalLB会发送ARP包来宣告MAC地址和IP映射关系的变化。客户端必须能正确处理这些包,大部分现代操作系统能正确处理ARP包
2.2 BGP模式
当在第三层工作时,集群中所有机器都和你控制的最接近的路由器建立BGP会话,此会话让路由器能学习到如何转发针对K8S服务IP的数据报。
通过使用BGP,可以实现真正的跨多节点负载均衡(需要路由器支持multipath),还可以基于BGP的策略机制实现细粒度的流量控制。
具体的负载均衡行为和路由器有关,可保证的共同行为是:每个连接(TCP或UDP会话)的数据报总是路由到同一个节点上,这很重要,因为:
- 将单个连接的数据报路由给多个不同节点,会导致数据报的reordering,并大大影像性能
- K8S节点会在转发流量给Pod时可能导致连接失败,因为多个节点可能将同一连接的数据报发给不同Pod
BGP模式的缺点:
- 不能优雅处理故障转移,当持有服务的节点宕掉后,所有活动连接的客户端将收到Connection reset by peer
- BGP路由器对数据报的源IP、目的IP、协议类型进行简单的哈希,并依据哈希值决定发给哪个K8S节点。问题是K8S节点集是不稳定的,一旦(参与BGP)的节点宕掉,很大部分的活动连接都会因为rehash而坏掉
缓和措施:
- 将服务绑定到一部分固定的节点上,降低rehash的概率
- 在流量低的时段改变服务的部署
- 客户端添加透明重试逻辑,当发现连接TCP层错误时自动重试
安装
在裸金属集群上安装MetalLB后,LoadBalancer类型的服务即可使用。注意,除了自动分配,你也可以通过服务的spec.loadBalancerIP静态的指定IP地址。
1. 前提条件
要使用MetalLB,你的基础设施必须满足以下条件:
- 版本在1.9.0+的K8S集群
- 可以和MetalLB兼容的CNI网络
- 供MetalLB分配的IPv4地址范围
- 你可能需要一个或多个支持BGP的路由器
1.2 CNI要求
Flannel、Calico、Romana都支持。
如果你使用Calico的外部BGP Peering特性来同步路由,同时也想在MetalLB中使用BGP,则需要一些变通手段。这个问题是由BGP协议本身导致的 —— BGP协议只每对节点之间有一个会话,这意味着当Calico和BGP路由器建立会话后,MetalLB就无法创建会话了。
由于目前Calico没有暴露扩展点,MetalLB没有办法与之集成。
一个变通手段是,让Calico、MetalLB和不同的BGP路由进行配对,如下图:
1.2 L2模式
直接安装
执行下面的命令安装:
1 | kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml |
然后提供配置:
1 | cat <<EOF | kubectl apply -f - |
helm安装
1 | helm install --name metallb --namespace metallb-system stable/metallb |
通过Helm安装时,MetalLB读取的ConfigMap为metallb-config。