【実務・中級編】 プライベートサブネット内でのクロスAZ通信コスト最適化とNATゲートウェイ回避策 – クラウド&コンテナネットワーク実践ガイド

クラウドの「見えない穴」を塞ぐ: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つを守るだけで、あなたのインフラは驚くほど堅牢で、そして安価になります。皆さんのサービスが、無駄な通信という名の「ノイズ」から解放されることを願っています。

コメント

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