k8s nginx應用-獲取客戶端訪問真實IP


通常,當 Kubernetes 集群內的客戶端連接到服務的時候,是支持服務的 Pod 可以獲取到客戶端的 IP 地址的,但是,當通過節點端口接收到連接時,由於對數據包執行了源網絡地址轉換(SNAT),因此數據包的源 IP 地址會發生變化,后端的 Pod 無法看到實際的客戶端 IP,對於某些應用來說是個問題,比如,nginx 的請求日志就無法獲取准確的客戶端訪問 IP 了,比如下面我們的應用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

 

直接創建后可以查看 nginx 服務被自動分配了一個 32761 的 NodePort 端口:

$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        28d
nginx        NodePort    10.106.190.194   <none>        80:32761/TCP   48m
$ kubectl get pods -o wide
NAME                              READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
nginx-54f57cf6bf-nwtjp            1/1     Running   0          3m      10.244.3.15    ydzs-node3   <none>           <none>
nginx-54f57cf6bf-ptvgs            1/1     Running   0          2m59s   10.244.2.13    ydzs-node2   <none>           <none>
nginx-54f57cf6bf-xhs8g            1/1     Running   0          2m59s   10.244.1.16    ydzs-node1   <none>           <none>

 

 

我們可以看到這個3個 Pod 被分配到了 3 個不同的節點,這個時候我們通過 master 節點的 NodePort 端口來訪問下我們的服務,因為我這里只有 master 節點可以訪問外網,這個時候我們查看 nginx 的 Pod 日志可以看到其中獲取到的 clientIP 是 10.151.30.11,其實是 master 節點的內網 IP,並不是我們期望的真正的瀏覽器端訪問的 IP 地址:

$ kubectl logs -f nginx-54f57cf6bf-xhs8g
10.151.30.11 - - [07/Dec/2019:16:44:38 +0800] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" "-"

 

 

這個是因為我們 master 節點上並沒有對應的 Pod,所以通過 master 節點去訪問應用的時候必然需要額外的網絡跳轉才能到達其他節點上 Pod,在跳轉過程中由於對數據包進行了 SNAT,所以看到的是 master 節點的 IP。這個時候我們可以在 Service 設置 externalTrafficPolicy 來減少網絡跳數:

 
        
spec: externalTrafficPolicy: Local

 

如果 Service 中配置了 externalTrafficPolicy=Local,並且通過服務的節點端口來打開外部連接,則 Service 會代理到本地運行的 Pod,如果本地沒有本地 Pod 存在,則連接將掛起,比如我們這里設置上該字段更新,這個時候我們去通過 master 節點的 NodePort 訪問應用是訪問不到的,因為 master 節點上並沒有對應的 Pod 運行,所以需要確保負載均衡器將連接轉發給至少具有一個 Pod 的節點。

但是需要注意的是使用這個參數有一個缺點,通常情況下,請求都是均勻分布在所有 Pod 上的,但是使用了這個配置的話,情況就有可能不一樣了。比如我們有兩個節點上運行了 3 個 Pod,假如節點 A 運行一個 Pod,節點 B 運行兩個 Pod,如果負載均衡器在兩個節點間均衡分布連接,則節點 A 上的 Pod 將接收到所有請求的 50%,但節點 B 上的兩個 Pod 每個就只接收 25% 。

由於增加了externalTrafficPolicy: Local這個配置后,接收請求的節點和目標 Pod 都在一個節點上,所以沒有額外的網絡跳轉(不執行 SNAT),所以就可以拿到正確的客戶端 IP,如下所示我們把 Pod 都固定到 master 節點上:

apiVersion: apps/v1
kind: Deployment
metadata:
  name:  nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      tolerations:
      - operator: "Exists"
      nodeSelector:
        kubernetes.io/hostname: ydzs-master
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
 externalTrafficPolicy: Local
  selector:
    app: nginx
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

 

更新服務后,然后再通過 NodePort 訪問服務可以看到拿到的就是正確的客戶端 IP 地址了:    

 

$ kubectl logs -f nginx-ddc8f997b-ptb7b

182.149.166.11 - - [07/Dec/2019:17:03:43 +0800] "GET / HTTP/1.1" 200 612 "-" "M


source: https://mp.weixin.qq.com/s/Jy5Y-b5rVJwec6V0u_jjvw


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM