一、引言
在云原生架构中,Kubernetes 默认的负载均衡能力依赖于云厂商(如 AWS ELB、GCP LB),但在裸机或本地数据中心环境中,这一功能缺失导致 LoadBalancer
类型的 Service 始终处于 Pending
状态。此时,MetalLB 应运而生。本文将从技术原理、部署实践、企业案例出发,深入探讨 MetalLB 在裸机 Kubernetes 环境中的价值与应用。
二、什么是 MetalLB?
MetalLB 是一个专为裸机 Kubernetes 集群设计的开源负载均衡器,通过标准路由协议(如 ARP/NDP 或 BGP)实现外部流量的接入。其核心功能包括:
-
IP 地址分配:从预配置的地址池中动态分配 IP 给
LoadBalancer
类型的 Service。 -
IP 广播:通过 Layer2(ARP/NDP)或 BGP 协议,将分配的 IP 通告给外部网络,实现流量路由256。
与云厂商方案不同,MetalLB 无需依赖特定硬件或云服务,特别适用于本地数据中心、边缘计算等场景。
什么是Layer2和BGP协议?
Layer2 是数据链路层,ARP(地址解析协议)用于 IPv4 环境,将 IP 地址解析为 MAC 地址,以实现局域网内设备通信;NDP(邻居发现协议)用于 IPv6 环境,功能类似 ARP。BGP(边界网关协议)是网络层协议,用于在不同自治系统之间传递路由信息,实现跨网络的流量转发和路径选择。
用简单的话来说就是:
Layer2 就是网络中的 “邻居找邻居” 这件事。ARP 好比在 IPv4 这条街上,A 家要找 B 家,但不知道 B 家的门牌号(MAC 地址),就喊一嗓子问谁是 B 家,B 家听到后就告诉 A 家自己的门牌号。NDP 则是 IPv6 这条街上干类似活的。
而 BGP 就像是快递公司(自治系统)之间的 “指路牌”,告诉快递员(路由器)包裹该走哪条路、怎么转,才能把包裹从发件地送到收件地。
三、部署与测试
1.此次K8S环境使用的是K8S1.23.17版本,CNI用的是Calico,CRI为Docker2.修改kube-proxy的configMap
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
sed -e 's#mode: ""#mode: "ipvs"#' | \
kubectl apply -f - -n kube-system3.下载metallb
[root@master231 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml4.所有K8S节点导入镜像
因为网络的原因,我这里提前下载好了镜像,有VPN的朋友此步骤可以跳过。http://192.168.16.253/Resources/Kubernetes/Add-ons/metallb/v0.14.9/5.部署metallb
[root@master231 /manifests/metallb]# kubectl apply -f metallb-native.yaml
namespace/metallb-system created
.....
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration configured6.查看metallb的状态
[root@master231 /manifests/metallb]# kubectl get deploy,rs,svc,po -n metallb-system
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 54sNAME DESIRED CURRENT READY AGE
replicaset.apps/controller-686c7db689 1 1 1 54sNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metallb-webhook-service ClusterIP 10.200.59.227 <none> 443/TCP 54sNAME READY STATUS RESTARTS AGE
pod/controller-686c7db689-cqg9l 1/1 Running 0 54s
pod/speaker-dqlwr 1/1 Running 0 54s
pod/speaker-mxrzl 1/1 Running 0 53s
pod/speaker-zxzcp 1/1 Running 0 53s7.创建MetalLB地址池
[root@master231 /manifests/metallb]# cat metallb-ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:name: linux96namespace: metallb-system
spec:addresses:- 10.0.0.150-10.0.0.180---apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:name: xixinamespace: metallb-system
spec:ipAddressPools:- linux96
[root@master231 /manifests/metallb]# kubectl apply -f metallb-ip-pool.yaml
ipaddresspool.metallb.io/linux96 created
l2advertisement.metallb.io/xixi created8.验证LoadBalancer是否可用
[root@master231 /manifests/metallb]# cat deploy-ns-svc.yaml
apiVersion: v1
kind: Namespace
metadata:name: haha---apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-xiuxiannamespace: hahalabels:apps: xiuxian
spec:replicas: 5selector:matchLabels:version: v1template:metadata:labels:version: v1school: hahaclass: linux96spec:containers:- image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v1name: xiuxian---apiVersion: v1
kind: Service
metadata:name: svc-xiuxian-lbnamespace: haha
spec:type: LoadBalancer ports:- port: 80protocol: TCPtargetPort: 80nodePort: 30120selector:version: v1#
[root@master231 metallb]# kubectl apply -f deploy-ns-svc.yaml
[root@master231 /manifests/metallb]# kubectl get deploy,rs,po,svc -n haha
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deploy-xiuxian 5/5 5 5 53sNAME DESIRED CURRENT READY AGE
replicaset.apps/deploy-xiuxian-9ddcfd7db 5 5 5 53sNAME READY STATUS RESTARTS AGE
pod/deploy-xiuxian-9ddcfd7db-4dwd2 1/1 Running 0 53s
pod/deploy-xiuxian-9ddcfd7db-9x2db 1/1 Running 0 53s
pod/deploy-xiuxian-9ddcfd7db-bkfcc 1/1 Running 0 53s
pod/deploy-xiuxian-9ddcfd7db-mxq2x 1/1 Running 0 53s
pod/deploy-xiuxian-9ddcfd7db-zq88k 1/1 Running 0 53sNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/svc-xiuxian-lb LoadBalancer 10.200.244.45 10.0.0.150 80:30120/TCP 53s访问测试:基于NodePort端口访问
http://10.0.0.231:30120/
http://10.0.0.232:30120/
http://10.0.0.233:30120/基于LoadBalancer访问
10.0.0.150
四、MetalLB 工作流程
MetalLB 由两个核心组件协作:
-
Controller:监听 Service 事件,负责 IP 地址分配与回收。
-
Speaker:以 DaemonSet 形式运行,根据配置模式(Layer2/BGP)广播 IP2610。
新增 Service 流程:
-
Controller:检测到
LoadBalancer
类型 Service 后,从地址池分配 IP 并写入 Service 的status.loadBalancer.ingress
字段。 -
Speaker:根据模式通告 IP。Layer2 模式下,通过 ARP/NDP 响应;BGP 模式下,向路由器发布路由表10。
故障切换:Layer2 模式通过 memberlist
库实现 Leader 选举,故障时重新选举并更新 ARP 响应(耗时约数秒)25。
Layer2 模式 vs BGP 模式
Layer2 模式
-
原理:选举一个 Leader 节点,通过 ARP/NDP 将 Service IP 绑定到该节点的 MAC 地址。流量经 Leader 节点转发至 Pod。
-
优点:配置简单,无需 BGP 路由器支持。
-
缺点:
-
单点瓶颈:流量集中到 Leader 节点,带宽受限于单节点性能。
-
故障转移延迟:客户端 ARP 缓存可能导致短暂服务中断(约 5-10 秒)16。
-
-
适用场景:中小规模集群、测试环境或对高可用性要求较低的场景。
BGP 模式
-
原理:每个节点与 BGP 路由器建立对等会话,将 Service IP 作为等价多路径(ECMP)路由通告,实现流量负载均衡。
-
优点:
-
真正负载均衡:流量分散到多个节点。
-
扩展性强:支持大规模集群。
-
-
挑战:
-
路由器依赖:需支持 BGP 协议,且配置复杂。
-
哈希算法限制:路由器基于五元组哈希分配连接,节点故障时可能导致部分连接重置210。
-
-
优化建议:
-
使用支持弹性 ECMP 的路由器,减少节点变更对连接的影响。
-
将服务拆分至多个 IP,结合 DNS 逐步迁移流量10。
-
-
适用场景:生产环境、高吞吐量服务。
五、企业真实案例:某电商平台的 MetalLB 实践
背景
某电商平台在本地数据中心部署 Kubernetes 集群,初期使用 NodePort 暴露服务,面临端口管理复杂和单点故障问题。
方案选型
-
需求:高可用、支持 TCP/UDP、无缝集成现有网络。
-
选择 MetalLB Layer2 模式:因内部网络无 BGP 支持,且初期流量压力较小。
实施效果
-
服务可用性提升:通过 Leader 选举机制,故障切换时间从分钟级降至秒级。
-
简化运维:统一使用
LoadBalancer
类型服务,替代手动管理 NodePort。 -
瓶颈暴露:促销期间 Leader 节点带宽饱和,后续切换至 BGP 模式并引入高性能路由器8。
使用建议
-
IP 地址规划:
-
预留充足 IP 段,避免与现有网络冲突。
-
使用
IPAddressPool
的autoAssign
属性控制自动分配范围36。
-
-
网络兼容性验证:
-
确保节点间 7946 端口(memberlist)互通。
-
Calico 用户需禁用 BGP 或调整 Peer 配置36。
-
-
监控与告警:
-
监控
metallb_allocator_ips_total
指标,避免地址池耗尽。 -
集成 Prometheus 抓取 Speaker 和 Controller 指标10。
-
六、总结
MetalLB 填补了裸机 Kubernetes 集群的负载均衡能力空白,其 Layer2 和 BGP 模式各具优劣。企业应根据网络环境、规模及运维能力选择合适方案。对于追求高可用的生产场景,BGP 模式结合弹性路由策略是更优解;而中小规模场景下,Layer2 模式则能以更低成本实现快速部署。
延伸阅读:
-
MetalLB 官方文档
-
BGP 模式深度调优指南
注:本文基于 MetalLB v0.14.9 编写,部分配置可能随版本迭代变化。