metallb 支持的三种格式
支持的三种格式:
addresses:
- 192.168.1.200-192.168.1.250 # IP 范围(start-end)
- 10.0.0.0/24 # CIDR 前缀
- 172.16.1.100/32 # 单个 IP
# 同一个 pool 可以混合使用,你的配置写法完全正确。
❯ apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.200-192.168.1.250
❯ metalLB 维护的 ip 的掩码都是/32 么? 另外谁维护的 metalLB 的 LB 的公网 ip 的配置?不是纯控制器模式么?如何维护的?
问题一:MetalLB 维护的 IP 掩码都是 /32 吗?
结论:默认是 /32(IPv6 是 /128),但 BGP 模式可配置。
代码证据 — internal/config/config.go:806-807:
AggregationLength: 32, // IPv4 默认 /32 AggregationLengthV6: 128, // IPv6 默认 /128
在 BGP 模式中,通告路由的前缀长度由 AggregationLength 控制 — speaker/bgp_controller.go:329:
m := net.CIDRMask(adCfg.AggregationLength, 32) // 默认 /32
ad := &bgp.Advertisement{
Prefix: &net.IPNet{
IP: lbIP.Mask(m),
Mask: m,
},
}
可通过 BGPAdvertisement CRD 改为更短前缀(如 /24),实现路由聚合。
L2 模式没有掩码概念,它只是对单个 IP 响应 ARP/NDP,本质上就是逐 IP(/32)工作的。
问题二:谁维护公网 IP?MetalLB 不是纯控制面吗?
结论:MetalLB 确实是纯控制面。它从不把 EIP 配置到任何网卡上。
整个代码库中 没有 ip addr add、netlink.AddrAdd 或任何将 IP 绑定到接口的操作。
MetalLB "维护" EIP 的方式完全是欺骗网络层:
┌──────┬──────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────────────┐
│ 模式 │ MetalLB 做了什么 │ MetalLB 没做什么 │
├──────┼──────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────┤
│ L2 │ 在选举节点上用用户态程序直接回复 ARP/NDP 请求,告诉询问者"这个 EIP 的 MAC 是我" (arp.go:112) │ 不把 EIP 加到任何接口,不改路由表 │
├──────┼──────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────┤
│ BGP │ 通过 FRR/native BGP 向路由器通告 EIP/32 的路由 │ 不把 EIP 加到任何接口,不改路由表 │
└──────┴──────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────┘
那流量到了节点后谁处理?
MetalLB 的工作到此为止
↓
外部 → [ARP/BGP让EIP可达] → 包到达节点 eth0 → kube-proxy iptables/IPVS → DNAT → Pod
↑
kube-proxy 的工作
kube-proxy 监听到 Service 的 status.loadBalancer.ingress 被 MetalLB Controller 写入后,自动创建对应的 DNAT 规则(KUBE-SERVICES → KUBE-SVC-xxx → KUBE-SEP-xxx)。
所以完整的协作链是:
- MetalLB Controller:分配 EIP,写入 svc.status.loadBalancer.ingress
- kube-proxy:看到 ingress IP,创建 iptables DNAT 规则(EIP:port → PodIP:targetPort)
- MetalLB Speaker:让 EIP 在网络上可达(ARP 欺骗 或 BGP 路由通告)
- 内核 netfilter:执行 kube-proxy 写好的 DNAT 规则,转发流量到 Pod
MetalLB 自始至终不碰数据面,EIP 也从不作为真实地址存在于任何接口上。
metalLB 既有控制器也有 daemonset speaker
纠正:"纯控制面"这个说法不准确
准确的表述是:MetalLB 不操作数据面转发规则(iptables/IPVS),但 Speaker 确实参与了网络面(ARP/BGP)。
MetalLB 的两个组件
┌────────────┬───────────────────────┬────────────────────────────────────────┬──────────────────────┐
│ 组件 │ 部署形态 │ 做了什么 │ 属于哪一面 │
├────────────┼───────────────────────┼────────────────────────────────────────┼──────────────────────┤
│ Controller │ Deployment(单副本) │ 分配 EIP,写入 svc.status │ 控制面 │
├────────────┼───────────────────────┼────────────────────────────────────────┼──────────────────────┤
│ Speaker │ DaemonSet(每个节点) │ L2: 用户态 ARP/NDP 应答;BGP: 路由通告 │ 网络面(让 IP 可达) │
└────────────┴───────────────────────┴────────────────────────────────────────┴──────────────────────┘
Speaker 确实以 DaemonSet 运行在每个节点上,它做的事情是网络可达性层面的:
- L2 模式:在用户态直接构造 ARP Reply 包(arp.go:112),告诉交换机 "EIP 的 MAC 是我"
- BGP 模式:通过 FRR 或 native BGP 向路由器通告 EIP/32 路由
我前面说的"纯控制面"想表达的是
MetalLB 不写任何 iptables/IPVS/nftables 规则,不参与实际的包转发(DNAT/SNAT/负载均衡)。这部分完全由 kube-proxy 负责。
Speaker 的边界: 让包能"到达"节点(ARP/BGP) ← MetalLB 做到这里 kube-proxy 的边界: 让包从节点"转发"到 Pod(DNAT) ← MetalLB 不碰这里
所以更准确的说法是:MetalLB 不参与数据面转发,但 Speaker DaemonSet 参与了网络面的 IP 可达性宣告。
前面的表述有误,感谢纠正。