クラウドの「見えない税金」を断つ:AZローカルルーティングとNATゲートウェイ配置の極意
クラウドインフラのコスト最適化において、多くのエンジニアが最初に直面し、そして頭を悩ませるのが「データ転送量(Data Transfer)」の請求書だ。中でも、パブリッククラウド(AWSのCross-AZ Data Transfer、GCPのCross-zone Trafficなど)におけるアベイラビリティーゾーン(AZ)間通信コストは、システムがスケールアウトするにつれて静かに、しかし確実にインフラ予算を蝕んでいく。
「マルチAZ構成にしているから可用性は万全だ。マルチAZにNATゲートウェイを並べておけば耐障害性も高い」――そう信じて設計されたシステムの本番環境で、月末に届く請求書を見て冷や汗をかいた経験はないだろうか。
今回は、パケットレベルの挙動、Linuxカーネルのルーティング、そしてTCP/IPのトランスポート層の最適化に踏み込みながら、クロスAZトラフィックコストの正体を暴き、それを根絶するための「AZローカルルーティング設計」の極意を解説する。
—
1. なぜクロスAZトラフィックコストが発生するのか? パケットの旅路を追う
まずは、クラウドの内部ネットワークで何が起きているのかを物理・論理レイヤーで直視しよう。
一般的な3レイヤーアプリケーションや、外部APIと通信するマイクロサービス群を想像してほしい。プライベートサブネット(非公開サブネット)に配置されたワーカーノードやKubernetesのPodから、外部のSaaSや決済ゲートウェイへHTTPSリクエストを送出するシーンを考える。
可用性を考慮し、パブリックサブネットに複数のNATゲートウェイ(AWSのNAT GatewayやGCPのCloud NATなど)を配置している。ここで、次のような設計ミス(あるいは無頓着なデフォルト設定)があったとする。
1. az-a にあるプライベートサブネットのワーカーノードから外部宛のパケットが送出される。
2. ルートテーブル(Route Table)のデフォルトルート(0.0.0.0/0)の向き先として、なぜか az-b にあるNATゲートウェイが指定されている(あるいは、特定のAZだけにNAT Gatewayを集約している)。
3. ワーカーノードから送り出されたIPパケットは、仮想ルーター(SDNコントロールプレーン)によって az-b へ転送される。
この瞬間、クラウドプロバイダーのバックボーンネットワーク上では、AZの境界を跨ぐデータ転送が発生している。ギガバイト単位、あるいはテラバイト単位のログや画像、APIペイロードがAZ間を結ぶ光ファイバーを駆け抜けるたびに、プロバイダーはしっかりと「クロスAZデータ転送費用」を課金しているのだ。これが、クラウドアーキテクトが夜な夜な怯える「見えない税金」の正体である。
—
2. AZローカルルーティング設計の核心:カスタムルートテーブルの動的制御
このコストを劇的に、かつ構造的に削減するための唯一の解法が 「AZローカルルーティング(AZ-Local Routing)」 である。
思想は極めてシンプルだ。「自分の所属するAZにあるNATゲートウェイへしかパケットを投げない」。しかし、これをTerraformやAWS CDKなどのIaCで美しく実装するには、クラウドのリージョン特性とサブネットのトポロジを完全に理解したルーティング設計が必要になる。
悪い例:単一NATゲートウェイ集中型
# 【アンチパターン】すべてのプライベートサブネットが同一のNAT Gatewayを参照
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.centralized.id # すべてのAZからこのNATに集中し、クロスAZ課金が爆発する
}
}
良い例:AZ独立・ローカル完結型ルーティング
真のAZローカルルーティングでは、各AZ専用のルートテーブルを生成し、対応するAZのNATゲートウェイへとパケットを誘導する。Terraformでこれを動的に構築するスマートなコードスニペットを見てみよう。
# AZごとのプライベートサブネットとNAT Gatewayを完全に独立させる動的マッピング
locals.tf や main.tf のイメージ
variable "azs" {
default = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}
# 1. 各AZにNAT Gatewayを配置 (冗長性とローカル完結の両立)
resource "aws_nat_gateway" "per_az" {
for_each = toset(var.azs)
allocation_id = aws_eip.nat[each.key].id
subnet_id = aws_subnet.public[each.key].id
tags = {
Name = "nat-gw-${each.key}"
}
}
# 2. AZごとに独立したプライベート用ルートテーブルを作成
resource "aws_route_table" "private_az" {
for_each = toset(var.azs)
vpc_id = aws_vpc.main.id
# 同一AZ内のNAT Gatewayへルーティングを閉じ込める(クロスAZゼロ)
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.per_az[each.key].id
}
tags = {
Name = "rt-private-${each.key}"
}
}
# 3. プライベートサブネットを対応するAZのルートテーブルに関連付け
resource "aws_route_table_association "private_assoc" {
for_each = aws_subnet.private
subnet_id = each.value.id
route_table_id = aws_route_table.private_az[each.value.availability_zone].id
}
この構成により、ap-northeast-1a に存在するPodやEC2インスタンスからのアウトバウンドトラフィックは、物理的・論理的に同一AZ内のNAT Gatewayを直撃し、外部へ抜け出す。AZ間を横断するパケットはゼロになり、クロスAZデータ転送コストは完全に排除される。
—
3. Kubernetes(EKS/GKE)環境におけるトポロジ認識と落とし穴
マネージドKubernetes環境(Amazon EKSやGoogle Kubernetes Engine)では、この設計はさらに複雑なレイヤーを持つ。K8sの TopologySpreadConstraints や service.kubernetes.io/topology-aware-routing が絡むためだ。
KubernetesのノードがマルチAZに分散している場合、Podから外部通信を行う際、どのノードがどのAZに属しているかを意識する必要がある。特に、CNI(Container Network Interface)プラグインがAWS VPC CNIやCalicoの場合、PodのIPアドレスはVPCのサブネットから直接割り当てられる。
ここで発生しがちなトラブルが、「CiliumやCalicoのルーティングミスによる意図しないAZまたぎ」 だ。
Kubernetesクラスターで外部通信のパフォーマンスを極限まで高め、AZコストを抑えるためには、ノード単位でのSNAT挙動や、kube-proxyのパケット処理モード(iptables vs IPVS vs eBPF)を正しく理解しなくてはならない。
eBPF(Cilium等)を用いたソブリン・ルーティングのすすめ
従来の iptables モードでは、コネクション数が数万を超えたあたりからルール評価の線形検索によるレイテンシ悪化(CPUバウンドなオーバーヘッド)が発生する。さらに、クロスAZトラフィックが発生している場合、どのパスを通っているかの追跡が極めて困難になる。
CiliumなどのeBPFベースのCNIを採用する場合、カーネルスペース(XDPレイヤー)でパケットを直接操作し、ローカルのネットワークインターフェイスやNATデバイスへダイレクトにルーティングさせることが可能だ。
—
4. ネットワーク層のチューニング:RTT削減とLinuxカーネルのTCPバッファ最適化
AZローカルルーティングによってパケットの無駄な遠回りは防げた。しかし、インフラエンジニアとして、ここで満足してはプロ失格だ。NATゲートウェイを経由する通信のパフォーマンス(スループットとレイテンシ)を限界まで引き上げるための、Linuxカーネル(Sysctl)のチューニングレシピを公開しよう。
NATゲートウェイは、膨大な数のプライベートIPアドレスを少数のパブリックIPアドレスに変換するため、内部で NAPT(Network Address Port Translation) のステートテーブルを高速に処理している。高スループットなシステムでは、このポート枯渇やコネクション渋滞がボトルネックになる。
プライベートサブネット側のノード(Linuxカーネル)で設定すべき、極限のネットワーク最適化パラメータを /etc/sysctl.d/99-network-performance.conf として以下に示す。
# ==========================================
# Linuxカーネル ネットワーク・TCP チューニング
# ==========================================
# 1. TIME_WAIT ソケットの迅速な再利用(ポート枯渇防止)
# 高頻度で外部APIとコネクションを張るワーカーノードにおいて、TIME_WAIT状態のソケットを再利用可能にする
net.ipv4.tcp_tw_reuse = 1
# 2. ローカルポート範囲の拡張(NAT経由のコネクション数上限を引き上げる)
# デフォルトよりも利用可能なエフェメラルポートの範囲を広げ、NAPTのポート枯渇リスクを最小化
net.ipv4.ip_local_port_range = 1024 65535
# 3. TCPウィンドウのスケーリングとバッファサイズの拡大
# 高帯域・高遅延(BDP: Bandwidth-Delay Product)環境を見据えたTCPバッファの動的チューニング
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 4. TCPシン・クッキー(SYN Cookies)の有効化
# SYNフラッド攻撃への耐性を持ちつつ、パケットロスに対する耐性を高める
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
# 5. コネクションプーリングとKeep-Aliveの最適化
# 毎回TLSハンドシェイクが発生するコストを抑えるため、TCP Keep-Aliveを早期に検知して再接続させる
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5
これらのパラメータを適用することで、NATゲートウェイ配下で稼働するクライアントアプリケーションのTCPコネクション効率が劇的に向上し、RTT(往復遅延時間)の削減とスループットの安定化が同時に手に入る。
—
5. セキュリティと監視:ルーティングの「サイレント障害」を検知する
最後に、アーキテクチャの堅牢性とセキュリティの話に触れておこう。
AZローカルルーティングを徹底するということは、「あるAZのNATゲートウェイがダウンした際、他のAZのNATへ自動的にフェイルオーバーさせない(あるいはクロスAZのフォールバックを意図的に遮断する)」設計に近づくケースがある。冗長性をどう担保するかは議論が分かれるところだが、一般的には 「各AZに独立したNATゲートウェイを配置し、障害時はAZ内のトラフィックが一時的に停止(あるいはマルチパスで制御)」 というトレードオフを選択することが多い。
ここで恐ろしいのが、「設定ミスやIaCの適用漏れにより、知らぬ間にクロスAZトラフィックが再発している状態(サイレントなコスト肥大)」 だ。
これを検知するためには、クラウドプロバイダーのネットワークフローログ(AWSならVPC Flow Logs)をAmazon AthenaやBigQueryに取り込み、次のようなSQLで「送信元サブネットのAZ」と「宛先NAT GatewayのAZ」のミスマッチを常時監視するアラートパイプラインを構築しておくべきだ。
-- VPC Flow LogsからクロスAZトラフィック(コスト発生源)を検知するクエリ例
SELECT
day,
source_subnet_az,
destination_nat_az,
SUM(bytes) / 1024 / 1024 / 1024 AS total_gb
FROM
vpc_flow_logs
WHERE
traffic_type = 'REJECT' OR traffic_type = 'ACCEPT'
-- 自AZ以外へのNAT通信を抽出
AND source_subnet_az != destination_nat_az
GROUP BY 1, 2, 3
ORDER BY total_gb DESC;
このような監視の仕組みをDevOpsのパイプラインに組み込んで初めて、「真に最適化されたクラウドネットワーク」が完成する。
—
結びにかえて
クラウドのネットワーク設計は、単に「通信ができること(Connectivity)」を確認して終わりではない。パケットがどの物理経路を通り、どのレイヤーでどのようなコストとレイテンシの代償を払っているのかを解像度高く把握することこそが、SREやテックリードに求められる本質的なスキルだ。
AZローカルルーティングの徹底は、毎月のクラウド請求書の桁を一つ減らすポテンシャルを秘めているだけでなく、パケットの往復経路を最短化し、システム全体の応答性能を底上げする強力な特効薬となる。
あなたのインフラストラクチャのルートテーブルを今すぐ開き、パケットの「正しい故郷」を指し示してあげよう。
コメント