3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DNATの先はDNATにできない? ~iptablesの制約とKubernetesの裏側~

Posted at

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ができません。この大きな理由は以下のとおりです。

  1. iptablesのNATは1回の変換を前提としている

    • iptablesのNATは接続トラッキング(conntrack)と連携して、パケットフロー単位でNATを行います。最初のパケットに対して一度DNATを適用すると、以後の同じコネクション上のパケットは「すでに変換済み」として扱われ、原則再度DNATは行いません。
  2. DNAT後にルーティングが走るので、パケットがPREROUTINGに戻らない

    • DNATは多くの場合PREROUTINGで適用されます。ここで宛先IPが書き換えられた後は、Linuxカーネルのルーティングテーブルを参照してパケットの行き先が決定します。同じ方向のパケットが再びPREROUTINGに流れ込むことはなく、結果として「DNATの先でさらにDNAT」という動きは発生しません。
  3. 特殊な構成を組めば二重DNATができる場合もあるが、一般的でない

    • 理屈の上では、別ホストに配送された後に、そこでまたDNATを行うことは可能です。しかし「同じホスト内でPREROUTING → DNAT → 再びDNAT」といった多段構成は、標準のiptablesでは想定されていません。

3. KubernetesのServiceで見られるDNAT

Kubernetesでは、Service(ClusterIP)あてのパケットをPodIPにDNATすることでトラフィックを転送します。具体的には、Node上に作られるKUBE-SERVICESやKUBE-POSTROUTINGチェーンなどで、以下の手順が実行されます。

  1. PREROUTINGでDNAT

    • ServiceのClusterIPにあてられたパケットを、選択したPodIP:Portに書き換えます。
  2. ルーティングテーブルにより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」を実現したいケースがあるなら、以下のような方法を検討できます。

  1. 別のホストや機器を挟む

    • DNATが適用された後、別ホストに配送された段階で新たなDNATをかけることは可能です。
  2. OUTPUTやPOSTROUTINGチェーンなどで別途NAT

    • 一方向でDNATし、戻りの方向でSNATするといった複雑な構成を組む場合はあります。ただし管理が難しく推奨はされません。

基本的にはネットワークが複雑になるデメリットの方が大きいので、設計の段階で可能な限り「多段DNAT」は避けるのがおすすめです。

まとめ

  • DNATの先をさらにDNATできない理由

    1. iptablesのNATはコネクション追跡(conntrack)との連携で「一度変換したコネクションを再び変換しない」
    2. DNAT後はルーティングが走るため、同じパケットはPREROUTINGに戻らない
  • KubernetesのServiceやNodePortも同様の仕組み

    • いずれも1回のDNATで宛先をPodIPに書き換えたら終了
  • どうしても二重DNATが必要な場合は

    • 別ホスト経由など、特殊な設定が必要で一般的でない

iptablesが持つ「NATは1コネクションにつき1回」という設計を知っておくと、Kubernetesやネットワークのトラブルシュートにも役立ちます。二重DNATによる複雑化を避けられるよう、システム設計時にはフローをシンプルにするのがおすすめです。

3
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?