/

EKS ELB 獲取 Client IP 方法紀錄

前言

在 EKS 上要建立 ELB 會採用 service type 指定 LoadBalancer。此時 AWS 的 In-Tree LoadBalacner Controller 或是 AWS Load Balancer Controller 其中之一會協助我們建立對應的 ELB 出來。本文紀錄這兩種 LB Controller 的差異以及不同類型 ELB 使用時機(以獲取 Client IP 為例)。

In-Tree LoadBalacner Controller - CLB

將 server type 指定成 LoadBalancer 此時 In-Tree LoadBalacner Controller 會 privosion 一個 CLB 出來

流量從外部要進入叢集的路徑為

CLB -> Node:NodePort -> Pod maybe in different node

因為透過節點上的 NodePort 進行跳轉,所以 Pod 如果要獲得 Clinet IP 會拿到 Node 中的 IP。而獲取不到真正的 Client IP

接著可以根據官方建議設定 .spec.externalTrafficPolicyLocal(預設為 Cluster

這樣的設定可以避免流量進入到沒有含 Destination Pod 的 Node 上,多做一個 hop 的跳轉,也避免 IP 被洗成該 Node 的 IP

結果發現 Client IP 還是獲取不到,因為 CLB 在與後方的 instance 溝通時,是用該 subnet 介面的 IP 溝通,所以 Client IP 變成是 ELB 的 private IP(該 IP 可以從 ec2 的 network interfacae 找出來)

現在的路徑變成

CLB -> Node:NodePort (Pod also in the node)

開啟了 externalTrafficPolicy 需不需要擔心如果該節點上沒有 Pod,進而請求沒有辦法路由到正確的位置上

答案是不需要,因為 CLB 會對後方的 instance 做健康檢查,若後方 instance 沒有 Pod,那某該 instance 不健康,流量自然不會導入過去

1
2
優點:完全不需修改參數、不需安裝其他 controller
缺點:無法保留 Client IP、不保留 Client IP 流量會多一跳、流量不平均(後面會提到)

In-Tree LoadBalacner Controller - NLB

需要在 annotations 加上

1
2
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"

並且我們將 externalTrafficPolicy 同樣設定成 Local

發現就可以正常獲取 Client IP 了,代表 NLB 在轉發時,不會將 Source IP 介面切換成內網介面,同時後端也不是 instance 是另外一層抽象(target group)

但試想一個一個情況,若我有 3 個 Pod (x, y, z),2 個 (x, y) 落在節點 A,1 個 (z) 落在節點 B

那麼流量進入 NLB 時會先進行 1/2 的機率選擇節點 (A, B),假設進入節點 A 又會有 1/2 的機率選擇 x, y 這兩個 Pod

那麼 Pod 被選中的機率變成

x: 1/2 * 1/2 = 1/4
y: 1/2 * 1/2 = 1/4
z: 1/2

可以發現流量並沒有真的平均轉發都後端的 Pod 上

但 In-Tree Controller 只能建立出這兩種 ELB(並且能修改的參數有限),剩下一種 ALB 必須安裝 AWS Load Balancer Controller

1
2
優點:不需安裝其他 controller、可以保留 Client IP
缺點:不保留 Client IP 流量會多一跳、流量不平均

AWS Load Balancer Controller - NLB

安裝 AWS Load Balancer Controller 後,在使用上必須指定 loadBalancerClass: service.k8s.aws/nlb

並且 AWS Load Balancer Controller 有提供 ipinstance mode(使用 in-tree controller 建立出來的 mode 就是 instance mode)

該功能需要配合 AWS VPC CNI 使用

1
2
3
4
5
annotations:
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
spec:
loadBalancerClass: service.k8s.aws/nlb

此時會發現 NLB 後方的 target group 直接對應到 Pod IP,可以省去多一次跳轉,並且解決流量不平均的問題

但 Client IP 還是沒有保留,我們可以調整 NLB 參數

1
2
annotations:
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: preserve_client_ip.enabled=true

將 NLB 提供的功能 preserve_client_ip 打開,即可完成配置,也不需要透過設定 externalTrafficPolicy 參數即可獲取 Client IP

1
2
優點:保留 Client IP、流量不會多一跳、流量平均
缺點:需安裝其他 controller

AWS Load Balancer Controller - ALB

使用 Ingress 資源建立出 ALB,但是無法設定 preserve_client_ip

如果去 management console 檢查對應 target group,會發現找不到 Preserve client IP addresses 但是多了 Load balancing algorithm 可以選擇

因為是 L7 支援,所以將 Client IP 放入 HTTP header 的 XFF 欄位即可

一樣有 instanceip mode 可以選擇

1
2
優點:保留 Client IP(放在 L7 的 HTTP header 中)、流量不會多一跳、流量平均
缺點:需安裝其他 controller