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への近道です。それでは、また現場でお会いしましょう!
コメント