Azure NAT Gatewayの「IP枯渇問題」を華麗に回避する:複数IPアサインとラウンドロビンの真実
クラウドインフラを設計していて、最も頭を抱える瞬間の一つが「SNATポート枯渇」です。特に、外部のSaaS APIを大量に叩くようなマイクロサービスを運用していると、ある日突然「Connection Timeout」の嵐に襲われる……そんな経験、皆さんも一度や二度あるのではないでしょうか。
Azure NAT Gatewayは、そんなネットワークエンジニアの救世主です。特に、最大16個ものパブリックIPアドレスを一つのNAT Gatewayにぶら下げられる「IPプール機能」は、大規模トラフィックを捌くための必須スキル。今日は、このNAT Gatewayが裏側でどうやってIPを選択し、パケットを送り出しているのか、現場の泥臭い視点から深掘りしていきます。
なぜ1つのIPでは足りないのか?
基本をおさらいしましょう。Azure NAT Gatewayは、サブネット内のインスタンスの通信を、単一のグローバルIPに集約してインターネットへ送り出します。ここでボトルネックになるのが「SNATポート」です。
TCPコネクションは 送信元IP:送信元ポート – 送信先IP:送信先ポート の組み合わせで識別されます。NAT Gatewayが変換できるポート数は、一つのパブリックIPあたり最大64,512個。これを超えると、新しい通信は全てドロップされます。
そこで登場するのが「パブリックIPの複数アサイン」です。
16個のIPを束ねる「ラウンドロビン」の挙動
Azure NAT Gatewayに複数のパブリックIPを関連付けると、システムはそれらを「IPプール」として管理します。ここで重要なのは、「コネクション生成ごとに、プール内のIPがラウンドロビン(循環)的に選択される」というロジックです。
通信フローのシーケンス
1. [内部] サブネット内のVMが外部Web APIへリクエストを送信。
2. [NAT Gateway] 関連付けられたIP 1 -> IP 2 -> … -> IP 16 の順で、空いているポートを持つIPを動的に割り当て。
3. [外部] 宛先サーバーは、バラバラなIPからやってくるリクエストを受け取る(ここが重要です!)。
もし貴方が「送信元のIPを常に固定しないと、外部API側で認証エラーになる」という特殊な環境にいる場合、このラウンドロビンは逆に罠になります。しかし、ステートレスなAPI呼び出しであれば、この仕組みのおかげでポート枯渇の閾値は単純計算で16倍(約100万ポート)まで跳ね上がります。
実践:Azure CLIで複数IPを構成する
まずは、CLIを使ってIPアドレスをNAT Gatewayに紐付ける手順を見てみましょう。
# 1. パブリックIPアドレスを2つ作成
az network public-ip create --name MyPublicIP1 --resource-group MyRG --sku Standard
az network public-ip create --name MyPublicIP2 --resource-group MyRG --sku Standard
# 2. NAT Gatewayに複数のIPを紐付ける
az network nat gateway create \
--name MyNatGateway \
--resource-group MyRG \
--public-ip-addresses MyPublicIP1 MyPublicIP2
# 確認:紐付けられたIPのリストを取得
az network nat gateway show --name MyNatGateway --resource-group MyRG --query "publicIpAddresses"
Pythonで確認する:送信元IPが切り替わっているか
実際にこの構成の上で、IPアドレスを確認する外部サービス(https://api.ipify.orgなど)を連続して叩いてみると、NAT Gatewayの挙動が可視化できます。
import requests
import time
# NAT Gateway経由で何度もIPを確認するコード
def check_nat_ip():
for i in range(10):
try:
# IPifyは呼び出し元のグローバルIPを返すAPI
response = requests.get("https://api.ipify.org")
print(f"Request {i+1}: Source IP = {response.text}")
except Exception as e:
print(f"Error: {e}")
# 短いスパンで叩いてプール内のIPが切り替わるか観察
time.sleep(0.5)
if __name__ == "__main__":
check_nat_ip()
このコードを実行すると、コンソールには MyPublicIP1 と MyPublicIP2 が交互に、あるいはランダムに近い形で出力されるはずです。
現場で役立つ運用のTips
1. 接続先サーバー側の「IPホワイトリスト」に注意
最もよくあるトラブルが、「NAT GatewayのIPプールを増やしたのに、接続先の外部サーバーから403エラーが返ってくる」というケースです。外部のAPIサーバー側でIP制限をかけている場合、プール内の全てのIPを許可リスト(Allowlist)に追加してもらう必要があります。これを忘れると、ラウンドロビンで「許可されていないIP」が選ばれた瞬間に通信が遮断されます。
2. ポート再利用(TCPパケットのタイムアウト)
NAT Gatewayは、通信終了後一定時間(デフォルトで4分)は、そのポートを「再利用不可」として保持します。高負荷環境では、このタイムアウト値を調整することも検討してください。
# TCPアイドルタイムアウトを調整する場合 (単位: 分)
az network nat gateway update \
--name MyNatGateway \
--resource-group MyRG \
--idle-timeout 10
最後に:ネットワークを「意識しない」ために
エンジニアの腕の見せ所は、「ネットワークの挙動を熟知した上で、それを意識せずに済むアーキテクチャを作ること」にあります。IPプールによるスケールアウトは強力ですが、まずは「コネクションの使い回し(Keep-Alive)」ができているかを確認してください。
HTTPクライアントで Connection: keep-alive を有効にするだけで、NAT GatewayのSNATポート消費は劇的に減ります。NAT GatewayのIPを増やすのは、その「最後の手段」として取っておくのが、トラブルの少ないインフラ運用の秘訣です。
次回は、これらの通信ログを Azure Network Watcher でどう可視化し、ボトルネックを特定するかについて解説したいと思います。それでは、良いクラウドライフを!
コメント