K3s 混合云记录:Traefik 获取真实 IP 的一个坑
最近在学习 Kubernetes,用 K3s 搭了一个混合云集群。
整体架构很简单:
- Kubernetes:K3s
- Ingress:Traefik
- 跨云网络:WireGuard
- 测试服务:whoami
原本只是想验证一下 Ingress 的访问链路,但很快发现一个问题:
Pod 一直获取不到客户端真实 IP。
问题现象
部署 whoami 后访问服务,返回结果类似:
RemoteAddr: 10.x.x.x
X-Forwarded-For: 10.x.x.x看到的始终是 节点或集群内部 IP,而不是客户端公网 IP。
第一反应:externalTrafficPolicy
常见解决方案是给 Service 设置:
externalTrafficPolicy: Local这样可以避免 kube-proxy 做 SNAT,从而保留客户端 IP。
但在我的环境里,即使设置了:
externalTrafficPolicy: Local依然无法获取真实 IP。
K3s 文档里的一个 Known Issue
继续查资料时,在 K3s 文档中看到一条说明:
If external traffic reaches the node using a NAT (e.g. in public clouds) and you require externalTrafficPolicy=local for purposes such as client source IP preservation, please do not define the k3s config node-external-ip for any of the nodes.
简单来说:
如果节点是在 NAT 网络(公有云很常见) 中,并且你需要依赖externalTrafficPolicy: Local 来保留客户端 IP,
不要配置 node-external-ip。
但在混合云场景下问题更复杂
在真实的 混合云架构 中,即使不配置 node-external-ip,问题仍然可能存在。
因为典型链路往往是:
Client
↓
云厂商 NAT / 公网入口
↓
Node
↓
Traefik
↓
Pod只要链路中存在 NAT,客户端 IP 就很可能已经被改写。
而 externalTrafficPolicy: Local 只能避免 Kubernetes 内部 SNAT,
无法解决公网入口 NAT 的问题。
实际可行的方案
如果是在 混合云 + 公有云 NAT 的环境中,想稳定获取真实 IP,通常需要在入口层解决。
比较常见的方式有两种:
1. 前置 HAProxy / Nginx / L4 负载均衡
在 Kubernetes 之前放一层入口代理,例如:
Client
↓
HAProxy / Nginx
↓
K3s Node
↓
Traefik
↓
Pod入口代理负责:
- 保留客户端 IP
- 添加
X-Forwarded-For/X-Real-IP - 再把流量转发给集群
2. 使用 CDN / 反向代理
例如:
- Cloudflare
- 其他 CDN / Edge 网络
链路变成:
Client
↓
CDN / Edge
↓
K3s Node
↓
Traefik
↓
PodCDN 会通过 Header 传递真实客户端 IP,例如:
CF-Connecting-IP
X-Forwarded-For然后在 Traefik 中信任这些 Header 即可。
最终结论
在 K3s + 混合云 + 公有云 NAT 的环境里:
externalTrafficPolicy: Local只能解决 Kubernetes 内部 SNAT- 无法解决 公网 NAT 导致的 IP 丢失
- 如果想稳定获取真实 IP,需要在 集群入口层处理
通常的做法是:
- 前置 HAProxy / Nginx
- 或使用 Cloudflare / CDN
小结
这次踩坑最大的感受是:
很多 Kubernetes 的网络问题,其实 不在 Kubernetes 本身,而是在入口网络结构。
特别是在 混合云环境 下:
网络链路远比单云复杂。
#(击掌)
死狗一