6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NTTテクノクロスAdvent Calendar 2024

Day 7

【AWS】 NAT GatewayをCloudFormationでスケーリングする

Last updated at Posted at 2024-12-06

NTTテクノクロス Advent Calendar 2024 シリーズ2 "7日目"の記事です。

こんにちは。NTTテクノクロスの増田です。
現在2年目のエンジニアで、AWSを用いた業務を行っています。

はじめに

本記事では、AWSのNAT Gatewayにおけるコスト削減のための作業を行ったので、その実施内容や方法などについてご紹介します。

NAT Gatewayとは

NAT Gatewayとは、VPC内に構成したプライベートサブネットからインターネットに接続するためのもので、IPアドレスとポート変換(NAPT)を行ってくれます。

NAT Gatewayのコスト

NAT Gatewayには時間単位料金とデータ処理料金があります。

時間単位料金:1時間あたり0.062USD
データ処理料金:1GBデータあたり0.062USD

NAT Gatewayを配置しているだけで時間単位料金が発生するため、不要なNAT Gatewayを削減する構成の見直しを行い、料金を抑えることにしました。

構成

NAT Gatewayの構成見直し前後の構成を以下に示します。

対処前

Untitled-1.png

対処前は可用性を考慮して異なるAZにNAT Gatewayを3つ配置していましたが、開発環境や検証環境は状況によってはマルチAZ構成が不要であることもあり、コスト節約のため不要時は削除できるように改善しました。

対処後

Untitled3.png

対処後は、CloudFormationを使用して上図のように構成を変更できるようにします。なお、CloudFormationはAWSリソースをコードとして定義し、構築するためのIaC(Infrastructure as Code)ツールです。

なお、ここでは対処後の構成を以下のように定義します。

構成 定義内容
Single構成 全てのAZにおけるルーティングを1つのNAT Gatewayに集約
(NAT Gateway:計1台)
Multipl構成 全てのAZにおいて、NAT Gatewayを配置
(NAT Gateway:計3台)

これにより、通常時はSingle構成の運用で、緊急時にはMultiple構成への切り替えを行うことが可能です。

CloudFormationテンプレート

構成を変更するCloudFormationテンプレートを作成します。

※テンプレート内の "VPC", "Public_Subnet00X", "Private_Subnet00X" の設定値はRefやImportValueなどで補完してください。

1. 構成選択用の環境変数を定義します
 デフォルトではSingle構成にしています

Parameters:
# NAT Gatewayの構成選択用の環境変数を定義
   NATGatewayType:
     Description: "Type of NAT Gateway configuration (single or multiple)"
     Type: String
     AllowedValues:
       - single
       - multiple
	 Default: single

2. Multiple構成の条件を定義します

Conditions:
  UseMultipleNatGateways: !Equals [!Ref "NATGatewayType", "multiple"]

3. NAT GatewayとElastic IPを作成します
 UseMultipleNatGatewaysの条件によって、NAT Gatewayの作成数が変わります

Resources:
  # NATGateway1a Create
  NATGateway1a:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NATGateway1aEIP.AllocationId
      SubnetId: !Ref SubnetPublic1a
      Tags:
        - Key: Name
          Value: !Sub NATGateway1a_Name
  # NATGateway1a For EIP Create
  NATGateway1aEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc
  # NATGateway1c Create
  NATGateway1c:
    Type: AWS::EC2::NatGateway
    # UseMultipleNatGatewaysが true の場合のみ作成
    Condition: "UseMultipleNatGateways"
    Properties:
      AllocationId: !GetAtt NATGateway1cEIP.AllocationId
      SubnetId: !Ref SubnetPublic1c
      Tags:
        - Key: Name
          Value: !Sub NATGateway1c_Name
  # NATGateway1c For EIP Create
  NATGateway1cEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc
  # NATGateway1d Create
  NATGateway1d:
    Type: AWS::EC2::NatGateway
    # UseMultipleNatGatewaysが true の場合のみ作成
    Condition: "UseMultipleNatGateways"
    Properties:
      AllocationId: !GetAtt NATGateway1dEIP.AllocationId
      SubnetId: !Ref SubnetPublic1d
      Tags:
        - Key: Name
          Value: !Sub NATGateway1d_Name
  # NATGateway1d For EIP Create
  NATGateway1dEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc

4. ルートテーブルを作成します

  # PrivateRouteTable1a Create
  PrivateRouteTable1a:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1a_Name
  # PrivateRouteTable1c Create
  PrivateRouteTable1c:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1c_Name
  # PrivateRouteTable1d Create
  PrivateRouteTable1d:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1d_Name

