はじめに
新人であった昨年度、0からAWS基盤構築の経験をさせていただき、マネコン上からAWSのリソースを弄り回していると「あれ?これなんだっけ?いつのバージョンのやつだっけ?」みたいな現象が頻発してました。
やはりGUIは悪でCLIは正義ということを身を以って体感したのでCloudFormation(cfn)の学習を始めました。
今回はcfnの勉強がてらVPCの一般的な基盤構築を行ってみました。
構成図
ご覧の通り、マネコンの「VPCを作成 / VPCなど」で作成できる諸々のリソースを作成します。
RouteTableもマネコン上からはあまり意識しませんが、作成対象のため今回の構成図では明示的に記述しています。
テンプレート
以下先に全文。
AWSTemplateFormatVersion: "2010-09-09"
Description: Create Fargate and ALB
Parameters:
ProjectName:
Type: String
Description: Project Name for all
VPCCiderBlock:
Default: 10.0.0.0/16
Type: String
Description: VPC Cider Block for VPC
PubSub1aCiderBlock:
Default: 10.0.10.0/24
Type: String
Description: Public Subnet 1a Cider Block for PublicSubnet1a
PriSub1aCiderBlock:
Default: 10.0.20.0/24
Type: String
Description: Private Subnet 1a Cider Block for PrivateSubnet1a
PubSub1cCiderBlock:
Default: 10.0.30.0/24
Type: String
Description: Public Subnet 1c Cider Block for PublicSubnet1c
PriSub1cCiderBlock:
Default: 10.0.40.0/24
Type: String
Description: Private Subnet 1c Cider Block for PrivateSubnet1c
Resources:
############################################
#### VPC ####
############################################
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCiderBlock
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub ${ProjectName}-VPC
############################################
#### Subnet ####
############################################
PubSubnet1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PubSub1aCiderBlock
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${ProjectName}-Public-Subnet-1a
PriSubnet1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PriSub1aCiderBlock
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${ProjectName}-Private-Subnet-1a
PubSubnet1c:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: !Ref PubSub1cCiderBlock
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${ProjectName}-Public-Subnet-1c
PriSubnet1c:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: !Ref PriSub1cCiderBlock
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${ProjectName}-Private-Subnet-1c
############################################
#### Route Table ####
############################################
PubRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${ProjectName}-rtb-public
VpcId: !Ref VPC
PriRouteTable1a:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${ProjectName}-rtb-private-1a
VpcId: !Ref VPC
PriRouteTable1c:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${ProjectName}-rtb-private-1c
VpcId: !Ref VPC
############################################
#### Gateway ####
############################################
S3Endpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
RouteTableIds:
- !Ref PriRouteTable1a
- !Ref PriRouteTable1c
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcEndpointType: Gateway
VpcId: !Ref VPC
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${ProjectName}-igw
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref IGW
VpcId: !Ref VPC
# ############################################
# #### NAT Gateway ####
# ############################################
# >>>>>>>> NAT Gatewayが必要な場合 >>>>>>>>>>>>
# NatGatewayEIP:
# Type: AWS::EC2::EIP
# Properties:
# Domain: vpc
# DependsOn: VPC
# NatGateway:
# Type: AWS::EC2::NatGateway
# Properties:
# AllocationId:
# Fn::GetAtt:
# - NatGatewayEIP
# - AllocationId
# SubnetId: !Ref PubSubnet1a
# Tags:
# - Key: Name
# Value: !Sub ${ProjectName}-natgateway
# <<<<<<<<< NAT Gatewayが必要な場合 <<<<<<<<<<<<
############################################
#### Route ####
############################################
PubRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
RouteTableId: !Ref PubRouteTable
# >>>>>>>>> NAT Gatewayが必要な場合 >>>>>>>>>
# PriRoute1a:
# Type: AWS::EC2::Route
# Properties:
# RouteTableId: !Ref PriRouteTable1a
# DestinationCidrBlock: 0.0.0.0/0
# NatGatewayId: !Ref NatGateway
# PriRoute1c:
# Type: AWS::EC2::Route
# Properties:
# RouteTableId: !Ref PriRouteTable1c
# DestinationCidrBlock: 0.0.0.0/0
# NatGatewayId: !Ref NatGateway
# <<<<<<<<<< NAT Gatewayが必要な場合 <<<<<<<<
############################################
#### Route Table Association ####
############################################
PubSub1aRouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PubRouteTable
SubnetId: !Ref PubSubnet1a
PubSub1cRouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PubRouteTable
SubnetId: !Ref PubSubnet1c
PriSub1aRouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PriRouteTable1a
SubnetId: !Ref PriSubnet1a
PriSub1cRouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PriRouteTable1c
SubnetId: !Ref PriSubnet1c
############################################
#### OutPuts ####
############################################
Outputs:
VpcId:
Value: !Ref VPC
Description: VPC ID
Export:
Name: !Sub ${ProjectName}-VpcId
PubSub1aId:
Value: !Ref PubSubnet1a
Description: Public Subnet ID in ap-northeast-1a
Export:
Name: !Sub ${ProjectName}-PubSub1aId
PubSub1cId:
Value: !Ref PubSubnet1c
Description: Public Subnet ID in ap-northeast-1c
Export:
Name: !Sub ${ProjectName}-PubSub1cId
PriSub1aId:
Value: !Ref PriSubnet1a
Description: Private Subnet ID in ap-northeast-1a
Export:
Name: !Sub ${ProjectName}-PriSub1aId
PriSub1cId:
Value: !Ref PriSubnet1c
Description: Private Subnet ID in ap-northeast-1c
Export:
Name: !Sub ${ProjectName}-PriSub1cId
ここで個人的に学びになった点をピックアップしてみます。
RouteTable
基本的にはマネコンで作成するときと同じ認識でリソースを作っていきますが、マネコンと大きく違う点がRouteTable関係です。
RouteTableは、AWS::EC2::RouteTableでRouteTable自体を作成し、AWS::EC2::Routeでそれぞれのルートを作成、AWS::EC2::SubnetRouteTableAssociationでRouteTableとSubnetを結び付けることで機能します。
なお、NAT Gatewayを使わない限り Private の Route は必要ありません。
理由としては、S3 Endpoint(ゲートウェイ型)はRouteTableに直接アタッチするためです。(マネコンでは Route として Private Subnet -> S3 Endpoint として作成される)
IGW
InternetGateWay(IGW)などのGateway関係は基本的に、その「Gateway本体」と「Gatewayのアタッチ処理」を別のキーとて記述する必要があります。
今回の例で言うと、 IGWで本体を作成して、IGWAttachmentでそれを作成済みのVPCにアタッチしています。
OutPuts
このキーはオプショナルですが、かなり使用頻度が高くなりそうなのでピックアップします。
OutPutsに記述することで、このテンプレートで定義したリソースを他のテンプレートでも呼び出せるようにすることができるようになります。
Valueで呼び出すリソースを、Export.Nameで呼び出す際の変数を定義します。
これで、VPCなどの多く共通して使いそうなリソースを個別のテンプレートとして用意しておいて、あとは使途に応じて随時作成するテンプレートから呼び出すことができるようになります。
パラメータと実行ファイル
テンプレートのParametersで、テンプレート内で使用する変数を定義することができます。
この際に変数に代入するものをテンプレート実行時に動的に与えても良いのですが、以下のようなjsonファイルとして外部に切り出して呼び出すこともできます。
[
{
"ParameterKey": "ProjectName",
"ParameterValue": "test"
}
]
また、以下のshスクリプトを実行することで、jsonファイルを使ったテンプレートからスタックを作成することができます。
#!/bin/bash
aws cloudformation create-stack \
--stack-name testStackVPC \
--template-body file://template.vpc.yaml \
--parameters file://parameter.vpc.json \
--capabilities CAPABILITY_NAMED_IAM
まとめ
上記でVPCを対象にCfnの簡単な動きをまとめました。
やはりGUIでぽちぽちやっていると、現在のリソースの状況を把握しにくくなるのでコードで管理できるのは非常にいいですね。
今後もCfn使っていこうと思います。