思路:先说如何操作——再说原理
1、server 配置中加入externalTrafficPolicy:配置
spec: type: NodePort externalTrafficPolicy: Local 只能在服务启动pod节点 访问才有反应,其他节点直接丢弃请求
2、对于问题那就直接将pod指定到某个节点
deploy中加入 spec: nodeName: node1 #指定pod节点配置 containers: - name: pod-name
3、访问的时候就直接 通过nodeip:serveri-port 进行访问即可获取真实ip
下面分析原因:
对于Service, 如果指定类型为 NodePort, 那么这个端口会在集群的所有 Node 上打开,即使这个Node 上面没有这个pod (很好理解,和守护进程集不一样,对于Deployment 来说,很少会在每个节点上都启动pod,所以必定有一些节点上没有这个pod) 引出一个问题,当某个节点上没有pod的时候,又去访问ta的这个NodePort,能访问到吗? 流程1 答案是可以的,官方文档 流程大概是这样的 client ^ v node 1 <--- node 2 | ^ SNAT | | ---> v | endpoint Client sends packet to node2:nodePort 客户端发送 tcp 包 到 node2:nodePort node2 replaces the source IP address (SNAT) in the packet with its own IP address node2 把客户端源ip地址替换为node2 的ip地址 node2 replaces the destination IP on the packet with the pod IP node2 把请求的目的地ip替换为 pod ip packet is routed to node 1, and then to the endpoint tcp包被路由到 node1, 接着达到 endpoint(如service) the pod’s reply is routed back to node2 pod的响应被路由到 node2 the pod’s reply is sent back to the client node2把pod的响应发送给客户端 可以发现,在这个过程中,客户端的源IP地址丢失了(看第二步) 流程2 为了解决这个问题, k8s 提供了一个功能,通过设置 externalTrafficPolicy=Local 可以保留源IP地址 设置完这个参数之后,流程如下 client ^ / / / / v X node 1 node 2 ^ | | | | v endpoint client sends packet to node2:nodePort, which doesn’t have any endpoints 客户端发送tcp包到 node2:nodePort, 但是 node2 并没有 这个pod packet is dropped tcp包被丢弃 client sends packet to node1:nodePort, which does have endpoints 客户端发送数据包到 node1:nodePort, node1有pod node1 routes packet to endpoint with the correct source IP node1 把包路由到对应的pod,那么pod 就可以拿到正确的客户端源IP地址
4、如果有多个pod可以使用lb进行负载,lb有服务的活性检测,把所有node节点都配置上,让它进行分发请求。