17. LoadBalancer
LoadBalancer
MetalLB 是一个给裸机(on-prem)Kubernetes 集群提供外部 LoadBalancer 功能的开源项目。它让你在没有云厂商 LB 的环境下,仍能创建 type: LoadBalancer 的 Service 并把一个外部可访问的 IP(EXTERNAL-IP)暴露出去。
主要职责和两类工作负载
MetalLB 由两个互相配合但职责不同的组件提供服务:
- controller(地址分配)
- 职责:监听 Kubernetes 集群中的 Service(特别是 type: LoadBalancer),并从事先配置好的 IP 池(IPAddressPool)中分配/回收外部 IP。
- 表现:分配的 IP 会写入 Service.status.loadBalancer.ingress(也就是 EXTERNAL-IP)
- 验证:看 controller pod 状态、查看 Service 的 EXTERNAL-IP 即可。
- speaker(外部公告 / 通告)
- 职责:把 controller 分配好的 IP “通告” 到集群外的网络,使外部客户端知道把流量发到哪个 MAC/路由。speaker 的实现方式取决于模式(Layer2 用 ARP/NDP,BGP 则用路由通告)。speaker 通常作为 DaemonSet 在每台节点上运行。
- 验证:检查 speaker 日志(是否在 ARP/NDP 或 BGP 上做了通告),或在网络中抓包确认有 ARP/BGP 报文。
一个“虚拟 IP”必须通过 ARP、路由表或隧道告诉网络由谁负责,否则没人知道流量往哪送。 这个就是通告的必要性。
两种主要工作模式(Speaker)
- Layer2(L2)模式 — 用 ARP(IPv4)/NDP(IPv6)
-
原理(通俗):当外部主机想访问某个 VIP(EXTERNAL-IP)时,会先发 ARP 请求问“谁是这个 IP?哪个 MAC?”。在 L2 模式下,MetalLB 的某一台节点(通过 speaker 的 leader 选举)会以自己的 MAC 地址回应这个 ARP,把流量引到该节点。该节点再交由 kube-proxy(例如 ipvs)把流量转发到后端 Pod。
-
要点/限制:
-
同一个 VIP 在任意时刻只有一个节点在回应 ARP(leader 节点),因此入口流量会集中到该节点,可能成为瓶颈。
-
当那个节点宕机时,需要通过 speaker 的 leader 重新选举并恢复通告,故障转移时间通常会比基于 VRRP 的方案慢一些(一般为几秒到十几秒,取决于 memberlist 的选举/检测时长)。
-
L2 配置简单,只需一段与集群同网段的 IP 池,并创建 IPAddressPool + L2Advertisement。
-
- BGP 模式
-
原理(通俗):MetalLB 的 speaker 与网络中的路由器建立 BGP 邻居,然后把每个分配到的 VIP 当作一条路由通告给上游路由器(通常是 /32),由路由器负责把流量路由到相应节点。
-
优点:
-
路由器能同时把流量分散或做更灵活的路由控制(不像 L2 那样把流量集中到单节点),可获得更好的可扩展性与更快的故障切换(由路由器决定)。
-
支持更复杂的 BGP 属性与 FRR 后端(如 BFD、IPv6、MP-BGP 等)。
-
-
要求:你的网络/路由器必须支持 BGP,并允许与集群节点建立邻居关系。
地址并发与 CRD
MetalLB 使用 CRD 管理地址与通告配置(新版 MetalLB 使用 IPAddressPool、L2Advertisement、BGPAdvertisement、BGPPeer 等):
-
IPAddressPool: 定义一段或多段可被分配给 LoadBalancer 的 IP(例如 172.18.0.10-172.18.0.30)。
-
L2Advertisement / BGPAdvertisement: 定义应如何对 IPAddressPool 中的 IP 做通告(例如 L2 模式下必须把 IP 池与一个 L2Advertisement 关联才能通告该池的 IP)。
# 查看地址池
ubuntu@ubuntu:~$ kubectl get ipaddresspool -n metallb-system
NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
default-pool true false ["192.168.236.200-192.168.236.210"]
# 查看 speaker
ubuntu@ubuntu:~$ kubectl get l2advertisement -n metallb-system
NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
default
安装
## 安装LB
ubuntu@ubuntu:~$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.3/config/manifests/metallb-native.yaml
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
configmap/metallb-excludel2 created
secret/webhook-server-cert created
service/webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
ubuntu@ubuntu:~$ kubectl get pods -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-6d9b64d49f-x5fs5 1/1 Running 0 27s
speaker-98mqz 0/1 Running 0 27s
speaker-dgfmd 0/1 Running 0 27s
speaker-nvss7 0/1 Running 0 27s
ubuntu@ubuntu:~$
## 给分配IP 192.168.236.101/24
ubuntu@ubuntu:~$ cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 192.168.236.200-192.168.236.210
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec: {}
EOF
ipaddresspool.metallb.io/default-pool created
l2advertisement.metallb.io/default unchanged

浙公网安备 33010602011771号