この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。
みなさんこんにちは。
おでんの美味しい季節がやってきましたね。
筆者は最近初めてCloudFormation(以下CFnと略)を利用してみました。
そこで本記事は備忘録として、あわよくば誰かの参考になればと思い執筆しました。
はじめに
テンプレート管理のベストプラクティスとしては、一つのテンプレートにすべてのリソースを記述して管理するのではなく、レイヤとライフサイクルを観点にリソース(スタック)を分割してテンプレートを管理するようです。
参考:[AWS Black Belt Online Seminar] AWS CloudFormation 資料及び QA 公開
https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-cloudformation-2020/
そこで、今回のハンズオンはベストプラクティスに則り、最も依存度の低いネットワークレイヤのテンプレートを作成することで、今後さらに上位のレイヤのテンプレートを作成してくための土台作りを行うという事始め的位置づけとなります。
構成
本記事で構築するスタックは以下のような構成となります。
- 可用性のためにマルチアベイラビリティゾーン構成
- Public-SubnetはInternet gatewaysを経由してインターネットにアクセス
- Private-SubnetはNAT gatewaysを経由してインターネットにアクセスしつつ、インターネットからのインバウンドトラフィックは遮断してセキュリティを保つ
- NAT gatewaysは単一のAZ障害に対する可用性を確保するため、マルチアベイラビリティゾーンで配置
[構成図]
templateの作成
公式ドキュメントの参照
今回は公式ドキュメントを参照しながらテンプレートを作成していきました。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html
テンプレートリファレンス -> リソースとプロパティのリファレンス
今回必要だったネットワーク関連のリソースは"Amazon EC2"配下にリファレンスのページがありました。泥臭いやり方ですが、ブラウザで’ctrl+F’で必要なリソース名を検索してそのページに飛んだりしてサンプルコードと説明を読みtemplateを作成していきました。
テンプレート
実際にテンプレートを作成したものが以下です。
※もし、以下のテンプレートをご使用になる場合について、テンプレートはそのままお使いいただけるはずですが、お使いのアカウントの環境次第ではVPCの上限数やCidrの競合などが理由でスタック作成に失敗するかもしれません。ご注意ください。また、NAT Gatewaysは料金が発生しますので検証などでお使いになられた後、不要になりましたらスタックの削除をお忘れなきようお願いします。
AWSTemplateFormatVersion: "2010-09-09"
Description: Network resources
Resources:
# ----------------------------------------------------------------------------#
# VPC
# ----------------------------------------------------------------------------#
# create VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: "true"
EnableDnsSupport: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: cfn-tom-vpc
# ----------------------------------------------------------------------------#
# subnet
# ----------------------------------------------------------------------------#
# create Public SubnetA
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: 10.0.0.0/24
VpcId: !Ref VPC
Tags:
- Key: Name
Value: cfn-tom-public-subnetA
# create Public SubnetC
PublicSubnetC:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: 10.0.1.0/24
VpcId: !Ref VPC
Tags:
- Key: Name
Value: cfn-tom-public-subnetC
# create Private SubnetA
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: 10.0.2.0/24
VpcId: !Ref VPC
Tags:
- Key: Name
Value: cfn-tom-private-subnetA
# create Private SubnetC
PrivateSubnetC:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: 10.0.3.0/24
VpcId: !Ref VPC
Tags:
- Key: Name
Value: cfn-tom-private-subnetC
# ----------------------------------------------------------------------------#
# internet gateway
# ----------------------------------------------------------------------------#
# create Internet Gateway
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: cfn-tom-internet-gateway
# ----------------------------------------------------------------------------#
# attaches an internet gateway to a VPC
# ----------------------------------------------------------------------------#
# create Attachment
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref IGW
VpcId: !Ref VPC
# ----------------------------------------------------------------------------#
# ElasticIP for NatGateway
# ----------------------------------------------------------------------------#
# create ElasticIP1
EIP1:
Type: AWS::EC2::EIP
DependsOn: VPCGatewayAttachment
Properties:
Domain: vpc
Tags:
- Key: Name
Value: cfn-tom-EIP1
# create ElasticIP2
EIP2:
Type: AWS::EC2::EIP
DependsOn: VPCGatewayAttachment
Properties:
Domain: vpc
Tags:
- Key: Name
Value: cfn-tom-EIP2
# ----------------------------------------------------------------------------#
# NatGateway
# ----------------------------------------------------------------------------#
# create NatGatewayA
NatGatewayA:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIP1.AllocationId
SubnetId: !Ref PublicSubnetA
Tags:
- Key: Name
Value: cfn-tom-NatGatewayA
# create NatGatewayC
NatGatewayC:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIP2.AllocationId
SubnetId: !Ref PublicSubnetC
Tags:
- Key: Name
Value: cfn-tom-NatGatewayC
# ----------------------------------------------------------------------------#
# route table
# ----------------------------------------------------------------------------#
# create Public RouteTable
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: cfn-tom-public-route-table
VpcId: !Ref VPC
# create Private RouteTableA
PrivateRouteTableA:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: cfn-tom-private-route-tableA
VpcId: !Ref VPC
# create Private RouteTableC
PrivateRouteTableC:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: cfn-tom-private-route-tableC
VpcId: !Ref VPC
# ----------------------------------------------------------------------------#
# add route
# ----------------------------------------------------------------------------#
# PublicRoute
PublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
RouteTableId: !Ref PublicRouteTable
# PrivateRouteA
PrivateRouteA:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayA
RouteTableId: !Ref PrivateRouteTableA
# PrivateRouteC
PrivateRouteC:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayC
RouteTableId: !Ref PrivateRouteTableC
# ----------------------------------------------------------------------------#
# Association of Route Tables with subnets
# ----------------------------------------------------------------------------#
# Public SubnetA
AssociationWithPublicSubnetA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetA
# Public SubnetC
AssociationWithPublicSubnetC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetC
# Private SubnetA
AssociationWithPrivateSubnetA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableA
SubnetId: !Ref PrivateSubnetA
# Private SubnetC
AssociationWithPrivateSubnetC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableC
SubnetId: !Ref PrivateSubnetC
スタックの作成
CloudFormationを検索して開きます。
スタック -> スタックの作成 -> 新しいリソースを使用(標準)
テンプレートの準備完了 -> テンプレートファイルのアップロード -> (ファイルをアップロードしたら)次へ
今回、テンプレートでパラメータは定義していないためパラメータなしと表示されます。
そのまま任意のスタック名を入力 -> 次へ
スタックオプションの設定はデフォルトのまま次へ(画像省略)
レビューも問題なければそのまま送信を押してください(画像省略)
以下のような画面に遷移するかと思います。
イベントタブで各リソースのステータスが時系列(降順)で表示されます。
以下の画像のように、左側のスタックのステータスが"CREATE_COMPLETE"と表示になったら作成成功です。
不要になった場合は、右上の"削除"からリソースを丸ごと削除できます。
テンプレートで作成したリソースは基本的にテンプレートで管理するため手動で削除や変更などしないようにします。
※手動でリソースを変更してしまった場合にドリフト検出という機能が使えるそうで、詳しい機能についてはまた検証します。
課題
実は今回のテンプレートでは、Outputsセクションを記述できていません。Outputsセクションによって出力した値は別のテンプレートから参照することができるため、次回はこのOutputsセクションを今回のテンプレートに追加するところから行っていきたいと考えています。
また、そのほかにもMetadataセクションやParameterLabelsセクションを記述していません。これらは、ユーザからの入力を受け付けることでテンプレートにより柔軟さを持たせることができるらしく、次は利用してみようと思います。
おわりに
また次回お会いしましょう!!