5. NAT Gatewayをルートテーブルへ関連付けます
 UseMultipleNatGatewaysの条件によって、関連付ける対象が変わります

  # Route to NATGateway1a for PrivateRouteTable1a
  Private1aRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1a
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway1a
  # Route to NATGateway1c for PrivateRouteTable1c
  Private1cRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1c
      DestinationCidrBlock: 0.0.0.0/0
      ### UseMultipleNatGatewaysが true の場合 NATGateway1c に、false の場合 NATGateway1a に接続
      NatGatewayId: !If 
        - UseMultipleNatGateways
        - !Ref NATGateway1c
        - !Ref NATGateway1a
  # Route to NATGateway1d for PrivateRouteTable1d
  Private1dRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1d
      DestinationCidrBlock: 0.0.0.0/0
      ### UseMultipleNatGatewaysが true の場合 NATGateway1d に、false の場合 NATGateway1a に接続
      NatGatewayId: !If 
        - UseMultipleNatGateways
        - !Ref NATGateway1d
        - !Ref NATGateway1a

6. プライベートサブネットをルートテーブルへ関連付けます

  # Associate SubnetPrivate1a with PrivateRouteTable1a
  Private1aSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1a
      RouteTableId: !Ref PrivateRouteTable1a
  # Associate SubnetPrivate1c with PrivateRouteTable1c
  Private1cSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1c
      RouteTableId: !Ref PrivateRouteTable1c
  # Associate SubnetPrivate1d with PrivateRouteTable1d
  Private1dSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1d
      RouteTableId: !Ref PrivateRouteTable1d

7. 構築したNAT Gatewayの構成を出力します

Outputs:
  NatGatewayType:
    Description: "The type of NAT Gateway configuration used"
    Value: !Ref "NATGatewayType"

リソースマップ

作成したNat Gatewayを含むVPCのリソースマップを以下に示します。
リソースマップだとSingle構成のルーティングも分かりやすいですね。

Single構成

image.png

Multiple構成

image.png


最後にNo.1~7までを繋げて、VPCやサブネットなどを追加したテンプレート全体を以下に示します。

sample.yaml
AWSTemplateFormatVersion: '2010-09-09'

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  VPCCIDR:
    Description: VPC Cider Block for VPC
    Type: String
  SubnetPublic1aCIDR:
    Description: Public Subnet 1a Cider Block for SubnetPublic1a
    Type: String
  SubnetPublic1cCIDR:
    Description: Public Subnet 1c Cider Block for SubnetPublic1c
    Type: String
  SubnetPublic1dCIDR:
    Description: Public Subnet 1d Cider Block for SubnetPublic1d
    Type: String
  SubnetPrivate1aCIDR:
    Description: Private Subnet 1a Cider Block for SubnetPrivate1a
    Type: String
  SubnetPrivate1cCIDR:
    Description: Private Subnet 1c Cider Block for SubnetPrivate1c
    Type: String
  SubnetPrivate1dCIDR:
    Description: Private Subnet 1d Cider Block for SubnetPrivate1d
    Type: String
  # NAT-GWの構成選択用の環境変数を定義
  NATGatewayType:
    Description: "Type of NAT Gateway configuration (single or multiple)"
    Type: String
    AllowedValues:
      - single
      - multiple
    Default: single
    
# ------------------------------------------------------------#
# Conditions
# ------------------------------------------------------------# 
Conditions:
  UseMultipleNatGateways: !Equals [!Ref "NATGatewayType", "multiple"]

Resources:
# ------------------------------------------------------------#
# VPC, Subnet, IGW
# ------------------------------------------------------------# 
  # VPC Create
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub VPC_Name
  # SubnetPublic1a Create
  SubnetPublic1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: !Ref SubnetPublic1aCIDR
      Tags:
        - Key: Name
          Value: !Sub Public_Subnet1a_Name
  # SubnetPublic1c Create
  SubnetPublic1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: !Ref SubnetPublic1cCIDR
      Tags:
        - Key: Name
          Value: !Sub Public_Subnet1c_Name
  # SubnetPublic1d Create
  SubnetPublic1d:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1d
      CidrBlock: !Ref SubnetPublic1dCIDR
      Tags:
        - Key: Name
          Value: !Sub Public_Subnet1d_Name
  # SubnetPrivate1a Create
  SubnetPrivate1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: !Ref SubnetPrivate1aCIDR
      Tags:
        - Key: Name
          Value: !Sub Private_Subnet1a_Name
  # SubnetPrivate1c Create
  SubnetPrivate1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: !Ref SubnetPrivate1cCIDR
      Tags:
        - Key: Name
          Value: !Sub Private_Subnet1c_Name
  # SubnetPrivate1d Create
  SubnetPrivate1d:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1d
      CidrBlock: !Ref SubnetPrivate1dCIDR
      Tags:
        - Key: Name
          Value: !Sub Private_Subnet1d_Name
  # InternetGateway Create
  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub IGW
  # InternetGateway Attachment to VPC
  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref IGW
      VpcId: !Ref VPC

