17. LoadBalancer

LoadBalancer

MetalLB 是一个给裸机(on-prem)Kubernetes 集群提供外部 LoadBalancer 功能的开源项目。它让你在没有云厂商 LB 的环境下,仍能创建 type: LoadBalancer 的 Service 并把一个外部可访问的 IP(EXTERNAL-IP)暴露出去。

主要职责和两类工作负载

MetalLB 由两个互相配合但职责不同的组件提供服务:

  1. controller(地址分配)
  • 职责:监听 Kubernetes 集群中的 Service(特别是 type: LoadBalancer),并从事先配置好的 IP 池(IPAddressPool)中分配/回收外部 IP。
  • 表现:分配的 IP 会写入 Service.status.loadBalancer.ingress(也就是 EXTERNAL-IP)
  • 验证:看 controller pod 状态、查看 Service 的 EXTERNAL-IP 即可。
  1. speaker(外部公告 / 通告)
  • 职责:把 controller 分配好的 IP “通告” 到集群外的网络,使外部客户端知道把流量发到哪个 MAC/路由。speaker 的实现方式取决于模式(Layer2 用 ARP/NDP,BGP 则用路由通告)。speaker 通常作为 DaemonSet 在每台节点上运行。
  • 验证:检查 speaker 日志(是否在 ARP/NDP 或 BGP 上做了通告),或在网络中抓包确认有 ARP/BGP 报文。

一个“虚拟 IP”必须通过 ARP、路由表或隧道告诉网络由谁负责,否则没人知道流量往哪送。 这个就是通告的必要性。

两种主要工作模式(Speaker)

  1. 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。

  1. 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

posted @ 2025-11-21 10:45  beamsoflight  阅读(20)  评论(0)    收藏  举报