AWSが提供するNAT Gatewayは、プライベートサブネットにあるサーバーなどのリソースがインターネットに接続するために必要な仕組みです。今回は、このNAT Gatewayに「セカンダリIPアドレス」を追加する方法と、セカンダリIPの基礎を解説します。
NAT GatewayにセカンダリIPアドレスを追加することで同時接続数を引き上げることが可能となるため、規模の大きなサービスに必要な機能となります。ぜひ一緒に学んでいきましょう。
NAT Gatewayとは
NAT Gatewayは、AWSが提供するマネージドサービスで、NAT(Network Address Translation)の仕組みを実現します。
NATは一般的に、グローバルIPアドレスとプライベートIPアドレスを変換する技術を指します。
NAT GatewayはこのNATの仕組みをAWS上で実現し、プライベートサブネット内にあるリソースがインターネットに接続する際、プライベートIPアドレスをパブリックIPアドレスに変換する役割を果たします。
NATの仕組みに関しては以下の記事で解説しています。
https://envader.plus/article/15
セカンダリIPアドレスとは
セカンダリIPアドレスとは、プライマリIPアドレスに追加するIPアドレスで、主に通信の分散や同時接続数を増やす目的で使用します。このセカンダリIPアドレスをNAT Gatewayに追加することで、特定のIPアドレス、ポート番号、プロトコルの組み合わせに対しての同時接続数を増やすことができます。
「特定のIPアドレスに対して」の通信でも、ポート番号、プロトコルが異なる場合には別の接続としてみなされます。
NAT Gatewayは、1つのIPアドレスで55,000の同時接続をサポートし、1つのプライマリIPアドレスと7つのセカンダリIPアドレス、合計8つのIPアドレスをNAT Gatewayに関連づけることで同時接続の制限を440,000まで引き上げることが可能になります。
なぜセカンダリIPアドレスが必要なのか
NAT Gatewayが処理できる同時接続数には限界があります。先述したように1つのIPアドレス(Elastic IP)で最大55,000の同時接続が可能ですが、大量の通信が発生する環境ではこの55,000という制限を超えてしまうことが考えられます。
例として大規模の顧客を抱えるサービスでは、セールの時期など注目度が高いコンテンツであれば大量のユーザーが一気にアクセスしてくることが予想されます。このような時に、レスポンスが遅い、サイトにアクセスできないなどの障害が発生する可能性があります。
セカンダリIPアドレスを追加することで、同時接続数の上限を引き上げてユーザー影響が発生しないよう対策することが可能になります。
同時接続数の上限を超えた場合
特定の宛先に対しての同時接続数が上限を超えた場合、その宛先への新しい接続は失敗します。
https://repost.aws/ja/knowledge-center/vpc-resolve-port-allocation-errors
この現象が発生した時には、NAT GatewayメトリクスのErrorPortAllocation
とPacketsDropCount
の値が上昇するため、CloudWatchメトリクスでどの時間帯にどのくらい発生していたのかを確認することが可能です。
NAT ゲートウェイの CloudWatch メトリクスであるErrorPortAllocationとPacketsDropCountを使用して、NAT ゲートウェイがポート割り当てエラーを生成しているかどうか、またはパケットをドロップしているかどうかを判断できます。
AWS公式ドキュメントより引用
NAT GatewayにセカンダリIPを追加することで、このポート割り当てエラーを解消することができます。
AWS CLIでセカンダリIPアドレスを追加する方法
セカンダリIPアドレスを追加するには、AWSコンソール、AWS CLI、Terraformを使用して追加する方法があります。
AWSコンソールでの追加方法は公式ドキュメントのセカンダリ IP アドレスの関連付けを編集するにありますのでそちらを参照ください。
AWS CLIでは、次の順番でセカンダリIPを追加します。
前提条件
NAT Gateway、Elastic IPアドレスはすでに作成していることを前提にコマンドを解説します。まだ作成していない場合は、以下の記事を参考に作成しましょう。
https://envader.plus/article/450
AWS CLIコマンドを実行する
AWS CLIでNAT GatewayにセカンダリIPを追加するにはElastic IPのallocation id情報が必要になるため、次のコマンドを実行し結果を控えておきます。
aws ec2 describe-addresses
続いてNAT Gatewayの情報を取得し、結果を控えます。
aws ec2 describe-nat-gateways --query 'NatGateways[*].NatGatewayId' --output text
最後に、NAT GatewayにセカンダリIPを追加します。
aws ec2 associate-nat-gateway-address --nat-gateway-id nat-xxxxxxxxxxx --allocation-ids eipalloc-xxxxxxxxxx
以下コマンドでNAT Gatewayを確認し、セカンダリIPの追加状況を確認します。JSON形式で出力されるため、"NatGatewayAddresses"
の中に"PublicIp"
が2つ存在していることを確認します。
aws ec2 describe-nat-gateways
{ "CreateTime": "2024-08-22Txx:38:41+00:00",
"NatGatewayAddresses": [
{.........
"PublicIp": "52.192.10.12",
.........
"PublicIp": "3.115.70.244",
.........
セカンダリIPを追加するときの注意点
AWSコンソールからNAT GatewayにElastic IPを追加する場合、すでにNAT Gatewayが作成されている必要があります。新規作成の場合、セカンダリIPを追加する項目は表示されないため注意が必要です。
また、NAT GatewayにセカンダリIPを追加することでの追加料金の明記はされておりませんが、追加のElastic IPに対しては料金が発生します。仮にセカンダリIPを上限の7個追加した場合、7個分のElastic IP追加料金が発生することは認識しておきましょう。
https://aws.amazon.com/jp/vpc/pricing/
TerraformでNAT GatewayにセカンダリIPを追加する
TerraformでNAT GatewayにセカンダリIPを追加するためには、AWSプロバイダーのバージョンを5.10.0
以上に上げる必要があります。これ以下のバージョンではサポートされていないため、Terraformで管理できません。
https://github.com/hashicorp/terraform-provider-aws/issues/29471
TerraformでNAT GatewayにセカンダリIPを追加する際の注意点
筆者がハマったことをお伝えします。
2024年8月時点で、既存のNAT GatewayにTerraformを使用してセカンダリIPをアタッチしようとすると、NAT Gatewayを新しく作り直される挙動になります。この現象はまだ改善されていないため、NAT Gatewayが再作成されてしまうのを防ぎたい場合には、AWS CLIやコンソールからセカンダリIPを追加し、その後にTerraformコードを追従するよう進めた方が良いでしょう。
https://github.com/hashicorp/terraform-provider-aws/issues/33964
プロバイダーバージョンを確認する
versions.tf
などでプロバイダーバージョンを管理している場合はバージョンを確認し、必要であれば修正します。
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.10.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
プロバイダーバージョンを変更した際には、terraform init
コマンドを忘れずに実行します
terraform init
セカンダリIPを追加する
TerraformでセカンダリIPを追加するには、aws_nat_gateway
リソースにsecondary_allocation_ids
を追加します。
data "aws_eip" "nat_eip" {
id = "eipalloc-040f9f4f82958bd51"
}
resource "aws_nat_gateway" "nat_gateway" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public.id
secondary_allocation_ids = [data.aws_eip.nat_eip.id] # ここを追加
tags = {
Name = "nat-gateway"
}
depends_on = [aws_eip.nat]
}
今回はdataリソースを使って、すでにあるElastic IPを取得しセカンダリIPとして追加しています。
以下コード全体です。
locals {
vpc = {
cidr_block = "10.0.0.0/16"
subnet_cidr = "10.0.10.0/24"
subnet_cidr_private = "10.0.20.0/24"
}
}
data "aws_eip" "nat_eip" {
id = "eipalloc-040f9f4f82958bd51"
}
# vpc
resource "aws_vpc" "main" {
cidr_block = local.vpc.cidr_block
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "main"
}
}
# subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = local.vpc.subnet_cidr
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true
tags = {
Name = "public"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = local.vpc.subnet_cidr_private
availability_zone = "ap-northeast-1a"
tags = {
Name = "private"
}
}
# RouteTable
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
tags = {
Name = "public"
}
}
# RouteTableAssociation
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# InternetGateway
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "igw"
}
}
# Route
resource "aws_route" "public" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
# private subnetのRouteTable
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
tags = {
Name = "private"
}
}
# private subnetのRouteTableAssociation
resource "aws_route_table_association" "private" {
subnet_id = aws_subnet.private.id
route_table_id = aws_route_table.private.id
}
# private subnetのRoute
resource "aws_route" "private" {
route_table_id = aws_route_table.private.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_gateway.id
}
# Elastic IP
resource "aws_eip" "nat" {
vpc = true
tags = {
Name = "nat-eip"
}
}
# NAT Gateway
resource "aws_nat_gateway" "nat_gateway" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public.id
secondary_allocation_ids = [data.aws_eip.nat_eip.id]
tags = {
Name = "nat-gateway"
}
depends_on = [aws_eip.nat]
}
まとめ
この記事では、NAT GatewayにセカンダリIPアドレスを追加する方法、セカンダリIPアドレスの基礎を解説しました。NAT GatewayにセカンダリIPアドレスを追加することで、同時接続数を大幅に増加させることができます。
AWSのインフラエンジニアであれば押さえておきたい項目になるため、AWS CLIやTerraformを使った設定方法も含め理解しておきましょう。
【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話
プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。
「フリーランスエンジニア」
近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。
「成功する人とそうでない人の違いは何か?」
私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。
比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。
多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、
エンベーダー編集部
エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。
関連記事
2020.02.25
完全未経験からエンジニアを目指す爆速勉強法
USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話
- キャリア・学習法
- エンジニア
2024.10.19
【Terraformハンズオン】Terraformでモジュールを作成してみよう
この記事では、Terraformのモジュールに焦点を当て、記事前半で基本を解説し、後半でEC2、VPCモジュールを作成するハンズオンを行います。
- AWS
- Terraform
- ハンズオン
2024.09.19
【Terraformハンズオン】同期呼び出しのLambda関数をデプロイしてみよう
この記事では、Lambdaの同期呼び出し、非同期呼び出しについて解説し、IaCツールであるTerraformを使って実際にLambda関数をAWSへデプロイする方法を紹介します。
- Terraform
- AWS
2023.07.28
Terraformのinput変数の基本的な定義方法 Variableとは
こちらの記事では、Terraformにおけるinput変数、Variableについて解説します。Terraformとは、IaC(Infrastructure as Code)を実現するための構成管理ツールの一つです。
- インフラエンジニア
- AWS