# ------------------------------------------------------------#
#  NAT Gateway, EIP
# ------------------------------------------------------------#
  # NATGateway1a Create
  NATGateway1a:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NATGateway1aEIP.AllocationId
      SubnetId: !Ref SubnetPublic1a
      Tags:
        - Key: Name
          Value: !Sub NATGateway1a_Name
  # NATGateway1a For EIP Create
  NATGateway1aEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc
  # NATGateway1c Create
  NATGateway1c:
    Type: AWS::EC2::NatGateway
    # UseMultipleNatGatewaysが true の場合のみ作成
    Condition: "UseMultipleNatGateways"
    Properties:
      AllocationId: !GetAtt NATGateway1cEIP.AllocationId
      SubnetId: !Ref SubnetPublic1c
      Tags:
        - Key: Name
          Value: !Sub NATGateway1c_Name
  # NATGateway1c For EIP Create
  NATGateway1cEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc
  # NATGateway1d Create
  NATGateway1d:
    Type: AWS::EC2::NatGateway
    # UseMultipleNatGatewaysが true の場合のみ作成
    Condition: "UseMultipleNatGateways"
    Properties:
      AllocationId: !GetAtt NATGateway1dEIP.AllocationId
      SubnetId: !Ref SubnetPublic1d
      Tags:
        - Key: Name
          Value: !Sub NATGateway1d_Name
  # NATGateway1d For EIP Create
  NATGateway1dEIP: 
    Type: "AWS::EC2::EIP"
    Properties: 
      Domain: vpc

# ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#
  # PublicRouteTable Create
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PublicRouteTable_Name
  # PrivateRouteTable1a Create
  PrivateRouteTable1a:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1a_Name
  # PrivateRouteTable1c Create
  PrivateRouteTable1c:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1c_Name
  # PrivateRouteTable1d Create
  PrivateRouteTable1d:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub PrivateRouteTable1d_Name
  # PublicRoute Create
  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW
  # Route to NATGateway1a for PrivateRouteTable1a
  Private1aRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1a
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway1a
  # Route to NATGateway1c for PrivateRouteTable1c
  Private1cRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1c
      DestinationCidrBlock: 0.0.0.0/0
      ### UseMultipleNatGatewaysが true の場合 NATGateway1c に、false の場合 NATGateway1a に接続
      NatGatewayId: !If 
        - UseMultipleNatGateways
        - !Ref NATGateway1c
        - !Ref NATGateway1a
  # Route to NATGateway1d for PrivateRouteTable1d
  Private1dRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1d
      DestinationCidrBlock: 0.0.0.0/0
      ### UseMultipleNatGatewaysが true の場合 NATGateway1d に、false の場合 NATGateway1a に接続
      NatGatewayId: !If 
        - UseMultipleNatGateways
        - !Ref NATGateway1d
        - !Ref NATGateway1a
  # Associate SubnetPublic1a with PublicRouteTable
  Public1aSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPublic1a
      RouteTableId: !Ref PublicRouteTable
  # Associate SubnetPublic1c with PublicRouteTable
  Public1cSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPublic1c
      RouteTableId: !Ref PublicRouteTable
  # Associate SubnetPublic1d with PublicRouteTable
  Public1dSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPublic1d
      RouteTableId: !Ref PublicRouteTable
  # Associate SubnetPrivate1a with PrivateRouteTable1a
  Private1aSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1a
      RouteTableId: !Ref PrivateRouteTable1a
  # Associate SubnetPrivate1c with PrivateRouteTable1c
  Private1cSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1c
      RouteTableId: !Ref PrivateRouteTable1c
  # Associate SubnetPrivate1d with PrivateRouteTable1d
  Private1dSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPrivate1d
      RouteTableId: !Ref PrivateRouteTable1d
      
# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#    
Outputs:
  NatGatewayType:
    Description: "The type of NAT Gateway configuration used"
    Value: !Ref "NATGatewayType"

まとめ

以上、NAT Gatewayに関する内容をお届けしました。今回ご紹介した運用方法以外にも、未使用時はNAT Gatewayをすべて削除し、必要な時に再配置するなど、さまざまな運用方法が考えられますね。

AWS環境の構築においては、コスト削減は重要なポイントです。今後も対策に取り組みながら、参考になる情報を投稿していければと思います。

明日は @yukimuraki さんの 「綺麗なIAMポリシーを書きたくて」です。明日以降も NTTテクノクロスアドベントカレンダー2024 をお楽しみに!

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?