在 Kubernetes 中,为了提高应用程序的可靠性和弹性,可以使用 HTTP service 来实现负载均衡和服务发现。但是,当 Pod 作为服务端接受客户端请求时,有时候需要获取客户端真实 IP 地址,以便进行针对性的处理。然而,当 Pod 通过 HTTP service 接收请求时,获取到的 IP 地址可能是 service 的 Cluster IP,而不是客户端真实 IP 地址。这个问题会影响到许多应用场景,比如 IP 地址限制、日志收集等等。本文将介绍 Kubernetes 中 Pod 无法从 HTTP service 发现中获取客户端真实 IP 的解决方法,并提供示例代码。
问题所在
在 Kubernetes 中,HTTP service 为 Pod 提供了一个稳定的入口地址。当客户端发送请求到 service 的入口地址时,请求会被 service 转发到后端 Pod 上。在这个过程中,service 会使用 iptables 规则将源 IP 地址 NAT 成为 Pod IP 地址。这个 NAT 的过程可能会导致问题,因为客户端真实 IP 地址被隐藏了起来。
解决方法
解决方法有两种:使用 proxy-protocol 或者使用 iptables 规则。下面将分别介绍这两种方法。
使用 proxy-protocol
proxy-protocol 是一种在 TCP 连接上添加头部的协议,该头部包含了客户端真实 IP 地址等信息。Kubernetes 中可以使用 nginx-ingress-controller 来实现支持 proxy-protocol 的负载均衡。具体操作如下:
部署 nginx-ingress-controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.40.2/deploy/static/provider/cloud/deploy.yaml
安装 external-dns:
kubectl apply -f https://github.com/kubernetes-sigs/external-dns/releases/download/v0.7.6/external-dns.yaml
配置 Ingress:
-- -------------------- ---- ------- ----------- ------------------------- ----- ------- --------- ------------ ------------------------------------- ------ ----- ---- ----- ------ - ----- ---------------- ----- ------ - -------- ------------ ---- ------------ -- ----- -
暴露 service:
kubectl expose deployment demo --port=80 --target-port=80 --type=LoadBalancer
等待 service 创建完成后,在 Ingress 上绑定 LoadBalancer IP:
kubectl patch ingress demo -p '{"spec":{"loadBalancerIP":"<load_balancer_ip>"}}'
尝试访问服务,并查看 Pod 的 logs,应该可以看到客户端真实 IP 地址。
使用 iptables 规则
这种方法需要直接修改 iptables 规则,比较麻烦和危险。操作过程如下:
添加 iptables 规则:
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination $POD_IP:80 iptables -t nat -A POSTROUTING -j MASQUERADE
$POD_IP
是后端 Pod 的 IP 地址。修改 Pod 运行命令:
command: [ "/bin/sh", "-c", "iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination $POD_IP:80 && iptables -t nat -A POSTROUTING -j MASQUERADE && exec /app" ] args: - "-app"
app
是应用程序的执行命令。
总结
本文介绍了 Kubernetes 中 Pod 无法从 HTTP service 发现中获取客户端真实 IP 的解决方法。使用 proxy-protocol 和 iptables 规则都可以实现客户端真实 IP 地址的获取,但是使用 proxy-protocol 更加方便和安全。我们建议使用 proxy-protocol 来解决这个问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/649d19f348841e98949d143d