![見出し画像](https://assets.st-note.com/production/uploads/images/72696082/rectangle_large_type_2_c42b0a6396686133498a44cc0a382049.png?width=1200)
EKS の SNAT の挙動から学ぶ EKS ネットワーキング
こんにちは、株式会社 POL のエンジニアの山田です。
今回は、EKS のネットワーキングについてハマった点を共有したいと思います。
内容としては「そんなのドキュメントに書いてあるだろう、ドキュメントよく読め」系なのですが、この挙動を調べているうちに雰囲気でしか理解していなかった EKS 上のトラフィックを Pod にルーティングするために Amazon VPC CNI が何をしているかについて理解することができました。その過程を共有したいと思います。
やろうとしたこと
下記の図のように 2 つ VPC があって、片方の VPC 上の EKS クラスタ上のコンテナに存在する Pod からもう片方の VPC 上の EC2 インスタンスに対して接続しようとしていました。
![](https://assets.st-note.com/img/1645193629496-TdxMEgV9ae.png?width=1200)
しかしながら、VPC peering やセキュリティグループの設定、果てには VPC Reachability Analyzer で EC2 インスタンスと Pod の VPC プライベート IP アドレスが紐付けられている ENI 間を解析しても OK が出ているにも関わらず、ping による疎通ができませんでした。
問題の切り分けのために、別の Podから EC2 インスタンス に ping を実行してみたところ、一部の Pod では ping 接続できることがわかりました。同じコンテナイメージを利用していても、接続できる Pod と接続できない Pod があり、アプリケーション上の問題や、Kuberentes リソースの問題ではないようです。
何が起きていたのか
結論から言うと Amazon VPC CNI の SNAT の挙動により、VPC 外から接続できる Pod と接続できない Pod ができていました。
詳細についてはこちらのドキュメントを確認して欲しいのですが、EKS 上の Pod から VPC 外へのトラフィックの送信元 IP アドレスは、デフォルト設定の動作として、Pod が稼働している EC2 のプライマリ ENI のプライマリプライベート IP アドレスに Amazon VPC CNI (正確には iptables の SNAT)によって変換されます。
なので、Pod が稼働している EC2 のプライマリ ENI 以外に Pod の IP アドレスが割り当てられている場合、Pod に入ってくるパケットが通過するネットワークインターフェースと Pod から出ていくパケットが通過するネットワークインターフェースが異なり、非対称ルーティングになるためパケットが破棄されます。
EKS ネットワーキング
EKS クラスタは複数台の EC2 インスタンスから構成されていて、その EC2 インスタンスからは 1 つ以上の ENI が生えています。
![](https://assets.st-note.com/img/1645178552950-d1kcblD2sb.png?width=1200)
ENI の数は EC2 インスタンスで稼働している Pod の数に依存します。Pod の数が少なければ EC2 インスタンスにアタッチされる ENI の数は 1 つだけになりますが、Pod の数が一定数を超えると ENI の数が 2 つ以上になります。これが通信できる Pod と通信できない Pod といった差分が発生した原因となります。EC2 インスタンスにアタッチされる ENI の数は 1 つだけの場合、すべての通信はプライマリ ENI で行われますが、EC2 インスタンスにアタッチされる ENI の数が2つ以上ある場合、Pod のトラフィックが非対称ルーティングになる可能性が発生します。
ping が成功する場合
デフォルトの状態で、Pod から VPC 外のネットワークへの Ping が成功する場合は、下記図のように Pod の IP アドレスがプライマリ ENI に割り当てられているときです。
![](https://assets.st-note.com/img/1645194055090-0CIzfSlS0a.png?width=1200)
まず、Pod から発信されるパケットの送信元 IP アドレスは Pod が配置されているノード上の iptables でプライマリ ENI のプライマリプライベート IP アドレスに変換されます。その後、相手の EC2 インスタンスへとパケットが届きます。次に、帰りのルートでは各プライマリ ENI を経由して、ping の送信元の Pod へとパケットが到着します。
![](https://assets.st-note.com/img/1645194541313-tVChMxeUdA.png?width=1200)
ping が失敗する場合
運悪く、ping を投げる Pod の IP アドレスがセカンダリ ENI などに割り当てられていた場合、ping は失敗します。
![](https://assets.st-note.com/img/1645194614728-B6eTnBS9u4.png?width=1200)
例にもれず、Pod から発信されるパケットの送信元 IP アドレスは Pod が配置されているノード上の iptables でプライマリ ENI のプライマリプライベート IP アドレスに変換されます。このとき「Ping が成功する場合」で紹介したときとは異なり、パケットはセカンダリ ENI を経由して、相手の EC2 インスタンスへとパケットが届きます。次に、帰りのルートでは EC2 インスタンスのプライマリ ENI を経由し、Ping 発信元のノードのセカンダリ ENI にパケットが届きます。しかしながら、これは非対称ルーティングになるため、パケットは破棄されます。
![](https://assets.st-note.com/img/1645194690355-WKvJOaSeWn.png?width=1200)
このようにして、ping できる Pod とできない Pod が発生していることがわかりました。
まとめ
今回、自分がハマった EKS の SNAT の挙動から EKS ネットワーキングがどのように実現されているのか、AWS VPC CNI の動きについて理解することができました。
ドキュメントに記載してある事柄とはいえ、「なぜそのようになっているのか」について調査してみることで、基礎・根本となる知識をつけることができるのではないかと思います。
上記の内容についてもう少し詳しく聞きたい方はお気軽にカジュアル面談にお申し込みください!
https://meety.net/matches/vjZLxrrqeoGW
この記事が気に入ったらサポートをしてみませんか?