【実務・中級編】 GCP Cloud NATの基本アーキテクチャとポートアロケーション方式 – クラウドインフラと仮想化ネットワーク実践ガイド

Cloud NATの深淵を覗く:ポート枯渇を乗り越え、堅牢な egress 設計を手に入れる

こんにちは。深夜の障害対応でアラートの波を乗り越え、ようやくコーヒーにありついたSREの皆さん、お疲れ様です。

今日はGCPの「Cloud NAT」について深掘りしましょう。「設定したら勝手に繋がる便利なゲートウェイ」と思っていませんか? 実は、その裏側ではポートアロケーション(ポート割り当て)という、現代のWebインフラにおける「兵站(へいたん)」の戦いが繰り広げられています。

APIを叩くたびに発生する Connection reset by peer や 503 Service Unavailable に頭を抱えた経験があるなら、この記事はあなたのためのものです。

—

1. Cloud NATの正体:なぜ「マネージド」なのか

VPC内のプライベートIPしか持たないVMが、なぜインターネット上の公開APIと通信できるのか。それはCloud NATが「L4(トランスポート層)の魔術師」として、送信元IPとポート番号を書き換えているからです。

Cloud NATの最大の美点は、「ステートフルなNAT」であること。VMが外部へ通信を開始すると、Cloud NATは「どのVMが、どの外部IPの、どのポートへ接続しているか」を追跡し、戻りのパケットを正しいVMへルーティングします。

エンドポイント独立型マッピング(Endpoint-Independent Mapping)

ここがGCPの面白いところです。Cloud NATはデフォルトで「エンドポイント独立型マッピング」を採用しています。
これは、同じ送信元IP・ポートから複数の外部宛先へ通信する場合、NAT後のIPとポートを固定するという仕様です。これにより、STUNのような通信プロトコルや、特定のクライアントIPを求める認証サーバーとの相性が劇的に良くなります。

—

2. 実務の壁:ポート枯渇(Port Exhaustion)の罠

エンジニアが最も遭遇する「Cloud NATの罠」が、ポートの枯渇です。

1つのNAT IPアドレスには、65,536個のポートしかありません(実際には予約分があるためもっと少ない)。もしあなたのプロダクトが、マイクロサービス間で大量の外部APIを叩く構成なら、あっという間にこのポートを使い果たします。

ポート割り当ての仕組み

Cloud NATは、VMに対して「ポートの束(チャンク)」を割り当てます。

  • 動的割り当て: 必要に応じてポート範囲を拡張します。
  • 最小ポート数: 1VMあたり最低64ポート(デフォルト)が確保されます。

もし、高い頻度で外部APIを叩く場合、min_ports_per_vm を調整しなければ、即座に通信エラーが発生します。

# 現在のCloud NAT設定を確認するコマンド
gcloud compute routers nats describe NAT_NAME --router=ROUTER_NAME --region=REGION

もしポート不足が疑われるなら、以下のように最小ポート数を引き上げます。

# 1VMあたりの最小ポート数を1024に引き上げる設定例
gcloud compute routers nats update NAT_NAME \
    --router=ROUTER_NAME \
    --region=REGION \
    --min-ports-per-vm=1024

—

3. 現場で使えるデバッグとコード設計

APIクライアントを書くとき、接続ごとにTCPコネクションを張る「毎回接続」は自殺行為です。Cloud NATのポートを瞬時に使い切り、障害を招きます。

推奨される設計:Connection Pooling

Pythonの requests ライブラリを使うなら、Session オブジェクトを使い回すのが鉄則です。これによりTCPコネクションが再利用され、NATのポート消費を劇的に抑えられます。

import requests

# Sessionオブジェクトを再利用することで、TCP接続をプールする
session = requests.Session()

def call_external_api(url):
    try:
        # この通信は既存のTCP接続を再利用する可能性がある
        response = session.get(url, timeout=5)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        # ここで発生するConnectionErrorがポート枯渇のサインかもしれない
        print(f"API Error: {e}")

# 実務ではこのsessionをシングルトンなどで管理する

クライアント側のデバッグ

もし通信が不安定なら、まずは curl で詳細なトレースを確認しましょう。

# TCP接続の確立時間や、NAT越えの挙動を確認するためのコマンド
curl -Iv https://api.example.com/health \
  --connect-timeout 2 \
  --max-time 10

—

4. SREからのTips:監視を怠るな

「なんとなく動いている」状態は、クラウドインフラにおいては最も危険です。Cloud Monitoringで以下のメトリクスをダッシュボードに貼ることを強く推奨します。

1. nat/allocated_ports_count: 現在いくつのポートが割り当てられているか。
2. nat/dropped_packets_count: ポート不足でパケットが捨てられていないか。

特に dropped_packets_count が0以外を指したとき、それはあなたのインフラが悲鳴を上げている証拠です。即座に min_ports_per_vm の見直し、あるいはNAT IPアドレスの追加を検討してください。

まとめ

Cloud NATはただのゲートウェイではありません。スケーラブルな通信を支える重要なコンポーネントです。

  • ポートの割り当て戦略を理解する。
  • Connection Pooling を適切に実装する。
  • メトリクスによる監視をサボらない。

これらを守るだけで、あなたのインフラの信頼性は格段に向上します。「なんとなく」を「納得」に変えていくのが、一流のSREへの近道です。それでは、また現場でお会いしましょう!

コメント

タイトルとURLをコピーしました