裸机 Kubernetes 负载均衡全景:从 MetalLB、Service 到 Ingress,再到云厂商实现原理
在自建 Kubernetes 集群中,Service 的
EXTERNAL-IP一直卡在<pending>?
你想用一个 IP 暴露多个 Web 应用,却只能开一堆NodePort?
节点一挂,服务就断,IP 还变了?
别再硬扛了!本文系统梳理 MetalLB、Service 与 Ingress 的定位、协作机制与最佳实践,并对比 云厂商 LoadBalancer 的底层原理,手把手教你构建媲美公有云的高可用入口体系。
一、为什么裸机 Kubernetes 需要 MetalLB?
在 AWS、阿里云等公有云上,创建一个 type: LoadBalancer 的 Service,系统会自动分配公网 IP。
但在自建裸机、私有云或边缘集群中,Kubernetes 原生并不提供 LoadBalancer 的实现——该类型 Service 的 EXTERNAL-IP 将长期处于 <pending> 状态。
为解决这一问题,社区诞生了 MetalLB:一个专为裸金属环境设计的负载均衡器实现,它使 LoadBalancer Service 在无云环境中也能获得稳定的外部 IP,从而与云上体验对齐。
Kubernetes 集群使用 MetalLB 作为 LoadBalancer 实现,填补了裸机 Kubernetes 集群的负载均衡能力空白。
然而,MetalLB 并非万能钥匙。它与 Kubernetes 原生的 Service、Ingress 组件协同工作,各自承担不同职责。本文将深入剖析三者的关系、原理与适用场景,并延伸至云厂商的实现机制,助你构建完整的流量入口架构。
二、核心组件定位:各司其职,分层协作
2.1 Kubernetes Service:集群网络的基石
Service 是 Kubernetes 最基础的网络抽象,为一组 Pod 提供稳定的访问端点。它有三种主要类型:
- ClusterIP(默认):仅集群内部可访问,由
kube-proxy通过 iptables/IPVS 实现负载均衡; - NodePort:在每个节点开放固定端口(如
30080),外部通过NodeIP:30080访问; - LoadBalancer:在云环境自动创建云负载均衡器;在裸机环境需 MetalLB 补充。
关键点:Service 是所有外部访问的起点和终点,Ingress 和 MetalLB 都围绕它工作。
2.2 Ingress:七层 HTTP 路由规则
Ingress 本身只是一个 API 资源(YAML 配置),用于定义基于 Host 或 Path 的 HTTP 路由规则。但要使其生效,必须部署 Ingress Controller(如 Nginx Ingress、Traefik)。
- Ingress Controller 本质是一个 反向代理,监听
Ingress资源变化,动态生成路由配置; - 它将外部 HTTP 请求根据规则转发到不同的
ClusterIPService; - 支持 TLS 终止、重写、速率限制等高级功能。
常见误区:
- Ingress 不能直接指向 Pod,必须通过 Service;
- Ingress 原生仅支持 HTTP(S),无法处理 TCP/UDP。
2.3 MetalLB:裸机的 LoadBalancer 实现者
MetalLB 的唯一使命是:让 Service 的 LoadBalancer 类型在裸机环境可用。
- 它监听所有
type: LoadBalancer的 Service; - 从用户预定义的 IP 池中分配一个 External IP;
- 通过 ARP(IPv4)或 NDP(IPv6)(Layer 2 模式)或 BGP(BGP 模式)将该 IP 宣告到物理网络;
- 使外部客户端能像在云上一样,通过一个固定 IP 访问服务。
本质:MetalLB 是 Kubernetes 原生
LoadBalancer语义在无云环境的补全,而非替代品。
三、深度解析:高可用原理、IP 稳定性与网络层级
3.1 为什么 External IP 在节点故障后不会变化?
这是 Kubernetes Service 语义 + MetalLB 实现机制 共同作用的结果:
IP 与 Service 绑定,而非节点:
MetalLB controller 在首次分配 IP 时,会将该 IP 写入 Service 的status.loadBalancer.ingress[0].ip字段,并持久化到 etcd。只要 Service 存在,该 IP 就被视为“已占用”。故障后仅重绑定,不重分配:
当原 Leader 节点故障,MetalLB speaker 检测到后,会在其他健康节点上重新宣告同一个 IP,而非释放后重新分配。因此,从 Kubernetes API 和客户端视角看,External IP 完全不变。
好处:DNS、防火墙规则、监控告警等外部依赖无需变更,保障服务连续性。
3.2 高可用切换原理:10 秒恢复是如何实现的?
在 Layer 2 模式下,MetalLB 通过以下步骤实现高可用:
- Leader 选举:所有 speaker 节点通过 memberlist(gossip 协议) 维持心跳;
- 故障检测:若节点失联(默认
probeInterval=1s,failureThreshold=3→ 超时 ≈10s),其余节点判定其离线; - 重新选举:存活节点选举新 Leader;
- IP 重宣告:新 Leader 通过 Gratuitous ARP(免费 ARP)向局域网广播:“IP
10.10.20.200现由我的 MAC 提供”; - 客户端更新:交换机和客户端收到 GARP 后,更新 ARP 表,后续流量直达新节点。
可调优:通过调整
probeInterval、probeTimeout、failureThreshold,可将恢复时间缩短至 3~5 秒。
BGP 模式:若网络设备支持,BGP 会话中断后路由秒级撤回,切换 < 1 秒,且支持多节点负载(ECMP)。
3.3 网络生效层级:流量到底走哪一层?
| 组件 | 网络层级 | 协议 | 作用 |
|---|---|---|---|
| MetalLB | L2(数据链路层) | ARP / NDP(IPv4/IPv6) | 在局域网内宣告 External IP 的可达性 |
| kube-proxy | L3/L4(网络/传输层) | iptables / IPVS | 将到达节点的流量转发到后端 Pod(无论 Pod 在哪个节点) |
| Ingress Controller | L7(应用层) | HTTP/HTTPS | 解析 Host/Path,反向代理到不同 Service |
完整流量路径示例(Layer 2 模式):
客户端 → [10.10.20.200:80] ↓(L2:ARP 解析 → 流量到 Leader 节点) Leader 节点(如 node-01) ↓(L4:kube-proxy iptables 转发) Pod(可能在 node-02)注意:MetalLB 不处理 Pod 调度,后端 Pod 的高可用由 Kubernetes 原生机制(Deployment、HPA、亲和性等)保障。
3.4 MetalLB 的 IP 真的“绑定”在网卡上吗?
不是! 这是一个常见误解。
- MetalLB 不会执行
ip addr add,因此ip addr show看不到该 IP; - 它通过 原始套接字(raw socket) 在用户态监听 ARP 请求,并直接发送 ARP Reply;
- IP 的“存在”仅体现在 网络宣告层面,而非操作系统接口配置。
验证方法:
# 抓包看 ARP 响应是否来自目标接口 tcpdump -i eth0 arp host 10.10.20.200 # 应能看到 MetalLB Speaker 发送的 ARP Reply
四、协作模式:如何组合使用?
4.1 场景一:暴露非 HTTP 服务(如数据库、游戏服务器)
客户端 → [External IP:6379]
↓
MetalLB(分配 IP)
↓
Service(LoadBalancer, targetPort=6379)
↓
Pod(Redis)
- 组件:MetalLB + Service(LoadBalancer)
- 原因:Ingress 仅支持 HTTP,无法处理 TCP/UDP 流量。
4.2 场景二:暴露多个 Web 应用(推荐生产架构)
客户端 → http://app1.example.com
↓
[External IP] ← MetalLB 分配
↓
Ingress Controller(其 Service 为 LoadBalancer)
↓(根据 Host 路由)
Service A → Pod A
Service B → Pod B
- 组件:MetalLB + Ingress Controller + Ingress
- 优势:
- 一个 IP 服务多个应用;
- 支持域名路由、TLS、路径重写;
- MetalLB 提供 IP 高可用,Ingress 提供灵活应用层路由。
4.3 场景三:简单测试,无需固定 IP
- 直接使用
Service(NodePort),通过NodeIP:NodePort访问; - 无需 MetalLB 或 Ingress,适合开发验证。
五、真实场景配置与避坑指南
5.1 虚拟机 + 防火墙 DNAT 环境
若虚拟机无公网 IP,公网访问通过防火墙 DNAT(如 203.0.113.10:80 → 10.10.20.200:80):
- MetalLB 应配置内网 IP 池(如
10.10.20.200-210); - 防火墙 DNAT 目标设为 MetalLB 分配的内网 VIP;
- 如何避开 DHCP 冲突?
- 登录路由器/DHCP 服务器,查 DHCP 池(如
10.10.20.100-199); - 将 MetalLB IP 设在 DHCP 范围之外(如
200-210); - (推荐)在 DHCP 中将
.200-.210标记为“保留”,彻底避免冲突。
- 登录路由器/DHCP 服务器,查 DHCP 池(如
好处:节点故障时,MetalLB 自动迁移 IP,防火墙规则无需修改!
5.2 多网卡虚拟机:指定绑定接口
MetalLB 默认绑定到 默认路由对应的接口。
若需指定接口(如业务流量走 eth1),可在 ConfigMap 中配置(MetalLB v0.13+):
interfaces:
- eth1
验证默认路由:
ip route show default
六、对比云厂商:LoadBalancer 是如何自动分配公网 IP 的?
在 AWS、阿里云等环境中,LoadBalancer Service 能自动获得公网 IP,其原理如下:
- Cloud Controller Manager(CCM) 监听 Service 创建事件;
- 调用云平台 API 创建负载均衡器(如 AWS NLB、阿里云 SLB);
- 云平台 自动分配公网 IP(或使用用户指定的 EIP);
- 将 IP 写回 Service 的
status.loadBalancer.ingress字段; - 负载均衡器将流量转发到集群节点(NodePort)或直接到 Pod。
本质区别:
- 云厂商:托管式、网络层集成,IP 由云基础设施全局管理;
- MetalLB:用户态模拟,依赖 ARP/BGP 在本地网络宣告 IP。
因此,在云上无需 MetalLB;而在裸机环境,MetalLB 是实现 LoadBalancer 语义的事实标准。
七、最佳实践方案速查表
| 需求 | 推荐方案 |
|---|---|
| 暴露 TCP/UDP 服务(如 Redis) | MetalLB + Service(LoadBalancer) |
| 单个 Web 应用 | MetalLB + Service(直接暴露 80 端口) |
| 多个 Web 应用(生产环境) | MetalLB + Ingress Controller + Ingress |
| 极致高可用(网络支持 BGP) | MetalLB BGP 模式 + ECMP |
| 云环境(AWS/阿里云) | 原生 Service(LoadBalancer) + Ingress(无需 MetalLB) |
黄金法则:
- Service 是基石;
- Ingress 是 HTTP 路由规则;
- MetalLB 是裸机 LoadBalancer 的实现。
三者分层协作,共同构建云原生流量入口体系。
八、结语
理解 MetalLB、Service 与 Ingress 的定位与协作关系,是构建可靠 Kubernetes 入口架构的关键。通过本文的深度原理剖析 + 真实场景配置,你应该已经掌握:
- 为什么 External IP 不会随节点故障而变化;
- 高可用切换的底层机制与调优方法;
- 流量在网络各层的走向;
- 如何在复杂网络环境中正确部署。
别再用 NodePort 硬扛生产流量了!
花 10 分钟配置 MetalLB + Ingress,换来的是稳定、可维护、可扩展的入口体系。