AWS CloudFormation で VPC とサブネットを作ってみる
こんにちは、Masuyama です。
AWS 上に作成する時に CloudFormation を使うことがありますが、
毎回書き方を忘れては調べての繰り返しになってしまっているので、基本的な構成についてまとめてみます。
今回用意する構成
- VPC x 1
- サブネット x 2
- パブリックサブネット x 1
- プライベートサブネット x 2
- インターネットゲートウェイ x 1
- NAT ゲートウェイ (プライベートサブネット用)
テンプレートファイルの準備
任意のフォルダに yml ファイルを任意の名前で作成していきます。
項目ごとに一つひとつ載せていきますが、一番最後に全文も載せていきますのでご安心ください。
今回はとりあえず cf-vpc-subnet-test.yml という名前にしておきます。
フォーマットバージョンの指定
それではテンプレートファイルを作成していきます。
冒頭ではテンプレートのフォーマットバージョンを指定します。
指定できるのは "2010-09-09" のみですので、そのように書いていきます。
AWSTemplateFormatVersion: 2010-09-09
VPC の設定
次から次へとテンプレートファイルに書き足していきしょう。
テンプレートファイルでは Resources 配下に作りたいリソースや、テンプレート内で一意の名前 (Logical ID)、CIDR Block 等をを設定していきます。
...
Resources:
CfVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.1.0.0/16
Tags:
-
Key: Name
Value: CfVPC
タグ付けも CloudFormation テンプレートファイルの中で指定できます。
サブネットの設定
続いて、先ほど指定した VPC の中にサブネットを 2 つ作っていきます。
一つはパブリックサブネット、もう一つはプライベートサブネットと、よくある構成です。
...
CfPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.1.1.0/24
MapPublicIpOnLaunch: true
VpcId: !Ref CfVPC
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: CfPublicSubnet
CfPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.1.2.0/24
MapPublicIpOnLaunch: false
VpcId: !Ref CfVPC
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: CfPrivateSubnet
新しく出てきたものがいくつかありますが、VpcId 欄の !Ref はとても重要な組み込み関数です。
どの VPC内にサブネットを作成するかを VPC ID で指定しますが、CloudFormation で VPC が作られないと ID は分かりませんよね。
そんな時は、同テンプレート内で設定した Logical ID (リソースの論理ID)を !Ref で参照してあげることで、VPC ID が自動的に当てはまるのです。
なお、!Ref を使用すると参照される側(ここでは VPC)が作成されてからサブネットを作成するといったような、依存関係も自動的に処理されます。
また、MapPublicIpOnLaunch は AWS マネジメントコンソールにおける「パブリックIPv4アドレスの自動割り当てを有効にする」にチェックを入れるかどうかに相当しています。
パブリックサブネットでは true、プライベートサブネットでは false を指定しています。
インターネットゲートウェイ の設定
インターネットゲートウェイ の定義
リソースタイプで指定してあげるだけなので簡単です。
...
CfInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: CfInternetGateway
インターネットゲートウェイy を VPC へアタッチ
上記で作成される インターネットゲートウェイ を CfVPC へアタッチします。
ここでも組み込み関数 !Ref を使って VPC ID と InterngetGateway ID を指定しましょう。
...
AttachCfInternetGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId : !Ref CfInternetGateway
VpcId: !Ref CfVPC
なお、ここで !Ref で CfInterngetGateway を指定しているので、ちゃんとインターネットゲートウェイ が作成されてからアタッチの動作を行ってくれます。
インターネットへのルート設定(パブリックサブネット)
続いてルートを準備していきます。まずはパブリックサブネット側からです。
ルートテーブルの作成(パブリックサブネット)
リソースタイプを指定してあげるだけなので簡単です。
...
CfRouteTableForPublicSubnet:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref CfVPC
Tags:
- Key: Name
Value: CfRouteTableForPublicSubnet
ルートの定義(パブリックサブネット)
上記で作成するルートテーブルを !Ref で指定しつつ、デフォルトゲートウェイ 0.0.0.0/0 の宛先としてインターネットゲートウェイを指定します。
...
CfRouteForPublicSubnet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref CfRouteTableForPublicSubnet
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref CfInternetGateway
ルートテーブルとサブネットの紐付け(パブリックサブネット)
上記で作成したルートテーブルはどのサブネットにも紐付いていないので、ルートテーブルとパブリックサブネットを紐づけてあげます。
...
CfAssocciateRouteTableForPublicSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref CfRouteTableForPublicSubnet
SubnetId: !Ref CfPublicSubnet
インターネットへのルートの設定(プライベートサブネット)
プライベートサブネットに置いてあるサーバがアップデート等のためにインターネットに出る必要がある場合を想定します。
ただし、プライベートサブネットは直接インターネットには出さず、NAT ゲートウェイ経由で出るようにします。
NAT ゲートウェイ用 Elasic IP の設定
NAT ゲートウェイに割り当てる Elasic IP を確保します。
...
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NAT ゲートウェイの作成
先ほど指定した Elastic IP を設定しつつ、パブリックサブネット内に NAT ゲートウェイを作成します。
...
CfNatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- NatGatewayEIP
- AllocationId
SubnetId: !Ref CfPublicSubnet
Tags:
- Key: Name
Value: CfNatGateway
ルートテーブルの作成(パブリックサブネット)
パブリックサブネットの時と同じく、リソースタイプを指定してあげるだけです。
...
CfRouteTableForPrivateSubnet:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref CfVPC
Tags:
- Key: Name
Value: CfRouteTableForPrivateSubnet
ルートの定義(プライベートサブネット)
プライベートサブネットのデフォルトゲートとして、上記で設定した NAT ゲートウェイを指定します。
Ref! での参照の仕方などはパブリックサブネットと同じで、NAT ゲートウェイの Logical ID を参照してあげます。
...
CfRouteForPrivateSubnet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref CfRouteTableForPrivateSubnet
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref CfNatGateway
ルートテーブルとサブネットの紐付け(プライベートサブネット)
こちらもパブリックサブネットの時と同じく、ルートテーブルとルートを紐付けてあげます。
...
CfAssocciateRouteTableForPrivateSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref CfRouteTableForPrivateSubnet
SubnetId: !Ref CfPrivateSubnet
テンプレートファイルの全文
テンプレートファイルはここまでですので、全文として再掲しておきます。
AWSTemplateFormatVersion: 2010-09-09
Resources:
CfVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.1.0.0/16
Tags:
-
Key: Name
Value: CfVPC
CfPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.1.1.0/24
MapPublicIpOnLaunch: true
VpcId: !Ref CfVPC
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: CfPublicSubnet
CfPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.1.2.0/24
MapPublicIpOnLaunch: false
VpcId: !Ref CfVPC
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: CfPrivateSubnet
CfInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: CfInternetGateway
AttachCfInternetGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId : !Ref CfInternetGateway
VpcId: !Ref CfVPC
CfRouteTableForPublicSubnet:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref CfVPC
Tags:
- Key: Name
Value: CfRouteTableForPublicSubnet
CfRouteForPublicSubnet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref CfRouteTableForPublicSubnet
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref CfInternetGateway
CfAssocciateRouteTableForPublicSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref CfRouteTableForPublicSubnet
SubnetId: !Ref CfPublicSubnet
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
CfNatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- NatGatewayEIP
- AllocationId
SubnetId: !Ref CfPublicSubnet
Tags:
- Key: Name
Value: CfNatGateway
CfRouteTableForPrivateSubnet:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref CfVPC
Tags:
- Key: Name
Value: CfRouteTableForPrivateSubnet
CfRouteForPrivateSubnet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref CfRouteTableForPrivateSubnet
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref CfNatGateway
CfAssocciateRouteTableForPrivateSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref CfRouteTableForPrivateSubnet
SubnetId: !Ref CfPrivateSubnet
CloudFormation のテスト
スタックの作成
ではいよいよコンソールからテンプレートファイルをアップロードし、CloudFormation でリソースを作成していきましょう。
CloudFormation のコンソールに移動し [スタックの作成] を選択します。
選択したら [新しいリソースを使用(標準)] を選択します。
画面に指示に従い、テンプレートファイルをアップロードします。
次の画面で任意のスタック名を指定します。
このテンプレートファイルで作成される リソースのセット を識別する名前となります。
次の画面で詳細な設定をできます。
タグ、IAM ロールなどを個別に設定できますが、今回はテストですので空欄のままで次へ進んでいただいて問題ありません。
最後に確認画面が出ますので [スタックの作成] を選択します。
スタックの作成開始後
作成が開始されるとステータスが更新され、リソースが自動的にどんどん作られていきます。
(記述ミスなどによりリソースが作成できなかった場合には、自動ですべてのリソースが削除されてロールバックしますのでご安心ください)
画面右側の円環矢印(タブ内の更新ボタン)を押すとリソースの作成状況が更新されていき、
最終的に指定したスタック名、つまりスタックが CREATE_COMPLETE となれば作成は完
了です。
[リソース] タブ内からも作成されたリソースが一覧で表示されていますが、もちろん各サービスのコンソールからでも確認できます。
例えば VPC は、指定したタグ Name で作成されていることを確認できます。
スタックの削除
テストが終わったら、余計な料金がかからないようにリソースを削除しておきましょう。
CloudFormation で作られたリソースは、スタックという一つのセットになっているので一括で削除することもできるので便利です。
CloudFormation のコンソール画面から [削除] を選択すれば、今回テストで作ったリソースを全部削除することができます。
まとめ
一つひとつのリソースをコードで管理できるようになることは工程を楽にするだけでなく、リソースの設定や構成を誰がみても理解できるようにする上で非常に重要なので、活用していきたいですね。
今回は IP アドレスは固定値にしていましたが、スタック作成時にコンソールで入力させるようにもできます。
また、タグについても固定値でしたが、例えばバージョン名などを入力して一括で毎回少しずつ変更することもできますので、そのあたりも別な機会に紹介します。
Discussion
のタグのvalueについてですがCfPrivateSubnetではなく、CfPublicSubnetが正しいと思います
ありがとうございます!
ご指摘の通りでしたので修正いたしました。
AZのハードコーディングをAWSは推奨してないとのことですので以下のコード例のようにAZをGetAZ配列内から取得できるようにすべきだと思います
こちらもアドバイスありがとうございます。
勉強になりましたm(_ _)m