Calico BGP 内置 LoadBalancer(生产:ECMP ingress DS)源: https://github.com/sxxpqp/linux/blob/main/kubernetes/calico/bgp-lb/README.md 状态: ✅ 生产验证Calico BIRD 一套 BGP同时宣告 Pod CIDR LoadBalancer Service IP,不再需要 MetalLB / kube-vip。多节点宣告同一 LB IP → 路由器走BGP ECMP做 L3 负载均衡 → 流量散到多个 ingress-nginx DS 实例。LB IP 自动分配,建 Service 即用。TL;DR# 1. 装 Calico BGP-LBbashinstall.sh --apiserver-host172.16.150.128 --my-asn64500\--lb-cidr172.16.150.200/29\--peer-asn64500--peer-address172.16.150.131# 2. 装 ingress-nginx(DaemonSet 跑在 node1/node2,Service 类型 LoadBalancer)bash../../ingress-nginx/install.sh --label-nodesnode1,node2# 3. 看 LB IP 自动分配 BGP ECMP 多路径生效kubectl get svc-ningress-nginx ingress-nginx-controller# 期望 EXTERNAL-IP 出现 172.16.150.200,且路由器侧 ip route 显示 multipath# 4. 卸载bashuninstall.sh--apply生产架构 — BGP ECMP 多路径 Ingress DS┌──────────────────┐ │ 外部路由器 │ │ AS64500│ │(本环境:.131)│ └──────┬───────────┘ │iproute172.16.150.200/32: proto bird(ECMP, 多 nexthop)nexthop via172.16.150.129 dev eth0 weight1← node1 nexthop via172.16.150.130 dev eth0 weight1← node2 │ ┌──────────────────┼──────────────────┐ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ kh .128 │ │ node1 .129│ │ node2 .130│ │ control │ │ ingress DS│ │ ingress DS│ │ plane │ │ worker │ │ worker │ └───────────┘ └─────┬─────┘ └─────┬─────┘ │ │ ingress-nginx controller(DaemonSet)│ ────────── Service / Pod CIDR ────────── │ ┌──────────┴──────────┐ ▼ ▼ Service A Service B(业务 ClusterIP)(业务 ClusterIP)4 层协作层组件干什么① 路由发现Calico BIRD(每节点)跟外部路由器建 BGP peer,宣告本节点持有的 Pod CIDR 子段 LB IP② ECMP 负载均衡外部路由器收到 N 个相同 prefix(172.16.150.200/32)的 BGP 通告,安装 N 条 nexthop(ECMP),按流哈希③ 入口流量ingress-nginx DS跑在多节点(hostNetwork: true直用宿主网络,或 Service LB),接收路由器送来的流量④ 业务流量Service Podingress 路由到后端 ClusterIP → kube-proxy / Calico 数据面送到 PodBGP ECMP 工作原理LB Service 创建→lb-assigner从--lb-cidr池里挑一个 IP 填进.status.loadBalancer.ingress[].ipCalico 监听→ 看到 LB IP 后,所有有该 Service backend Pod 的节点(externalTrafficPolicyCluster 时:所有节点)通过 BGP 把LB_IP/32宣告出去路由器收到 N 条同 prefix 路由→ 内核 / 路由表合并成 ECMP 多路径,按(src_ip, src_port, dst_ip, dst_port, proto)5-tuple 哈希挑 nexthop同一连接稳定到同一节点(避免乱序);不同连接散到多节点 → 负载均衡⚠externalTrafficPolicy: Local时只有跑了 backend Pod 的节点会宣告 → ECMP 路径数 节点 Pod 数。Cluster时所有节点都宣告(可能多此一跳 SNAT,但 ECMP 更均衡)。Ingress DS 推荐Local(每节点都有 Pod,路径数等于 DS 实例数)。ingress-nginx DaemonSet 部署模型字段推荐理由kindDaemonSet每个标记节点一个实例,故障域隔离,ECMP 多路径靠这个nodeSelectoringresstrue(用--label-nodesnode1,node2自动打)只在专门的入口节点跑,跟业务节点解耦Service.typeLoadBalancer(配合 Calico BGP)拿到 LB IP,被 BGP 宣告Service.externalTrafficPolicyLocal保留客户端真实 IP ECMP 路径数等于 DS 实例数hostNetwork看情况:中小集群true(80/443 直绑宿主) / 大集群false(Service LB)hostNetwork 模式 ingress 直接吃宿主 80/443,跳过一层 kube-proxy详情和 yaml 模板见 …/…/ingress-nginx/README.md。文件文件状态说明install.sh✅BGP 安装:operator BGPConfiguration BGPPeer LB 自动分配器uninstall.sh✅卸载:剥 CR finalizer 清 namespace,默认 dry-runinstallation.yaml✅Installation CR:Iptables BGP 无 VXLANlb-assigner.sh✅LB IP 自动分配器(安装时自动部署为 Deployment)simulate-router.sh✅外部路由器模拟(FRRouting Docker,用于测试 BGP peering / ECMP)参数参数必填说明--apiserver-host✅API server 地址--my-asn✅集群 BGP AS 号(私有 AS 64512-65534,本环境 64500)--lb-cidr✅LoadBalancer Service IP 段(本环境172.16.150.200/29)--peer-asn可选上游路由器 AS 号;不传只开 node-mesh(节点间 iBGP)--peer-address可选上游路由器 BGP IPIP 段规划段用途172.16.150.128/25节点 IP(kh .128 / node1 .129 / node2 .130 / node4 .131)172.16.150.200/29LoadBalancer Service IP(8 个)10.244.0.0/16Pod CIDR(BGP 宣告)10.96.0.0/12ClusterIP Service CIDR⚠ LB CIDR 跟节点同段不冲突 — BGP 宣告/32主机路由,优先级高于/24子网路由。跟其他模式对比BPF (operator)BGP (bgp/)BGP-LB (本目录)dataplaneeBPFIptablesIptablesPod 路由VXLANBIRD BGPBIRD BGPService LBMetalLBMetalLBCalico 自带 ECMPLB IP 分配MetalLB 自动MetalLB 自动lb-assigner 自动入口负载均衡kube-proxykube-proxy路由器 ECMP ingress DSkube-proxy替换保留保留额外组件无MetalLB speakerlb-assigner(1 个 pod)验证1. Calico BGP peer 状态# 所有 Established 才算 BGP 正常kubectl-ncalico-systemexecds/calico-node -- birdcl show protocols2. BGP 路由(集群侧)# 节点应该向路由器宣告:Pod CIDR 子段 各 LB IP /32kubectl-ncalico-systemexecds/calico-node -- birdcl show route3. ECMP 多路径(路由器侧 — 这是关键)# 在路由器 / FRR 容器里跑iproute show172.16.150.200/32# 期望输出:# 172.16.150.200 proto bird# nexthop via 172.16.150.129 dev eth0 weight 1# nexthop via 172.16.150.130 dev eth0 weight 1只有 1 个 nexthop ECMP 没生效。常见原因:路由器没开maximum-paths(FRR 默认multipath-relax关,需手动开)只有一个节点宣告(检查externalTrafficPolicy ingress DS 是否真的多节点跑了)4. LB 分配器日志kubectl-nkube-system logs deploy/lb-assigner-f5. 端到端连通bash../test-connectivity.sh# 从集群外打 LB IP,验证 ingress 接到curl-HHost: 你的 ingress 域名http://172.16.150.200/# 多发几次看是否均衡到不同节点(看 ingress pod 日志)foriin{1..20};docurl-s-HHost: ...http://172.16.150.200/;donekubectl-ningress-nginx logs ds/ingress-nginx-controller--tail50|grepclient_ip踩坑现象原因修法LB Service EXTERNAL-IPpendinglb-assigner没起来 /--lb-cidr池满kubectl -n kube-system get pod -l applb-assigner 看日志路由器ip route show LB_IP只 1 个 nexthop路由器没开 ECMP /multipath-relaxFRR:bgp bestpath as-path multipath-relaxmaximum-paths N只有 1 个节点在宣告 LB IPexternalTrafficPolicy: Local但只有 1 个节点有 backend Pod把 ingress DS 调度到 ≥2 个节点(nodeSelector--label-nodes)BGP peerActive不EstablishedCalico 侧没配 BGPPeer / AS 不匹配kubectl get bgppeer -o yaml看 AS;确认--peer-asn跟路由器一致namespace 卡 Terminatinguninstall脚本python3不可用手动:kubectl get ns -o jsonBad peer AS路由器 AS 跟 Calico 配的不匹配确认--peer-asn跟路由器实际 AS 一致ECMP 流量不均衡路由器哈希算法只用src_ip(默认 3-tuple)改 5-tuple:ip rule fib_multipath_hash_policy1(L3L4)路由器侧 FRR ECMP 配置(参考)如果你的路由器也是 FRR(本仓库测试环境就是),关键配置:router bgp64500bgp router-id172.16.150.131 bgp bestpath as-path multipath-relax maximum-paths4neighbor172.16.150.129 remote-as64500!node1 neighbor172.16.150.130 remote-as64500!node2!...Linux 内核侧打开 L4 哈希(否则 ECMP 按 src_ip 哈希,单源压测时全到一个节点):sysctl-wnet.ipv4.fib_multipath_hash_policy1# 0L3(默认), 1L3L4
Calico BGP + 内置 LoadBalancer(生产:ECMP + ingress DS)
Calico BGP 内置 LoadBalancer(生产:ECMP ingress DS)源: https://github.com/sxxpqp/linux/blob/main/kubernetes/calico/bgp-lb/README.md 状态: ✅ 生产验证Calico BIRD 一套 BGP同时宣告 Pod CIDR LoadBalancer Service IP,不再需要 MetalLB / kube-vip。多节点宣告同一 LB IP → 路由器走BGP ECMP做 L3 负载均衡 → 流量散到多个 ingress-nginx DS 实例。LB IP 自动分配,建 Service 即用。TL;DR# 1. 装 Calico BGP-LBbashinstall.sh --apiserver-host172.16.150.128 --my-asn64500\--lb-cidr172.16.150.200/29\--peer-asn64500--peer-address172.16.150.131# 2. 装 ingress-nginx(DaemonSet 跑在 node1/node2,Service 类型 LoadBalancer)bash../../ingress-nginx/install.sh --label-nodesnode1,node2# 3. 看 LB IP 自动分配 BGP ECMP 多路径生效kubectl get svc-ningress-nginx ingress-nginx-controller# 期望 EXTERNAL-IP 出现 172.16.150.200,且路由器侧 ip route 显示 multipath# 4. 卸载bashuninstall.sh--apply生产架构 — BGP ECMP 多路径 Ingress DS┌──────────────────┐ │ 外部路由器 │ │ AS64500│ │(本环境:.131)│ └──────┬───────────┘ │iproute172.16.150.200/32: proto bird(ECMP, 多 nexthop)nexthop via172.16.150.129 dev eth0 weight1← node1 nexthop via172.16.150.130 dev eth0 weight1← node2 │ ┌──────────────────┼──────────────────┐ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ kh .128 │ │ node1 .129│ │ node2 .130│ │ control │ │ ingress DS│ │ ingress DS│ │ plane │ │ worker │ │ worker │ └───────────┘ └─────┬─────┘ └─────┬─────┘ │ │ ingress-nginx controller(DaemonSet)│ ────────── Service / Pod CIDR ────────── │ ┌──────────┴──────────┐ ▼ ▼ Service A Service B(业务 ClusterIP)(业务 ClusterIP)4 层协作层组件干什么① 路由发现Calico BIRD(每节点)跟外部路由器建 BGP peer,宣告本节点持有的 Pod CIDR 子段 LB IP② ECMP 负载均衡外部路由器收到 N 个相同 prefix(172.16.150.200/32)的 BGP 通告,安装 N 条 nexthop(ECMP),按流哈希③ 入口流量ingress-nginx DS跑在多节点(hostNetwork: true直用宿主网络,或 Service LB),接收路由器送来的流量④ 业务流量Service Podingress 路由到后端 ClusterIP → kube-proxy / Calico 数据面送到 PodBGP ECMP 工作原理LB Service 创建→lb-assigner从--lb-cidr池里挑一个 IP 填进.status.loadBalancer.ingress[].ipCalico 监听→ 看到 LB IP 后,所有有该 Service backend Pod 的节点(externalTrafficPolicyCluster 时:所有节点)通过 BGP 把LB_IP/32宣告出去路由器收到 N 条同 prefix 路由→ 内核 / 路由表合并成 ECMP 多路径,按(src_ip, src_port, dst_ip, dst_port, proto)5-tuple 哈希挑 nexthop同一连接稳定到同一节点(避免乱序);不同连接散到多节点 → 负载均衡⚠externalTrafficPolicy: Local时只有跑了 backend Pod 的节点会宣告 → ECMP 路径数 节点 Pod 数。Cluster时所有节点都宣告(可能多此一跳 SNAT,但 ECMP 更均衡)。Ingress DS 推荐Local(每节点都有 Pod,路径数等于 DS 实例数)。ingress-nginx DaemonSet 部署模型字段推荐理由kindDaemonSet每个标记节点一个实例,故障域隔离,ECMP 多路径靠这个nodeSelectoringresstrue(用--label-nodesnode1,node2自动打)只在专门的入口节点跑,跟业务节点解耦Service.typeLoadBalancer(配合 Calico BGP)拿到 LB IP,被 BGP 宣告Service.externalTrafficPolicyLocal保留客户端真实 IP ECMP 路径数等于 DS 实例数hostNetwork看情况:中小集群true(80/443 直绑宿主) / 大集群false(Service LB)hostNetwork 模式 ingress 直接吃宿主 80/443,跳过一层 kube-proxy详情和 yaml 模板见 …/…/ingress-nginx/README.md。文件文件状态说明install.sh✅BGP 安装:operator BGPConfiguration BGPPeer LB 自动分配器uninstall.sh✅卸载:剥 CR finalizer 清 namespace,默认 dry-runinstallation.yaml✅Installation CR:Iptables BGP 无 VXLANlb-assigner.sh✅LB IP 自动分配器(安装时自动部署为 Deployment)simulate-router.sh✅外部路由器模拟(FRRouting Docker,用于测试 BGP peering / ECMP)参数参数必填说明--apiserver-host✅API server 地址--my-asn✅集群 BGP AS 号(私有 AS 64512-65534,本环境 64500)--lb-cidr✅LoadBalancer Service IP 段(本环境172.16.150.200/29)--peer-asn可选上游路由器 AS 号;不传只开 node-mesh(节点间 iBGP)--peer-address可选上游路由器 BGP IPIP 段规划段用途172.16.150.128/25节点 IP(kh .128 / node1 .129 / node2 .130 / node4 .131)172.16.150.200/29LoadBalancer Service IP(8 个)10.244.0.0/16Pod CIDR(BGP 宣告)10.96.0.0/12ClusterIP Service CIDR⚠ LB CIDR 跟节点同段不冲突 — BGP 宣告/32主机路由,优先级高于/24子网路由。跟其他模式对比BPF (operator)BGP (bgp/)BGP-LB (本目录)dataplaneeBPFIptablesIptablesPod 路由VXLANBIRD BGPBIRD BGPService LBMetalLBMetalLBCalico 自带 ECMPLB IP 分配MetalLB 自动MetalLB 自动lb-assigner 自动入口负载均衡kube-proxykube-proxy路由器 ECMP ingress DSkube-proxy替换保留保留额外组件无MetalLB speakerlb-assigner(1 个 pod)验证1. Calico BGP peer 状态# 所有 Established 才算 BGP 正常kubectl-ncalico-systemexecds/calico-node -- birdcl show protocols2. BGP 路由(集群侧)# 节点应该向路由器宣告:Pod CIDR 子段 各 LB IP /32kubectl-ncalico-systemexecds/calico-node -- birdcl show route3. ECMP 多路径(路由器侧 — 这是关键)# 在路由器 / FRR 容器里跑iproute show172.16.150.200/32# 期望输出:# 172.16.150.200 proto bird# nexthop via 172.16.150.129 dev eth0 weight 1# nexthop via 172.16.150.130 dev eth0 weight 1只有 1 个 nexthop ECMP 没生效。常见原因:路由器没开maximum-paths(FRR 默认multipath-relax关,需手动开)只有一个节点宣告(检查externalTrafficPolicy ingress DS 是否真的多节点跑了)4. LB 分配器日志kubectl-nkube-system logs deploy/lb-assigner-f5. 端到端连通bash../test-connectivity.sh# 从集群外打 LB IP,验证 ingress 接到curl-HHost: 你的 ingress 域名http://172.16.150.200/# 多发几次看是否均衡到不同节点(看 ingress pod 日志)foriin{1..20};docurl-s-HHost: ...http://172.16.150.200/;donekubectl-ningress-nginx logs ds/ingress-nginx-controller--tail50|grepclient_ip踩坑现象原因修法LB Service EXTERNAL-IPpendinglb-assigner没起来 /--lb-cidr池满kubectl -n kube-system get pod -l applb-assigner 看日志路由器ip route show LB_IP只 1 个 nexthop路由器没开 ECMP /multipath-relaxFRR:bgp bestpath as-path multipath-relaxmaximum-paths N只有 1 个节点在宣告 LB IPexternalTrafficPolicy: Local但只有 1 个节点有 backend Pod把 ingress DS 调度到 ≥2 个节点(nodeSelector--label-nodes)BGP peerActive不EstablishedCalico 侧没配 BGPPeer / AS 不匹配kubectl get bgppeer -o yaml看 AS;确认--peer-asn跟路由器一致namespace 卡 Terminatinguninstall脚本python3不可用手动:kubectl get ns -o jsonBad peer AS路由器 AS 跟 Calico 配的不匹配确认--peer-asn跟路由器实际 AS 一致ECMP 流量不均衡路由器哈希算法只用src_ip(默认 3-tuple)改 5-tuple:ip rule fib_multipath_hash_policy1(L3L4)路由器侧 FRR ECMP 配置(参考)如果你的路由器也是 FRR(本仓库测试环境就是),关键配置:router bgp64500bgp router-id172.16.150.131 bgp bestpath as-path multipath-relax maximum-paths4neighbor172.16.150.129 remote-as64500!node1 neighbor172.16.150.130 remote-as64500!node2!...Linux 内核侧打开 L4 哈希(否则 ECMP 按 src_ip 哈希,单源压测时全到一个节点):sysctl-wnet.ipv4.fib_multipath_hash_policy1# 0L3(默认), 1L3L4