はい、承知いたしました!GCP Cloud NATのポートパブリッシュ、SNAT、ポートオーバーサブスクリプションの回避策について、インフラやネットワークの初心者の方にも分かりやすく、まるで隣で一緒にパケットの流れを追うような感覚で解説するブログ記事を執筆します。
—
GCP Cloud NATのポートパブリッシュ、SNAT、そして「あのエラー」を理解しよう!
皆さん、こんにちは!AWSやGCPのネットワークって、最初はちょっと「??」ってなっちゃいますよね。特に、プライベートIPしか持っていない仮想マシン(VM)が、どうやってインターネットとやり取りしているのか、不思議に思ったことはありませんか?
今日は、そんな疑問をスッキリ解決するために、GCPの「Cloud NAT」というサービスに焦点を当てて、その裏側で何が起きているのかを、身近な例え話を交えながら、じっくり紐解いていきたいと思います。
「ポートパブリッシュ? SNAT? ポートオーバーサブスクリプション? なんか難しそう…」と思ったあなたも大丈夫! 一歩ずつ、丁寧に解説していきますので、安心してくださいね。
そもそも、プライベートIPなVMがインターネットに出られないってホント?
まず、基本から確認しましょう。GCPのVPCネットワークでは、VMには通常、グローバルに一意なIPアドレス(グローバルIPアドレス)か、VPCネットワーク内でしか使えないIPアドレス(プライベートIPアドレス)が割り当てられます。
インターネットは、世界中のコンピューターが繋がっている「公衆網」です。この公衆網に接続するためには、インターネット側から「あなたに話しかけたい!」と思ったときに、どこに届ければいいか分かる、ユニークな住所が必要になります。
プライベートIPアドレスは、まさに「自宅の部屋番号」のようなものです。同じ建物(VPCネットワーク)の中では、その部屋番号で特定できますが、建物の外(インターネット)からは、「〇〇マンションの△△号室」と言っても、そもそもどのマンションか分からない、という状態なんです。
ということは、プライベートIPアドレスしか持っていないVMは、そのままではインターネットへ通信を送信することも、インターネットからの通信を受け取ることもできません。
そこに現れた救世主! Cloud NATの登場!
では、どうすればプライベートIPなVMからインターネットへ通信できるのでしょうか? そこで登場するのが、GCPの「Cloud NAT」なんです。
Cloud NATは、プライベートIPアドレスを持つVMからのインターネットへのアウトバウンド通信(外向きの通信)を、グローバルIPアドレスに変換してくれるサービスです。
例えるなら、Cloud NATは、たくさんの「郵便局」のようなものです。
- VM(プライベートIP): あなたの家。自宅の部屋番号(プライベートIP)は知っているけれど、外の人は直接あなたの家を特定できません。
- インターネット: 世界中の宛先。
- Cloud NAT: 郵便局。あなたが書いた手紙(通信)を預かり、あなたの家の住所(プライベートIP)ではなく、郵便局の住所(グローバルIP)で、宛先(インターネット)へ送ってくれます。そして、宛先からの返信も、一旦郵便局(Cloud NAT)で受け取って、あなた(VM)に届けてくれるんです。
このように、Cloud NATがあるおかげで、プライベートIPなVMでも、インターネットへのアウトバウンド通信が可能になるんですね。
SNATって何? NATの「変換」の仕組みを覗いてみよう
Cloud NATがVMの通信をグローバルIPに変換する仕組みのことを、一般的に「NAT(Network Address Translation)」と呼びます。その中でも、プライベートIPをグローバルIPに変換する処理は「SNAT(Source NAT)」と呼ばれます。
SNATの「Source」は「送信元」という意味です。つまり、通信の「送信元IPアドレス」を変換するんですね。
もう少し詳しく見てみましょう。
1. VMがインターネットへ通信を開始:
VMは、宛先IPアドレス(例: Googleのウェブサーバー)と、送信元IPアドレスとして自分のプライベートIPアドレス(例: 10.128.0.5)を使って、パケットを生成します。
2. Cloud NATがパケットを受信:
そのパケットは、Cloud NATゲートウェイに到達します。
3. SNAT処理の実行:
Cloud NATは、パケットの送信元IPアドレスを、Cloud NATに割り当てられたグローバルIPアドレス(例: 35.200.100.50)に書き換えます。
4. インターネットへ送信:
変換されたパケットは、送信元IPアドレスがグローバルIPアドレスになった状態で、インターネットへ送信されます。
この変換のおかげで、インターネット上のサーバーは、通信がCloud NATから来たものだと認識し、返信をCloud NATに送り返します。Cloud NATは、どのVMがその通信を開始したかを覚えておき、返信を正しいVMに届けます。
郵便局で例えると…
あなたが友達に手紙を出すとします。
- あなたの家(VM):
〇〇マンション △△号室 - 友達(インターネット上のサーバー):
△△市 □□通り 1-2-3 - 郵便局(Cloud NAT):
〒100-0001 東京都千代田区…
あなたが手紙に書く「差出人」は、本来なら「〇〇マンション △△号室」としたいところですが、もし郵便局の住所でしか送れないとしたら…
Cloud NATは、あなたの手紙の「差出人」を、あなたの住所ではなく「〒100-0001 東京都千代田区…」という郵便局の住所に書き換えてくれるイメージです。
そして、友達から返事が来るときは、郵便局(Cloud NAT)に届きます。郵便局は、「この返事は、あの〇〇マンションの△△号室から来た手紙への返事だな」と覚えていて、あなた(VM)に届けてくれるのです。
ポートって何?通信の「窓口」を理解する
さて、SNATでIPアドレスは変換されることが分かりました。でも、インターネット上には、たくさんのウェブサイトやサービスがありますよね? 一つのグローバルIPアドレスで、どうやってたくさんの通信を区別しているのでしょうか?
ここで登場するのが「ポート番号」です。
ポート番号は、IPアドレスと組み合わせて、コンピューター上で動作している特定のアプリケーションやサービスを識別するための番号です。例えるなら、建物の「部屋番号」のようなものです。
- IPアドレス: 建物(コンピューター)の住所
- ポート番号: その建物の中の、特定の部屋番号
例えば、ウェブサイト(HTTP)は通常80番ポート、暗号化されたウェブサイト(HTTPS)は443番ポートを使います。
SNATのとき、Cloud NATはIPアドレスだけでなく、送信元ポート番号も変換します。なぜなら、同じVMから複数のインターネットへの通信が発生した場合、送信元IPアドレスだけが同じだと、インターネット側はどの通信がどのVMからのものか、そしてVM側は受け取った返信がどの通信に対するものか区別できなくなってしまうからです。
Cloud NATは、VMの送信元IPアドレスと送信元ポート番号の組み合わせを、Cloud NATのグローバルIPアドレスと新しい送信元ポート番号の組み合わせにマッピングして管理します。この、元のポート番号とは異なる新しいポート番号を割り当てることを「ポートパブリッシュ」と呼ぶこともあります。
郵便局の「窓口」で例えると…
先ほどの郵便局の例に戻りましょう。
もし、あなたが郵便局(Cloud NAT)から友達(インターネット上のサーバー)に、同時に複数の手紙を出したいとします。
- 友達に「元気?」と聞く手紙
- 友達に「おすすめの映画を教えて」と頼む手紙
これらの手紙が、すべて同じ「郵便局の住所」で届くと、友達は「あれ? どっちの手紙に返事を書けばいいんだっけ?」となってしまいますよね?
そこで、郵便局(Cloud NAT)は、あなたからの手紙に「窓口番号」のようなものを付けます。
- 「元気?」の手紙 → 郵便局の住所 + 窓口A
- 「おすすめの映画は?」の手紙 → 郵便局の住所 + 窓口B
このように、Cloud NATは、VMのプライベートIPアドレスとポート番号の組み合わせを、Cloud NATのグローバルIPアドレスと、ユニークなポート番号(窓口番号)の組み合わせに変換して、インターネットに送信します。
そして、友達からの返信も、郵便局の住所と窓口番号で届くので、郵便局(Cloud NAT)は、どのVMのどの通信に対する返信かを正しく判断し、VMに届けることができるのです。
ポートオーバーサブスクリプション?「窓口」が足りなくなるとどうなる?
さて、ここで少し困った問題に直面することがあります。それは「ポートオーバーサブスクリプション」という現象です。
Cloud NATは、限られた数のグローバルIPアドレスとポート番号を使って、たくさんのVMからの通信を仲介しています。
- グローバルIPアドレス: Cloud NATが使用するIPアドレス。
- ポート番号: 各グローバルIPアドレスで利用できるポート番号の総数(通常、TCP/UDPそれぞれ65536個)。
Cloud NATは、VMからの通信ごとに、グローバルIPアドレスとポート番号のペア(例: 35.200.100.50:12345)を、通信が終了するまで(あるいはタイムアウトするまで)割り当てて、管理しています。
もし、一つのCloud NATゲートウェイが管理するグローバルIPアドレスのポート数が、同時に接続しようとするVMからの通信数に対して不足してしまうと、どうなるでしょうか?
まさに「窓口が足りなくなる」状態です。
- 郵便局(Cloud NAT): 窓口が65535個しかないのに、同時に10万人の人が手紙を出そうとしている!
- あなた(VM): 新しい手紙(通信)を出そうとしても、空いている窓口がない!
この状態を「ポートオーバーサブスクリプション」と呼びます。
ポートオーバーサブスクリプションが発生すると…
ポートオーバーサブスクリプションが発生すると、新しいアウトバウンド通信を開始しようとしたVMは、ポートを割り当てることができず、通信が失敗してしまいます。
具体的には、以下のようなエラーが発生することがあります。
ERR_CONNECTION_TIMED_OUT(接続タイムアウト)ERR_CONNECTION_REFUSED(接続拒否)ERR_NAME_NOT_RESOLVED(名前解決エラー) など、通信経路のどこかで詰まったようなエラー
これらのエラーは、必ずしもCloud NATのポート枯渇だけが原因とは限りませんが、VMからのアウトバウンド通信が頻繁に失敗するようになった場合、Cloud NATのポート枯渇を疑うべき重要なサインとなります。
ポートオーバーサブスクリプションを回避するには?
では、この「窓口不足」を防ぐにはどうすれば良いのでしょうか? いくつかの方法があります。
1. Cloud NATゲートウェイのポート割り当てを増やす
Cloud NATでは、ポートの割り当て方法をいくつか設定できます。
- 自動割り当て (Automatic allocation): GCPが自動的にポートを割り当ててくれます。VMの数や通信量に応じて、必要に応じてポートを増やしてくれますが、それでも限界はあります。
- 手動割り当て (Manual allocation): 使用するグローバルIPアドレスと、各IPアドレスに割り当てるポート数を具体的に指定できます。
手動割り当てで、より多くのポートを割り当てることで、ポート枯渇のリスクを減らすことができます。
設定例:Cloud NATのポート割り当てを増やす(gcloud CLI)
ここでは、gcloudコマンドを使って、Cloud NATのポート割り当てを増やす例を見てみましょう。
まず、既存のCloud NATの設定を確認します。
gcloud compute routers nats describe [NAT_GATEWAY_NAME] \
--router=[ROUTER_NAME] \
--region=[REGION]
[NAT_GATEWAY_NAME]: 作成したCloud NATゲートウェイの名前[ROUTER_NAME]: Cloud NATが関連付けられているルーターの名前[REGION]: Cloud NATがデプロイされているリージョン
上記のコマンドで、natIpAllocateOption や logConfig などの設定が表示されます。
次に、ポート割り当てを増やすために、natIpAllocateOption を AUTO_ONLY から MANUAL_ONLY に変更し、logConfig.enable を true にしてログを有効にしておくと、後でデバッグしやすくなります。
注意: MANUAL_ONLY を指定する場合、sourceNatActiveRanges で使用するグローバルIPアドレスを指定する必要があります。ここでは、既存のIPアドレスを使用する例を示します。
gcloud compute routers nats update [NAT_GATEWAY_NAME] \
--router=[ROUTER_NAME] \
--region=[REGION] \
--nat-ip-allocate-option=MANUAL_ONLY \
--source-nat-active-ranges="[GLOBAL_IP_ADDRESS_1],[GLOBAL_IP_ADDRESS_2]" \
--min-ports-per-vm=1024 \ # 各VMに最低1024ポートを割り当てる (必要に応じて調整)
--max-ports-per-vm=2048 # 各VMに最大2048ポートを割り当てる (必要に応じて調整)
--nat-ip-allocate-option=MANUAL_ONLY: 手動割り当てモードにします。--source-nat-active-ranges: 使用するグローバルIPアドレスを指定します。事前にgcloud compute addresses createなどで作成しておいたグローバルIPアドレスを指定してください。--min-ports-per-vm: 各VMに最低限割り当てるポート数。--max-ports-per-vm: 各VMに最大で割り当てるポート数。
ポイント: --min-ports-per-vm と --max-ports-per-vm の値を調整することで、各VMが利用できるポート数を制御できます。通信量が多いアプリケーションをご利用の場合は、これらの値を大きめに設定することを検討しましょう。
2. より多くのグローバルIPアドレスをCloud NATに割り当てる
Cloud NATゲートウェイに、より多くのグローバルIPアドレスを割り当てることも、ポート枯渇のリスクを軽減する効果的な方法です。
IPアドレスが増えれば、それだけ利用できるポートの総数も増えるからです。
設定例:Cloud NATに複数のグローバルIPアドレスを割り当てる(gcloud CLI)
Cloud NATを作成する際に、複数のグローバルIPアドレスを指定します。
# 事前にグローバルIPアドレスを作成しておく
gcloud compute addresses create nat-ip-1 --region=[REGION]
gcloud compute addresses create nat-ip-2 --region=[REGION]
# Cloud NATを作成し、複数のIPアドレスを指定
gcloud compute routers nats create [NAT_GATEWAY_NAME] \
--router=[ROUTER_NAME] \
--region=[REGION] \
--nat-ip-allocate-option=MANUAL_ONLY \
--source-nat-active-ranges="[IP_ADDRESS_1],[IP_ADDRESS_2]" \
--auto-allocate-nat-external-ips=false # 手動割り当てなのでfalseにする
--source-nat-active-ranges: ここに、作成した複数のグローバルIPアドレスをカンマ区切りで指定します。--auto-allocate-nat-external-ips=false: 手動でIPアドレスを指定するので、自動割り当てを無効にします。
3. VMインスタンスの数を増やす(オートスケーリングの活用)
もし、特定のVMインスタンスでポート枯渇が頻繁に発生している場合、そのインスタンスの通信量が多すぎる可能性があります。
この場合、VMインスタンスの数を増やして通信を分散させる、あるいはオートスケーリング機能を使って、通信量に応じてVMの数を自動的に調整する、というアプローチも有効です。
ただし、これはあくまで「通信の分散」であり、Cloud NAT自体のポート上限を増やすわけではありません。
4. TCPコネクションのタイムアウト設定を見直す
TCP通信では、通信が終了した後もしばらくの間、ポートが「TIME_WAIT」などの状態になり、すぐに再利用できないことがあります。
もし、アプリケーションが非常に短時間で大量のTCPコネクションを確立・切断する場合、このタイムアウト設定がポート枯渇に影響する可能性もゼロではありません。
しかし、これは高度なチューニングになるため、まずは上記1、2の方法を優先的に検討することをおすすめします。
まとめ:Cloud NATの「窓口」を理解して、快適なネットワークライフを!
今日は、GCP Cloud NATのSNAT、ポートパブリッシュ、そしてポートオーバーサブスクリプションについて、郵便局の例え話を交えながら解説しました。
- SNAT(Source NAT): プライベートIPなVMの通信を、Cloud NATのグローバルIPに変換する仕組み。
- ポートパブリッシュ: SNATの際に、通信を区別するために新しいポート番号を割り当てること。
- ポートオーバーサブスクリプション: Cloud NATが管理するポート数が不足し、通信ができなくなる状態。
これらの仕組みを理解することで、VMからインターネットへの通信がどのように実現されているのか、そして、なぜ通信エラーが発生するのか、その原因を特定する手がかりが得られたはずです。
もし、VMからのアウトバウンド通信で「接続タイムアウト」のようなエラーが頻繁に発生するようになったら、今回ご紹介したCloud NATのポート割り当て設定を見直してみてください。
ネットワークの基礎は、最初は少し難しく感じるかもしれませんが、一つ一つ丁寧に理解していけば、必ず皆さんの力になります!
これからも、皆さんのインフラ・ネットワークライフがより快適になるような情報をお届けしていきますので、お楽しみに!
コメント