こんにちは!クラウドの世界へようこそ。インフラやネットワークの世界って、最初は専門用語が多くて「なんだか難しそう……」と感じてしまいますよね。でも、一歩ずつ身近な例に置き換えて見ていくと、実は私たちの日常生活とすごく似た仕組みで動いていることが分かります。
今回は、AWSなどのパブリッククラウドを使っていると、ふと請求書を見て「おやっ?」と驚く原因になりがちな「クロスAZトラフィックのコスト」と、その対策である「NATゲートウェイの配置戦略」について、おしゃべりするようにお話ししていきますね。
一緒に、パケットたちの旅をのぞいてみましょう!
—
1. そもそも「AZ」と「NATゲートウェイ」ってなに?
クラウドの世界では、システムが突然の地震や雷などの災害で止まってしまわないように、物理的に離れた複数のデータセンターにサーバーを分散させます。このデータセンターの単位をAWSではAZ(アベイラビリティゾーン)と呼びます。東京ドーム何個分もあるような巨大な施設が、少し離れた場所で複数セット用意されているイメージです。
そして、プライベートな空間(インターネットから直接アクセスできない安全なエリア)にいるサーバーたちが、ソフトウェアのアップデートや外部APIの呼び出しのために、こっそり外のインターネットへお使いに出かけるときの「通関窓口」の役割をしてくれるのがNATゲートウェイ(NAT Gateway)です。
郵便局に例えてみましょう
ちょっと身近な例で考えてみましょう。
- AZ-A と AZ-B:それぞれ「渋谷郵便局」と「新宿郵便局」です。
- プライベートサブネットのサーバー:その郵便局の管轄エリアに住む住民たちです。
- NATゲートウェイ:海外へ荷物を送るための「国際郵便の窓口」です。
本来なら、渋谷(AZ-A)に住んでいる人は、歩いてすぐの渋谷郵便局(AZ-AのNATゲートウェイ)から海外へ荷物を送りたいですよね。
—
2. なぜ「クロスAZトラフィックコスト」が発生するのか?
ここで、クラウド特有の「ちょっぴり意地悪なルール」が登場します。
もし、あなたが渋谷(AZ-A)に住んでいるのに、わざわざ電車賃(データ転送量のお金)を払って、遠く離れた新宿郵便局(AZ-BのNATゲートウェイ)まで荷物を持ち込んで海外へ送ったらどうなるでしょうか?
クラウドの世界では、「あるAZにあるサーバーが、別のAZにあるNATゲートウェイを経由してインターネットへ通信する」と、AZの壁をまたいだ瞬間にお金(Cross-AZ Data Transferの費用)が発生してしまうのです。
コスト爆発のシナリオ
初学者のうちは、「インターネットに出るだけなんだから、どこから出ても一緒でしょ?」と思いがちです。しかし、次のような設計ミス(あるいはデフォルト設定のまま放置)をしていると、月末の請求書を見て青ざめることになります。
1. 予算や手間の都合で、NATゲートウェイを AZ-A にしか置かなかった。
2. アプリケーションのサーバーは、高可用性(耐障害性)のために AZ-A と AZ-B の両方にたくさん配置した。
3. 結果として、AZ-B にいるサーバーたちがインターネットと通信するとき、わざわざ交通費(クロスAZ転送費)を払って、遠くの AZ-A のNATゲートウェイまでパケットを長旅させることになった。
この「見えない交通費」が、サーバーの台数や通信量が増えるにつれて雪だるま式に膨れ上がってしまうのです。これが、私たちが頭を悩ませるクロスAZトラフィックコストの正体です。
—
3. 解決策:すべてのAZにNATゲートウェイを置く「AZローカルルーティング」
この問題を解決する王道かつ最強の戦略が、「AZローカルルーティング(AZ閉塞型ルーティング)」です。
やり方はとてもシンプル。「自分のAZにあるNATゲートウェイを使いなさい!」というルールを、それぞれのAZの住民(サブネット)に徹底させるだけです。
AZ-Aのサーバー ➔AZ-AのNATゲートウェイを使うAZ-Bのサーバー ➔AZ-BのNATゲートウェイを使う
郵便局の例えなら、「自分の街の郵便局を使いましょうね」という当たり前のルールに戻すだけですね。これで、AZの壁をまたぐ無駄な交通費(クロスAZコスト)をきれいにゼロに抑えることができます。
—
4. 実践!TerraformでスマートなマルチAZ・NAT配置を構築する
「理屈は分かったけれど、実際にどうやって設定するの?」という方のために、インフラをコードで管理するツールである Terraform の設定サンプルを見てみましょう。
ここでは、AZ-A と AZ-B のそれぞれにサブネットを作り、それぞれ専用のNATゲートウェイを配置する美しい構成をコードに落とし込んでみます。
# =====================================================================
# 1. ネットワーク(VPC)の土台作り
# =====================================================================
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "cost-optimized-vpc"
}
}
# =====================================================================
# 2. パブリックサブネット(インターネットの出入り口)の作成
# =====================================================================
# AZ-A用のパブリックサブネット
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a" # 東京リージョン AZ-A
tags = { Name = "public-subnet-a" }
}
# AZ-B用のパブリックサブネット
resource "aws_subnet" "public_b" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-1c" # 東京リージョン AZ-C (実質的なAZ-B)
tags = { Name = "public-subnet-b" }
}
# =====================================================================
# 3. 弹性IP(EIP)とNATゲートウェイの「AZ別」配置
# =====================================================================
# AZ-A専用のEIPとNATゲートウェイ
resource "aws_eip" "nat_a" {
domain = "vpc"
tags = { Name = "eip-nat-a" }
}
resource "aws_nat_gateway" "nat_a" {
allocation_id = aws_eip.nat_a.id
subnet_id = aws_subnet.public_a.id
tags = { Name = "nat-gateway-a" } # AZ-Aに常駐
}
# AZ-B専用のEIPとNATゲートウェイ
resource "aws_eip" "nat_b" {
domain = "vpc"
tags = { Name = "eip-nat-b" }
}
resource "aws_nat_gateway" "nat_b" {
allocation_id = aws_eip.nat_b.id
subnet_id = aws_subnet.public_b.id
tags = { Name = "nat-gateway-b" } # AZ-Bに常駐
}
# =====================================================================
# 4. プライベートサブネットと「ローカル専用」ルートテーブルの作成
# =====================================================================
# --- AZ-A プライベート側 ---
resource "aws_subnet" "private_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.10.0/24"
availability_zone = "ap-northeast-1a"
tags = { Name = "private-subnet-a" }
}
resource "aws_route_table" "private_a" {
vpc_id = aws_vpc.main.id
# AZ-Aのサーバーからの通信は、必ず「AZ-AのNATゲートウェイ」へ流す!
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_a.id
}
tags = { Name = "rt-private-a" }
}
resource "aws_route_table_association" "asso_a" {
subnet_id = aws_subnet.private_a.id
route_table_id = aws_route_table.private_a.id
}
# --- AZ-B プライベート側 ---
resource "aws_subnet" "private_b" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.20.0/24"
availability_zone = "ap-northeast-1c"
tags = { Name = "private-subnet-b" }
}
resource "aws_route_table" "private_b" {
vpc_id = aws_vpc.main.id
# AZ-Bのサーバーからの通信は、必ず「AZ-BのNATゲートウェイ」へ流す!
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_b.id
}
tags = { Name = "rt-private-b" }
}
resource "aws_route_table_association" "asso_b" {
subnet_id = aws_subnet.private_b.id
route_table_id = aws_route_table.private_b.id
}
このコードのポイントは、aws_route_table をAZごとに完全に独立させている点です。これにより、パケットは自分がいるAZの中で綺麗に完結し、無駄なクロスAZ料金の発生を防ぐことができます。
—
5. コスト効率と耐障害性のトレードオフ(現場の知恵)
「ちょっと待って! じゃあマルチAZ構成にするたびに、すべてのAZにNATゲートウェイを置かなきゃいけないの? NATゲートウェイ自体にも固定費(時間単位の料金)がかかるよね?」
その通り! ここが現場のSREとしての腕の見せどころであり、頭を悩ませるジレンマです。
- NATゲートウェイの固定費:1つあたり、だいたい月数千円〜(リージョンによりますが)の基本料金がかかります。
- クロスAZデータ転送費:データ量が多いシステムほど、高額になります。
現場でどう判断すべき?
1. 小規模・開発環境の場合
- トラフィック量が少ないため、クロスAZのデータ転送量も大した額になりません。むしろNATゲートウェイをあちこちに立てる固定費のほうが高くつくことがあるため、あえて「NATゲートウェイは1つだけ」にしてコストを抑える判断もアリです。
2. 大規模・本番環境の場合
- 外部との通信量が爆発するシステムや、マイクロサービスでコンテナが頻繁に外部と通信する環境では、クロスAZ料金のほうが圧倒的に高くつきます。迷わずすべてのAZ(通常は3AZなど)にNATゲートウェイを配置し、AZローカルルーティングを徹底しましょう。
さらに、万が一あるAZのNATゲートウェイが壊れたとき(まれに障害が起きます)に備えて、クロスAZの通信フォールバックを組む高度なルーティング設計もありますが、まずは基本の「各AZに1つずつ配置して、自分のところを通るようにする」をマスターすることが第一歩です。
—
まとめ
今回は、インフラ初学者の方向けに、クロスAZトラフィックコストとNATゲートウェイの配置戦略について紐解いてみました。
- クロスAZコスト:パケットが別のAZへお出かけすると発生する「見えない交通費」のこと。
- 対策:各AZにNATゲートウェイを配置し、自分のAZ内で通信を完結させる(AZローカルルーティング)。
- 判断基準:システムの規模や通信量に合わせて、NATの固定費とデータ転送費のバランスを見極める。
クラウドネットワークの設計は、パケットの気持ちになって「最短距離で、無駄なお金をかけずに目的地へ行かせてあげられているかな?」と想像してあげることが一番の近道です。
今回の解説が、皆さんの日々のインフラ設計やコスト削減のヒントになればとっても嬉しいです。それでは、また次回の技術ブログでお会いしましょう!
コメント