概要
GKE上にNginxのpodを起動し、起動したNginxでIPアドレスによるアクセス制御するという要件があり、
その時にいろいろハマったのでご紹介。
何にハマったのか?
構成は、
Client -> Ingress -> (NodePort) -> Nginx(pod) -> GAE(アプケーション)
という構成です。
Nginxのログはデフォルトだとremote_addr
を使ってクライアントIPを出力するようなのですが、
アクセスログを見ると、remote_addr
がClientのIPアドレスではなく、何やらPrivateなIPアドレスが表示されています。
この時点では、なんとなくX-Forwarded-For
の設定を入れればいいかなー?と思っていたのですが、
それだけではなかったというお話です。
調査結果
調査を進めると、LoadBalancer配下のNginxがClientIPアドレスを取得する方法が出てきました。
GCP HTTP(S) load balancing 配下のnginxでクライアントIPを取得する方法
remote_addr
やx-forwarded-for
については、以下のブログが分かりやすかったです。
remote_addrとかx-forwarded-forとかx-real-ipとか
上記を参考にNginxを設定しても、NginxがクライアントIPアドレスを取得できません。
ずっとNginxの設定ばかりみていたのですが、実はIngressとNginxに間にあるNodePort
の設定が原因でした。
NodePortのexternalTrafficPolicyについて
NodePortはWokerノードに到達したパケットをロードバランスする機能があるようです。
その設定は、externalTrafficPolicy
で設定可能で、
- cluster(デフォルト)
- local
が設定できます。
externalTrafficPolicy Clusterモード
デフォルトの設定です。
こちらの文献によると、
NodePortではノード上のNodePortに到達したパケットは、さらにノードをまたいだPodへもロードバランシングされる形となっています。
とあります。
このパケット転送を行う際、各Wokerノードで起動しているkube-proxy
がSNATでSrouce IP Address
とDestination IP Address
が書き換えられ、ロードバラシングしてるようです。
今回、 このSrouce IP Address
の書き換えによって、ClientIPアドレスの取得できませんでした。
以下、参考文献をご紹介。
Source IP for Services with Type=NodePort
externalTrafficPolicy localモード
一方、local
モードでは、パケットはバラシングされません。
Clusterモード
の場合、パケットを転送する分ホップ数が増えるため、結果レイテンシーが増えます。
しかしlocalモード
は、当該ノード到達後にノードをまたいだロードバランシングを行わず、当該ノードのPodにパケットを転送しようとするため、Clusterモード
と比較して早いようです。
よって、当該ノードに該当するラベルのPodが存在しない場合は、レスポンスを返すことができなくなりエラーが返ります。
localモード
を使用する際は、全ノードへPodがデプロイされるDaemonSet
が必須 ということになります。
まとめ
externalTrafficPolicyがCluster
モードで動いている場合、
Client -> Ingress
とリクエストが流れきて、ingressが各Wokerノードにリクエストをロードバランスする。
さらにロードバランスした先のWokerノードで起動しているkube-proxy
によって、各Pod間でロードバランスされる。
この際、負荷分散対象となるPodは、NodePortでラベル指定しているPodが対象となり、そのIPアドレスは、NodePortのEndpoints
に登録してある。
と理解しました。(間違ってたら指摘してください)
NodePortと一言で言っても裏ではいろんな仕組みが動いているし、そもそもその概念を理解するのが難しい。
なんとなく動いちゃってるから普段は意識しないが、こうやっていろいろ調べてみると勉強になる。
参考文献
この記事は以下の情報を参考にして執筆しました。
KubernetesのDiscovery&LBリソース(その1)
GKE/Kubernetes でなぜ Pod と通信できるのか
ネットワークの概要
Source IP for Services with Type=NodePort