您好,登錄后才能下訂單哦!
這篇文章主要介紹了在Kubernetes Pod中怎么獲取客戶端的真實IP,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
Kubernetes 依靠 kube-proxy 組件實現 Service 的通信與負載均衡。在這個過程中,由于使用了 SNAT 對源地址進行了轉換,導致 Pod 中的服務拿不到真實的客戶端 IP 地址信息。本篇主要解答了在 Kubernetes 集群中負載如何獲取客戶端真實 IP 地址這個問題。
這里選擇 containous/whoami
作為后端服務鏡像。在 Dockerhub 的介紹頁面,可以看到訪問其 80 端口時,會返回客戶端的相關信息。在代碼中,我們可以在 Http 頭部中拿到這些信息。
Hostname : 6e0030e67d6a IP : 127.0.0.1 IP : ::1 IP : 172.17.0.27 IP : fe80::42:acff:fe11:1b GET / HTTP/1.1 Host: 0.0.0.0:32769 User-Agent: curl/7.35.0 Accept: */*
簡單介紹一下集群的狀況。集群有三個節點,一個 master ,兩個 worker 節點。如下圖:
創建企業空間、項目
如下圖所示,這里將企業空間和項目命名為 realip
創建服務
這里創建無狀態服務,選擇 containous/whoami
鏡像,使用默認端口。
將服務改為 NodePort 模式
編輯服務的外網訪問方式,修改為 NodePort 模式。
查看訪問服務的 NodePort 端口,發現端口為 31509。
訪問服務
瀏覽器打開 Master 節點的 EIP + :31509
時,返回如下內容:
Hostname: myservice-fc55d766-9ttxt IP: 127.0.0.1 IP: 10.233.70.42 RemoteAddr: 192.168.13.4:21708 GET / HTTP/1.1 Host: dev.chenshaowen.com:31509 User-Agent: Chrome/86.0.4240.198 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: lang=zh; Dnt: 1 Upgrade-Insecure-Requests: 1
可以看到 RemoteAddr 是 Master 節點的 IP ,并不是訪問客戶端的真實 IP 地址。這里的 Host 指的是訪問入口的地址,為了方便快速訪問,我使用的是域名,并不影響測試結果。
在上面的訪問中,獲取不到客戶端真實 IP 的原因是 SNAT 使得訪問 SVC 的源 IP 發生了變化。將服務的 externalTrafficPolicy 改為 Local 模式可以解決這個問題。
打開服務的配置編輯頁面
將服務的 externalTrafficPolicy 設置為 Local 模式。
訪問服務,可以得到如下內容:
Hostname: myservice-fc55d766-9ttxt IP: 127.0.0.1 IP: 10.233.70.42 RemoteAddr: 139.198.254.11:51326 GET / HTTP/1.1 Host: dev.chenshaowen.com:31509 User-Agent: hrome/86.0.4240.198 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cache-Control: max-age=0 Connection: keep-alive Cookie: lang=zh; Dnt: 1 Upgrade-Insecure-Requests: 1
Cluster 隱藏了客戶端源 IP,可能導致第二跳到另一個節點,但具有良好的整體負載分布。 Local 保留客戶端源 IP 并避免 LoadBalancer 和 NodePort 類型服務的第二跳,但存在潛在的不均衡流量傳播風險。
下面是對比簡圖:
當請求落到沒有服務 Pod 的節點時,將無法訪問。用 curl 訪問時,會一直停頓在 TCP_NODELAY
, 然后提示超時:
* Trying 139.198.112.248... * TCP_NODELAY set * Connection failed * connect to 139.198.112.248 port 31509 failed: Operation timed out * Failed to connect to 139.198.112.248 port 31509: Operation timed out * Closing connection 0
在生產環境,通常會有多個節點同時接收客戶端的流量,如果僅使用 Local 模式將會導致服務可訪問性變低。引入 LB 的目的是為了利用其探活的特點,僅將流量轉發到存在服務 Pod 的節點上。
這里以青云的 LB 為例進行演示。在青云的控制,可以創建 LB ,添加監聽器,監聽 31509 端口,可以參考 LB 的使用文檔(https://docs.qingcloud.com/product/network/loadbalancer/),在此不再贅述。
如下圖可以看到,在服務的 31509 端口僅 master 節點處于活躍狀態,流量也僅會導向 master 節點,符合預期。
接著繼續增加副本數量到 3
遺憾的是,Pod 并沒有均勻分布在三個節點,其中有兩個處于 master 上。因此 LB 的后端節點也沒有完全點亮。如下圖:
這就需要給 deploy 加上反親和性的描述。有兩種選擇。第一種是配置軟策略,但不能保證全部 LB 后端點亮,均勻分配到流量。
spec: template: metadata: labels: app: myservice spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - myservice topologyKey: kubernetes.io/hostname
另一種是配置硬策略,強制 Pod 分配在不同的節點上,但會限制副本數量,也就是 Pod 總數不能超過 Node 總數。
spec: template: metadata: labels: app: myservice spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - myservice topologyKey: kubernetes.io/hostname
采用硬策略的配置,最終點亮全部后端,如下圖:
如果每一個服務都占用一個 LB,成本很高,同時配置不夠靈活,每次新增服務時,都需要去 LB 增加新的端口映射。
還有一種方案是 LB 將 80、443 的流量導給 Ingress Controller,然后將流量轉發到 Service,接著達到 Pod 中的服務。
此時,需要 LB 能做 TCP 層的透傳,或者 HTTP 層的帶真實 IP 轉發,將 Ingress Controller 的 externalTrafficPolicy 設置為 Local 模式,而 Service 可以不必設置為 Local 模式。
如果想要提高可訪問性,同樣可以參考上面配置反親和性,保證在每個后端節點上都有 Ingress Controller 。
流量的轉發路徑:
LB(80/443) -> Ingress Controller(30000) -> myservice(80) -> myservice-fc55d766-xxxx(80)
首先需要勾選 LB 【獲取客戶端IP】的配置
接著開啟項目的外網訪問網關
然后添加服務的路由
最后還需要在【平臺管理】-> 【集群管理】,進入集群,在系統項目 kubesphere-controls-system 中找到 realip 項目對應的網關。
編輯服務的配置文件,將 externalTrafficPolicy 改為 Local 模式即可。
訪問服務,可以得到如下內容:
Hostname: myservice-7dcf6b965f-vv6md IP: 127.0.0.1 IP: 10.233.96.152 RemoteAddr: 10.233.70.68:34334 GET / HTTP/1.1 Host: realip.dev.chenshaowen.com User-Agent: Chrome/87.0.4280.67 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cache-Control: max-age=0 Cookie: _ga=GA1.2.896113372.1605489938; _gid=GA1.2.863456118.1605830768 Cookie: lang=zh; Upgrade-Insecure-Requests: 1 X-Forwarded-For: 139.198.113.75 X-Forwarded-Host: realip.dev.chenshaowen.com X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Original-Uri: / X-Real-Ip: 139.198.113.75 X-Request-Id: 999fa36437a1180eda3160a1b9f495a4 X-Scheme: https
感謝你能夠認真閱讀完這篇文章,希望小編分享的“在Kubernetes Pod中怎么獲取客戶端的真實IP”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。