【Cilium / eBPF】kube-proxy 替代:ClusterIP/NodePort 的 BPF 路径与失败模式

💡 原文中文,约9400字,阅读约需23分钟。
📝

内容提要

Cilium KPR使用BPF map替代kube-proxy的iptables/IPVS,实现O(1)查找与原子更新。ClusterIP采用socket-LB,NodePort支持SNAT/DSR/Hybrid模式,Maglev用于南北向一致性哈希。排障需区分socket与per-packet平面,注意map容量、externalTrafficPolicy及混部冲突。

🔎

延伸解读

两条LB平面:排障先分清socket与per-packet

KPR的LB路径分为socket-LB和per-packet两层。socket-LB在connect时改写目标,适用于本机进程;per-packet路径处理跨节点和外部流量。排障时若ClusterIP不通而NodePort正常,问题多出在socket-LB挂载或hostNetwork例外;反之则需检查TC/XDP路径。混淆两层会导致错误归因,例如将per-packet的丢包误判为应用问题。

externalTrafficPolicy=Local的隐藏陷阱

当externalTrafficPolicy设为Local时,外部流量仅转发到本地后端。若节点无本地Pod,云LB健康检查可能失败,导致节点被标记为unhealthy,出现黑洞。集群内ClusterIP访问不受此影响,因此内外表现可能分裂。排障时应先确认失败路径是集群内还是外部,再检查本地端点是否存在。

Maglev并非万能:仅适用于南北向

Maglev一致性哈希主要用于外部(N-S)流量,集群内(E-W)流量在connect时由socket-LB随机选择,不走Maglev表。全集群必须共享相同hashSeed,否则不同入口节点会选到不同后端。此外,每个Service占用一份查找表,内存开销较大,需按Service数量规划容量。

混部kube-proxy与KPR的风险

同时运行kube-proxy和Cilium KPR可能导致NAT与conntrack双写,引发随机丢包和难以复现的故障。官方建议通过CiliumNodeConfig和节点标签逐步迁移,并确保配置k8sServiceHost/k8sServicePort,否则移除kube-proxy后agent无法连接apiserver。迁移窗口外应保持单一权威实现。

Q&A

Cilium 的 kube-proxy replacement (KPR) 相比 kube-proxy 的 iptables 模式有什么优势?

KPR 使用 BPF map 进行常数时间查找和原子更新,避免了 iptables 规则随 Service 和端点数量线性增长的问题,以及全量 iptables-restore 和全局锁带来的控制面开销。

Cilium KPR 中 socket-LB 和 per-packet LB 分别处理哪些流量?

Socket-LB 处理本机进程(包括 Pod)发起的到 ClusterIP 或 NodePort 的连接,在 connect 时改写目标地址;per-packet LB 处理跨节点、外部入站以及未经过 socket 改写的包,在 TC 或 XDP 层进行负载均衡。

Cilium KPR 中 NodePort 的 SNAT 和 DSR 模式有什么区别?

SNAT 模式下,入口节点对去往后端节点的包做 SNAT,回包必须经过入口节点,后端看不到客户端真实源 IP;DSR 模式下,后端节点直接回包给客户端,保留客户端源 IP,但需要额外的封装(如 IPIP、Geneve)并可能受云厂商反欺骗限制。

Cilium KPR 中 Maglev 算法主要用于什么场景?它有什么限制?

Maglev 主要用于南北向(外部)流量,提供一致性哈希,减少后端变更时受影响连接的比例。它不用于东西向流量,因为 socket-LB 在 connect 时已分配后端。此外,全集群需共享相同的 hashSeed,且每个 Service 会占用额外内存。

在 Cilium KPR 中,externalTrafficPolicy=Local 可能导致什么问题?

当 externalTrafficPolicy=Local 时,流量只会转发到本地后端。如果节点上没有本地 Pod,外部流量会被丢弃,导致黑洞。此外,集群内访问与外部访问的语义可能不同,排障时需区分。

Cilium KPR 中,如果新建 Service 不生效,可能的原因是什么?

可能的原因是 BPF map 容量已满,导致新条目无法写入。此时应检查 map 压力(如 --bpf-lb-map-max),而不是先怀疑 DNS 或应用问题。

Cilium KPR 与 kube-proxy 混部时需要注意什么?

混部时需避免两套实现同时处理同一 Service,否则可能导致 NAT 和 conntrack 冲突。建议使用 CiliumNodeConfig 和节点标签逐步迁移,并配置 k8sServiceHost/k8sServicePort,否则去掉 kube-proxy 后 agent 无法连接 apiserver。

Cilium KPR 中,hostPort 功能由谁接管?如果主机端口不通,应如何排查?

完整 KPR 会接管 hostPort,不再依赖 portmap CNI 插件。如果主机端口不通,应检查 agent 是否将 hostPort 编入 LB 相关 map,而不是先怀疑应用监听地址。

🏷️

标签

➡️

继续阅读