Kubernetesやネットワーク構成を扱う際、DNAT(Destination NAT)の仕組みをよく目にします。「ServiceのVirtual IPをPod IPに書き換える」「外部アクセスを特定のノードやPodへ転送する」――いずれもDNATが裏で動いているケースです。
ところが、ここで1つ不思議な疑問が生まれます。「DNATされた先を、さらに別のDNATで書き換えることはできるのか?」様々な事例やトラブルシューティングで、この疑問に突き当たる方がいます。しかし結論から言うと、一般的には「できない」「やりづらい」という答えになります。本記事では、この仕組みと理由を解説していきます。
1. DNATとは?
まず改めてDNATをおさらいしましょう。DNAT (Destination NAT)とは、受信パケットの宛先情報(IPアドレスやポート)を書き換える技術のことです。Linuxのnetfilter/iptablesでは、主にnatテーブルのPREROUTINGチェーンなどで設定します。
- 例: 「外部からNodeの80番ポートに来た通信を、Podの8080番ポートに転送する」
- PREROUTINGで-d --dport 80のパケットを-j DNAT --to-destination :8080のように指定する
Kubernetesでは、このDNATが各ノードで自動的に設定され、Service(ClusterIP)の宛先をPodIPに振り分ける仕組みが実装されています。
2. 「DNATの先をさらにDNAT」できないのはなぜ?
結論から言うと、iptablesでは基本的に二重DNATができません。この大きな理由は以下のとおりです。
-
iptablesのNATは1回の変換を前提としている
- iptablesのNATは接続トラッキング(conntrack)と連携して、パケットフロー単位でNATを行います。最初のパケットに対して一度DNATを適用すると、以後の同じコネクション上のパケットは「すでに変換済み」として扱われ、原則再度DNATは行いません。
-
DNAT後にルーティングが走るので、パケットがPREROUTINGに戻らない
- DNATは多くの場合PREROUTINGで適用されます。ここで宛先IPが書き換えられた後は、Linuxカーネルのルーティングテーブルを参照してパケットの行き先が決定します。同じ方向のパケットが再びPREROUTINGに流れ込むことはなく、結果として「DNATの先でさらにDNAT」という動きは発生しません。
-
特殊な構成を組めば二重DNATができる場合もあるが、一般的でない
- 理屈の上では、別ホストに配送された後に、そこでまたDNATを行うことは可能です。しかし「同じホスト内でPREROUTING → DNAT → 再びDNAT」といった多段構成は、標準のiptablesでは想定されていません。
3. KubernetesのServiceで見られるDNAT
Kubernetesでは、Service(ClusterIP)あてのパケットをPodIPにDNATすることでトラフィックを転送します。具体的には、Node上に作られるKUBE-SERVICESやKUBE-POSTROUTINGチェーンなどで、以下の手順が実行されます。
-
PREROUTINGでDNAT
- ServiceのClusterIPにあてられたパケットを、選択したPodIP:Portに書き換えます。
-
ルーティングテーブルによりPod宛てと判断
- 書き換えられたあとは、Podが動いているNode内部、もしくは別のNodeへのルーティングが行われます。
当然ながら1回のDNATで宛先が確定すると、その後さらにDNATをかけるケースは想定されていません。これが「DNATの先を再度DNAT」は難しいという背景に直結しています。
4. よくある疑問・トラブルシューティング
4.1 「外部ロードバランサ → NodePort → Pod でさらにDNATは?」
Kubernetesでは外部ロードバランサがNodePortにトラフィックを流し、NodePortを経由してPodに行くときもDNATが行われます。しかしこれも本質は「外部LB → NodePort → DNAT → Pod」のひとつの流れであって、一つの連続した接続をトラッキングしているため、二重にDNATするわけではありません。
4.2 「ServiceからほかのServiceへ転送するとDNATは再度行われる?」
同じNode上でService A → Service Bにリクエストする場合、パケット自体は別のコネクションとして扱われるため、再びDNATが行われる可能性はあります。ただしこれも「まったく別の接続として」DNATされているにすぎません。
5. それでも二重DNATをしたい場合のヒント
もし何らかの要件で「DNATの先でさらにDNAT」を実現したいケースがあるなら、以下のような方法を検討できます。
-
別のホストや機器を挟む
- DNATが適用された後、別ホストに配送された段階で新たなDNATをかけることは可能です。
-
OUTPUTやPOSTROUTINGチェーンなどで別途NAT
- 一方向でDNATし、戻りの方向でSNATするといった複雑な構成を組む場合はあります。ただし管理が難しく推奨はされません。
基本的にはネットワークが複雑になるデメリットの方が大きいので、設計の段階で可能な限り「多段DNAT」は避けるのがおすすめです。
まとめ
-
DNATの先をさらにDNATできない理由
- iptablesのNATはコネクション追跡(conntrack)との連携で「一度変換したコネクションを再び変換しない」
- DNAT後はルーティングが走るため、同じパケットはPREROUTINGに戻らない
-
KubernetesのServiceやNodePortも同様の仕組み
- いずれも1回のDNATで宛先をPodIPに書き換えたら終了
-
どうしても二重DNATが必要な場合は
- 別ホスト経由など、特殊な設定が必要で一般的でない
iptablesが持つ「NATは1コネクションにつき1回」という設計を知っておくと、Kubernetesやネットワークのトラブルシュートにも役立ちます。二重DNATによる複雑化を避けられるよう、システム設計時にはフローをシンプルにするのがおすすめです。