L2&BGP 模式说明¶
MetalLB L2 模式¶
L2 模式下,Metallb
将会通过 ARP(for ipv4)、NDP(for ipv6)宣告 LoadBalancerIP
的地址。 在 Metallb
< v0.13.2
之前,只能通过 configMap
来配置 Metallb
。 在 v0.13.2
之后,通过 CRD 资源的方式配置 Metallb
,另外 configMap
的方式已被弃用。
在 Layer2
模式下,当创建服务时,Metallb
(speaker
组件)会为这个服务选举出集群中某个节点,作为这个服务对外暴露的主机。 当对 Service 的 externalIP
发出请求时,此节点会代替这个 externalIP
回复 arp
请求。 所以对 Service 发出的请求,会首先到达集群中这个节点,然后再经过这个节点上的 kube-proxy
组件,最后将流量导向这个 service 某个具体的端点 (endpoint)。
服务选举节点的逻辑主要有三点:
- 首先过滤掉未 ready 的节点以及 endpoint 未 ready 所在的节点
- 如果该服务的 endpoint 分布在同一个节点,那么筛选此节点作为该服务 IP 的
arp
响应者 - 如果该服务的 endpoint 分布在不同的节点,那么通过
sha256
计算节点 + # + externalIP
后,按照字典顺序取第一个
这样,MetalLB 就会为每个 Service 选择一个节点作为暴露的主机。 metallb
会将这单个 Service 的流量,全部导向某个节点,所以这个节点可能会成为限制性能的瓶颈。 Service 的带宽限制也会取决于单个节点的带宽,这也是使用 ARP 或 NDP 最主要的限制。
此外,当此节点发生故障时,MetalLB 需要为服务重新选择一个新的节点。 然后 Metallb
会给客户端发送一个"免费"的 arp
,告知客户端需要更新他们的 Mac 地址缓存。 在客户端更新缓存前,流量仍会转发到故障节点。因此从某种程度来看:故障转移的时间,依赖于客户端更新 Mac 地址缓存的速度。
使用¶
-
创建 IP 池
-
addresses
:IP 地址列表,每一个列表成员可以是一个 CIDR,可以是一个地址范围(如 192.168.9.1 - 192.168.9.5),也可以是不同ipFamily
、Metallb
会从其中分配 IP 给LoadBalancer
服务 -
autoAssign
:是否自动分配 IP 地址,默认为 true。在某些情况下(IP 地址不足或公有 IP),不希望池中的 IP 被轻易地分配,可设置为 false。 可以通过在 service 中设置 annotations:metallb.universe.tf/address-pool: pool-name
。或者在spec.LoadBalancerIP
字段设置 IP(注意这种方式已被k8s标记为遗弃)。 -
avoidBuggyIPs
:是否避免使用池中以.0
或.255
地址,默认为 false。 -
配置
LoadBalancerIP
通告规则 (L2)通过
L2Advertisement
绑定地址池,这样告诉Metallb
这些地址应该由ARP
或NDP
通告出去。 -
ipAddressPools
:可选,通过 name 筛选地址池,如ipAddressPools
和ipAddressPoolSelectors
同时未指定,则作用于所有地址池。 -
ipAddressPoolSelectors
:可选,通过 labels 筛选地址池,如ipAddressPools
和ipAddressPoolSelectors
同时未指定,则作用于所有地址池。 -
nodeSelectors
:可选,用于筛选哪些节点作为loadBalancerIP
的下一跳,默认所有节点。 -
创建
LoadBalancer Service
apiVersion: v1 kind: Service metadata: name: metallb1-cluster labels: name: metallb #annotations: #metallb.universe.tf/address-pool: lan spec: type: LoadBalancer allocateLoadBalancerNodePorts: false ports: - port: 18081 targetPort: 8080 protocol: TCP selector: app: metallb-cluster
只需要指定
spec.type=LoadBalancer
,这样Metallb
就会自然接管此Service
的生命周期。Note
如果想让 Service 从指定的地址池中分配地址,通过
annotations: metallb.universe.tf/address-pool: <pool-name>
指定。或者通过service.spec.loadBalancerIP
字段指定 IP(需要保证存在于一个池中,不推荐这种方式)。 如果存在多种负载均衡器,可通过service.spec.loadBalancerClass
字段指定。在部署Metallb
时,可通过--lb-class
flag 进行配置。
负载均衡性¶
-
当
Service.spec.externalTrafficPolicy=cluster
这种模式下,具有良好的负载均衡性,但流量可能经历多跳,这会隐藏客户端源 IP。
______________________________________________________________________________ | -> kube-proxy(SNAT) -> pod A | | | | client -> loadBalancerIP:port -> | -> node A(Leader) -> | | | | | -> kube-proxy(SNAT) -> node B -> kube-proxy -> pod B | ------------------------------------------------------------------------------
-
当
Service.spec.externalTrafficPolicy=local
这种模式下,会保留客户端源IP,但负载均衡性较差,流量会一直到某一个后端Pod。
__________________________________________________________________________________________ | -> kube-proxy -> pod A (后端Pod在本节点) | | | | client -> loadBalancerIP:port -> | -> node A(Leader) -> | | | | | -> kube-proxy -> node B -> kube-proxy -> pod B (后端Pod在不同节点) | ------------------------------------------------------------------------——————————————————
MetalLB BGP 模式(L3)¶
Layer2
模式局限在一个二层网络中,流向 Service 的流量都会先转发到某一个特定的节点,这并不算真正意义上的负载均衡。 BGP 模式不局限于一个二层网络,集群中每个节点都会跟 BGP Router 建立 BGP 会话,宣告 Service 的 ExternalIP
的下一跳为集群节点本身。 这样外部流量就可以通过 BGP Router 接入到集群内部,BGP Router 每次接收到目的是 LoadBalancer
IP 地址的新流量时,它都会创建一个到节点的新连接。 但选择哪一个节点,每个路由器厂商都有一个特定的算法来实现。所以从这个角度来看,这具有良好的负载均衡性。
使用¶
-
创建 IP 池
-
配置
LoadBalancerIP
通告规则 (L3)Note
BGP 模式需要硬件支持运行 BGP 协议。若无,可使用如
frr
、bird
等软件代替。推荐使用
frr
进行安装:frr
配置BGP
:router bgp 7675 # bgp as number bgp router-id 172.16.1.1 # route-id 常常是接口IP no bgp ebgp-requires-policy # 关闭 ebpf filter !!! neighbor 172.16.1.11 remote-as 7776 # 配置 ebgp -> neighbor 1, 172.16.1.11 为集群一节点 neighbor 172.16.1.11 description master1 # description neighbor 172.16.2.21 remote-as 7776 # 节点 2 neighbor 172.16.2.21 description woker1
Metallb
配置: -
配置
BGPAdvertisement
此 CRD 主要用于指定需要通过 BGP 宣告的地址池,同 L2 模式,可通过池名称或者
labelSelector
筛选。同时可配置BGP一些属性:apiVersion: metallb.io/v1beta1 kind: BGPAdvertisement metadata: name: local namespace: metallb-system spec: ipAddressPools: - bgp-pool aggregationLength: 32
aggregationLength
:路由后缀聚合长度,默认为 32,意味这 BGP 通告的路由的掩码为 32,值调小可聚合路由条数aggregationLengthV6
:同上,用于 ipv6,默认为 128ipAddressPools
:[]string,选择需要 BGP 通告的地址池ipAddressPoolSelectors
:通过 label 筛选地址池nodeSelectors
:通过 node label 筛选loadBalancerIP
的下一跳节点,默认为全部节点peers
:[]string,BGPPeer
对象的名称,用于声明此BGPAdvertisement
作用于哪些 BGP 会话communities
:参考 BGP communities,可以直接配置,也可以指定 communities CRD 的名称
-
配置 BGP Peer
BGP Peer 用于配置 BGP 会话的配置,包括对端 BGP AS 及 IP 等。
apiVersion: metallb.io/v1beta2 kind: BGPPeer metadata: name: test namespace: metallb-system spec: myASN: 7776 peerASN: 7675 peerAddress: 172.16.1.1 routerID: 172.16.1.11
myASN
:本端 ASN,范围为1-64511(public AS)
、64512-65535(private AS)
peerASN
:对端 ASN,范围同上。如果二者相等,则为iBGP
;否则为eBGP
peerAddress
:对端路由器 IP 地址sourceAddress
:指定本段建立 BGP 会话的地址,默认从本节点网卡自动选择nodeSelectors
:根据 node label 指定哪些节点需要跟 BGP Router 建立会话
-
创建
LoadBalancer
类型的 Service
验证¶
在 BGP Router 上可以看到通过 BGP 学习到的路由:
$ vtysh
Hello, this is FRRouting (version 8.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
router# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
f - OpenFabric,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
t - trapped, o - offload failure
K>* 0.0.0.0/0 [0/100] via 10.0.2.2, eth0, src 10.0.2.15, 03:52:17
C>* 10.0.2.0/24 [0/100] is directly connected, eth0, 03:52:17
K>* 10.0.2.2/32 [0/100] is directly connected, eth0, 03:52:17
B>* 10.254.254.1/32 [20/0] via 172.16.1.11, eth1, weight 1, 03:32:16
* via 172.16.2.21, eth2, weight 1, 03:32:16
C>* 172.16.1.0/24 is directly connected, eth1, 03:52:17
可以看到通往 LoadBalancerIP
的下一跳分别是集群节点 1 和节点 2,在 BGP Router 执行连通性测试:
root@router:~# curl 10.254.254.1:18081
{"pod_name":"metallb-demo","pod_ip":"172.20.166.20","host_name":"worker1","client_ip":"172.20.161.0"}
FRR Mode
¶
目前 Metallb
BGP 模式有两种 Backend 实现:Native BGP
和 FRR BGP
。
FRR BGP
目前是实验阶段,对比 Native BGP
,FRR BGP
主要有以下几个优点:
BFD
协议支持(提高故障反应能力,缩短故障时间)- 支持
IPV6 BGP
- 支持
ECMP