metalLB 官方网站
Repo:https://github.com/metallb/metallb
官网:https://metallb.universe.tf/installation
metalLB解决什么问题?
MetalLB 是一个用于裸机 Kubernetes 集群的负载均衡器实现,使用标准路由协议。
k8s 并没有为裸机集群实现负载均衡器,因此我们只有在以下 IaaS 平台(AliCloud, AWS, Azure)上才能使用 LoadBalancer 类型的 service。
因此裸机集群只能使用 NodePort 或者 externalIPs service 来对面暴露服务,然而这两种方式和 LoadBalancer service 相比都有很大的缺点。
前提条件
MetalLB 要求如下:
一个 Kubernetes 集群, Kubernetes 版本 1.13.0+, 没有网络负载均衡器功能;
可以与 MetalLB 共存的集群网络配置;
一些供 MetalLB 分发的 IPv4 地址;
当使用 BGP 操作模式时,您将需要一台或多台能够发布 BGP 的路由器;
使用 L2 操作模式时,节点之间必须允许 7946 端口(TCP 和 UDP,可配置其他端口)上的流量,这是 hashicorp/memberlist 的要求。
原理说明
在公有云的 Kubernetes 集群中, 你申请一个负载均衡器, 云平台会给你分配一个 IP 地址. 在裸金属集群中, MetalLB 来做地址分配。
MetalLB 不能凭空造 IP, 所以你需要提供供它使用的 IP 地址池. 在 Service 的创建和删除过程中, MetalLB 会对 Service 分配和回收 IP, 这些都是你配置的地址池中的 IP.
如何获取 MetalLB 的 IP 地址池取决于您的环境。如果您在托管设施中运行裸机集群,您的托管服务提供商可能会提供 IP 地址供出租。在这种情况下,将租用例如 /26 的 IP 空间(64 个地址),并将该范围提供给 MetalLB 以用于集群服务。
工作模式
MetalLB 是裸机 Kubernetes 集群的负载均衡器实现,使用标准路由协议,主要用于暴露 K8s 集群的服务到集群外部访问,MetalLB 可以让我们在 K8s 集群中创建服务类型为 LoadBalancer 的服务,并且无需依赖云厂商提供的LoadBalancer。
它具有两个共同提供此服务的工作负载:地址分配(address allocation)和外部公告(external announcement),对应在 K8s 中部署的 controller 和 speaker。
address allocation:地址分配这个功能比较好理解,首先我们需要给 MetalLB 分配一个 IP 段,接着它会根据K8s 的 Service 中的相关配置来给 LoadBalancer 的服务分配 IP,LoadBalancer 的 IP 可以手动指定,也可以让 MetalLB 自动分配。地址分配主要就是由作为 Deployment 部署的 controller 来实现,它负责监听集群中的 Service 状态并且分配 IP。
external announcement:外部公告的主要功能就是要把服务类型为 LoadBalancer 的服务的 EXTERNAL-IP 公布到网络中去,确保客户端能够正常访问到这个 IP。MetalLB 对此的实现方式主要有三种:ARP/NDP 和 BGP,其中ARP/NDP 分别对应 IPv4/IPv6 协议的 Layer2 模式,BGP 路由协议则是对应 BGP 模式。外部公告主要通过由 DaemonSet 部署的 speaker 来实现,它负责在网络中发布 ARP/NDP 报文或者是和 BGP 路由器建立连接并发布BGP 报文。
不管是 Layer2 模式还是 BGP 模式,两者都不使用 Linux 的网络栈,也就是说我们没办法使用诸如 ip 命令之类的操作准确的查看 VIP 所在的节点和相应的路由,相对应的是在每个节点上面都能看到一个 kube-ipvs0 网卡接口上面的IP。同时,两种模式都只是负责把 VIP 的请求引到对应的节点上面,之后的请求怎么到达 pod,按什么规则轮询等都是由kube-proxy 实现的。
Layer 2 中的 Speaker 工作负载是 DaemonSet 类型,在每台节点上都调度一个 Pod。首先,几个 Pod 会先进行选举,选举出 Leader,Leader 获取所有 LoadBalancer 类型的 Service,将已分配的 IP 地址绑定到当前主机的网卡上。也就是说,所有 LoadBalancer 类型的 Service 的 IP 同一时间都是绑定在同一台节点的网卡上。
如何部署
1. 环境说明
实验环境:
1、k8s version:v1.27.4
2、containerd:v1.6.22
部署 Layer2 模式需要把 K8s 集群中的 ipvs 配置打开 strictARP,开启之后 K8s 集群中的 kube-proxy 会停止响应 kube-ipvs0 网卡之外的其他网卡的 arp 请求,而由 MetalLB 接手处理。我们只需要在 K8s 集群中编辑kube-proxy 配置即可。
注意:当前集群为
v1.27.4
,默认已经是ipvs模式了。
kubectl edit configmap -n kube-system kube-proxy
#搜索ipvs
33 ipvs:
34 excludeCIDRs: null
35 minSyncPeriod: 0s
36 scheduler: ""
37 strictARP: true #新增
38 syncPeriod: 0s
39 tcpFinTimeout: 0s
40 tcpTimeout: 0s
41 udpTimeout: 0s
42 kind: KubeProxyConfiguration
43 metricsBindAddress: ""
44 mode: ipvs #默认ipvs
2. 使用 Layer2 模式,直接使用下面的命令一键安装即可
wget https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
kubectl apply -f metallb-native.yaml
3. 检查验证
kubectl get pods -n metallb-system -owide
对于 2 层模式的配置使用是最简单的,因为不需要什么特定的协议配置,只需要 IP 地址即可。L2模式不需要将 IP 与你的工作节点的网络接口绑定,它的工作方式是直接响应你本地网络上的 ARP 请求,把机器的 MAC地址给客户端。
4. 配置metalLB
要 Layer2 模式进行配置,需要创建一个 IPAddressPool 资源对象,用来指定用于分配的 IP 池,这部分一定要在 DHCP 服务器上做 IP 资源的保留,以防止IP被再次分配,造成异常;
比如我们这里创建如下所示的一个分配给 LB 的 IP 池对象:
cat ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ip-pool
namespace: metallb-system
spec:
addresses:
- 192.11.182.222-192.11.182.226 #分配给LB的IP池
注意:我们可以看出 MetalLB 的二层模式是非常简单的(另一种 BGP 模式需要路由器支持),只要保证 IP 地址池与集群是同一个网段即可。
接着,需要创建一个广播声明,可以关联上面的 IP 池对象,这样会使用关联的 IP 池地址。为了通告来自 IPAddressPool 的 IP,L2Advertisement 实例必须关联到 IPAddressPool。
cat advertise.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2adver
namespace: metallb-system
spec:
ipAddressPools:
- ip-pool
kubectl apply -f ip-pool.yaml
kubectl apply -f advertise.yaml
5. 部署测试
cat demoLB.yaml
apiVersion: v1
kind: Service
metadata:
name: demo-svc
spec:
selector:
app: demo
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer #此处必需为 LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-dep
spec:
replicas: 2
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: demo
image: nginx
kubectl apply -f demoLB.yaml
总结
MetalLB 的二层模式是非常简单的(另一种 BGP 模式需要路由器支持),只要保证 IP 地址池与集群是同一个网段即可。当然缺点也很明显:
所有的流量都会在同一个节点上,该节点的容易成为流量的瓶颈,当 VIP 所在节点宕机之后,需要较长时间进行故障转移(一般在 10s),这主要是因为 MetalLB 使用了memberlist 来进行选主;
当 VIP 所在节点宕机之后重新选主的时间要比传统的 keepalived 使用的 vrrp 协议要更长,难以定位 VIP 所在节点;
MetalLB 并没有提供一个简单直观的方式让我们查看到底哪一个节点是 VIP 所属节点,基本只能通过抓包或者查看 pod 日志来确定,当集群规模变大的时候这会变得非常的麻烦;
所以有条件的可以考虑使用 BGP 模式。