在一次 SSO 对接过程中,我发现服务获取不到客户端的真实 IP。为弄清楚其中原委,我对 k3s 中 LoadBalancer 类型服务的流量路径做了一次详细测试。


🧪 测试目标:搞清楚 LB 流量的路径

在 k3s 中,使用 svclb 实现 LoadBalancer 类型的服务时,它到底是如何转发流量的?
跨节点和同节点流量路径会有什么不同?客户端的真实 IP 地址还能保留吗?

这次的测试,正是为了回答这些问题。


🧰 测试场景一:跨节点访问

场景说明

  • svclb Pod 仅部署在 test-1 节点

  • NGINX 控制器 仅部署在 test-2 节点

也就是说,流量先由客户端打到 test-1 节点的 svclb,再被转发至集群内的 test-2 上的 NGINX。

测试示意图

图片

图片

日志观测结果

  • NGINX 记录的 remote_addr 是 svclb Pod 的 IP,而不是客户端的真实 IP。

  • 跨节点后,客户端真实地址丢失。


🟢 测试场景二:同节点访问

场景说明

  • svclb 和 NGINX 控制器 都部署在 test-1 节点

也就是说,流量不跨节点,直接在同一个节点内部路由。

测试示意图

图片

图片

日志观测结果

  • 此时,NGINX 能正确记录客户端的真实 IP。

  • 没有经过 cluster 网络,IP 未被篡改。


🧠 最终结论

image-20250713225325553

✅ 跨节点流量经过 svclb 后,remote_addr 被替换为 svclb 的 IP ✅ 同节点访问时,客户端 IP 能被正确记录 ✅ 建议:

  • 若依赖真实 IP,避免跨节点或改用 MetalLB

  • 通过 header 透传真实 IP(如 X-Real-IP, X-Forwarded-For)


📝 彩蛋小故事

k3s 自带的 LoadBalancer就是个klipper-lb cosplay 的‘假LB’,于是耿某抱着满腔热血,开始频频向组内涛某“游说“:咱们的基建要上真家伙MetalLB!,涛某一边喝着咖啡一边回应:”你就说能不能用吧,能跑就行🐸“。劝说未果!!!

“有些 LB,生来就注定不能暴露公网;

 有些人,生来就不愿折腾 MetalLB。”


📚 延伸阅读推荐

  • k3s 中的 Service LoadBalancer 原理 [1]

  • MetalLB [2]


如果你也在使用 k3s,遇到过类似问题,欢迎留言讨论!👍

引用链接

[1] k3s 中的 Service LoadBalancer 原理: https://rancher.com/docs/k3s/latest/en/networking/#load-balancer
[2] MetalLB: https://metallb.io/