概述
對於NodePort 類型的 service 而言,有一個參數是 externalTrafficPolicy=Local
即 service.spec.externalTrafficPolicy=Local
(
外部訪問Service的方式有兩種:
1)通過設置nodePort映射到物理機,同時設置Service的類型為NodePort。
2)通過設置LoadBalancer映射到雲服務上提供的LoadBalancer地址。這種用法僅用於公有雲服務提供商的雲平台設置Service的場景。對該Service的請求將會通過LoadBalancer轉發到后端Pod上,負載分發的實現方式則依賴於雲服務商提供的LoadBalancer的實現機制。
external 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地址
參考
https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-type-nodeport
https://www.jianshu.com/p/973d3924ee11

