クラウドの「見えない穴」を塞ぐ:AZ間通信のコスト最適化とNATゲートウェイの呪縛を解く
AWSやGCPでインフラを運用していると、月末の請求書を見て青ざめる瞬間があるはずです。「なぜ、同じクラウド内での通信にこんなにコストがかかっているのか?」と。
その犯人の多くは、「NATゲートウェイを経由したAZ間通信」です。
今日は、教科書には載っていない、しかし現場のSREが必ずと言っていいほどぶつかるこの「通信コストの罠」について、パケットの動きを追いながら、どうやってトラフィックを局所化し、財布に優しいアーキテクチャを築くかを解説します。
—
1. なぜNATゲートウェイを介すと「高くつく」のか?
まず前提として、パブリックサブネットにある NAT Gateway を経由する通信には、以下の2つの料金が発生します。
1. データ処理料金:NATゲートウェイを通過するデータ量(GB単位)にかかる固定費。
2. AZ間データ転送料金:これが盲点です。プライベートサブネット(AZ-a)から NAT Gateway(AZ-b)を経由して外部へ出る、あるいは同じリージョン内の別のAZへ戻る通信には、AZを跨ぐための転送コストが加算されます。
特に厄介なのは、プライベートサブネット同士の通信を「NATゲートウェイ経由のインターネット経由」で行うという誤った設計です。これをしてしまうと、本来ならVPC内ルーティングで済むはずの通信に、わざわざNATのコストと転送コストを二重で支払うことになります。
—
2. パケットの挙動を可視化する:アンチパターンと正攻法
アンチパターン:遠回りするパケット
開発環境のマイクロサービスA(AZ-a)が、別のマイクロサービスB(AZ-b)へアクセスする際、名前解決の結果がパブリックIPを指しており、それが NAT Gateway を経由して戻ってくる。これでは、パケットはVPCの外へ出て、また戻ってくるという無駄な旅を強いられます。
正攻法:トラフィックの局所化(Localizing Traffic)
これを防ぐための鉄則は、「VPC内部の通信は、プライベートIPで完結させる」ことです。
手法A:VPCエンドポイント(Interface Endpoint)の活用
S3やDynamoDB、あるいは自社のAPIがAWSのマネージドサービス経由である場合、Gateway Endpoint ではなく Interface Endpoint(PrivateLink)を各AZに設置してください。これにより、同一AZ内での通信が完結し、AZ間転送コストを回避できます。
手法B:サービスディスカバリとプライベートDNS
curl や Fetch API で他サービスを叩く際、ホスト名にパブリックURLを指定していませんか?
# 悪い例:パブリックURLを叩くとNATゲートウェイを経由する可能性がある
curl https://api.production.example.com/v1/users
# 良い例:VPC内であれば内部ロードバランサーのプライベートDNSを指定する
# これにより、パケットはVPC内部のルーターのみを通過する
curl http://internal-api.service.local/v1/users
—
3. 実践:PythonでAZ間通信を最適化する
アプリケーションコード内での指定方法も重要です。もし環境変数でAPIエンドポイントを注入しているなら、以下のようにプライベートIPまたは内部DNSを優先する設計にします。
import os
import requests
# サービスAからサービスBを呼び出す際の関数
def call_internal_service(endpoint_path):
# 環境変数から内部DNSエンドポイントを取得する
# 例: INTERNAL_API_URL = "http://internal-api.service.local"
base_url = os.getenv("INTERNAL_API_URL", "http://internal-api.service.local")
try:
response = requests.get(f"{base_url}{endpoint_path}", timeout=5)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
# ログには通信先も記録し、NATを経由していないか確認できるようにする
print(f"Error connecting to {base_url}: {e}")
return None
—
4. トラブルシューティング:本当にNATを通っているのか?
「設計は直したはずなのに、コストが下がらない」という場合、パケットがどこを通っているか確信が持てないことがあります。そんな時のデバッグ手順はこれです。
Step 1: VPC Flow Logsの確認
VPC Flow Logs を有効にし、特定のIPアドレス(NATゲートウェイのインターフェースIP)への通信量を確認します。
-- Athenaを使用して、NATゲートウェイのENIへの通信を抽出するクエリ例
SELECT srcaddr, dstaddr, SUM(bytes) as total_bytes
FROM vpc_flow_logs
WHERE interface_id = 'eni-0123456789abcdef' -- NATゲートウェイのENI ID
GROUP BY srcaddr, dstaddr
ORDER BY total_bytes DESC;
Step 2: Route Tableの確認
サブネットのルートテーブルを確認し、宛先が Local になっているか、それとも NAT Gateway に吸い込まれているかを確認してください。特にクロスAZ通信が意図せず NAT を経由する設定になっていないか、ルートの優先順位(ロンゲストマッチ)を再確認しましょう。
—
最後に:SREとしてのマインドセット
クラウドのコスト最適化は、単なる「節約」ではありません。「通信経路の可視化」と「ネットワーク設計の最適化」という、エンジニアリングの基本に立ち返る行為です。
1. パブリックIPをアプリケーション内部で呼び出さない。
2. AZを跨ぐ通信は、可能な限りVPC内部で完結させる。
3. 迷ったらVPC Flow Logsを叩いてパケットの足跡を追う。
この3つを守るだけで、あなたのインフラは驚くほど堅牢で、そして安価になります。皆さんのサービスが、無駄な通信という名の「ノイズ」から解放されることを願っています。
コメント