前提
VSCodeの拡張機能である「CloudFormation」が入っている事
任意のフォルダを用意、開いて、そこにymlファイルを用意。ここではcloudformation.ymlとする。
テンプレートについて
全体像
全体像はこれだが、Resourcesのみが必須項目。他は任意やオプションの部分である。
{
"AWSTemplateFormatVersion" : "version date",
"Description" : "JSON string",
"Metadata" : {
template metadata
},
"Parameters" : {
set of parameters
},
"Rules" : {
set of rules
},
"Mappings" : {
set of mappings
},
"Conditions" : {
set of conditions
},
"Transform" : {
set of transforms
},
"Resources" : {
set of resources
},
"Outputs" : {
set of outputs
}
}
Resourcesについて
こんな構成
Resources:
Logical ID:
Type: Resource type
Properties:
Set of properties
Logical ID(論理ID)
任意の論理ID 例) mrb-ec2
リソースタイプ:
AWS::EC2::Instance等。ドキュメントを参照
プロパティ:
リソースの詳細情報。AZやセキュリティグループなど。ドキュメント参照。
ドキュメントはこちら。
リソースタイプの一覧と、プロパティ内の必須項目が記載されている。
留意事項
以下の様にセキュリティグループを作成する際など、IpProtocolの前に-(ハイフン)を入れる必要があるが、これはAWSのドキュメントには載っていない。YAMLの構文の話で配列を示すものだから。
ドキュメント通りに記載してもエラーになる場合はYAMLの構文に関する記事をググるのが良さそう。
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 0.0.0.0/0
FromPort: 22
リソース作成の流れ
前提事項の拡張機能が入っている場合、VSCode内で startと打ってtabキーを押すと全体の骨組みを
提示してくれる。
さらに、リソースの部分にec2と打つと候補が現れるので選択。
すると適当な論理IDによるプロパティの枠組みが現れる。
今回は以下のVPC作成をする
AWSTemplateFormatVersion: 2010-09-09
Resources:
myVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
Tags:
- Key: Name
Value: my-vpc-fromCF
作成したファイルをCloudFormationのメニューでアップロード
スタック名を適当に指定する
スタックオプション、詳細オプションは変更無し
作成が進行中から完了と遷移する。
作成できた
タグ内にスタック名なども表示されている
スタック作成時の考慮事項
Ref関数
同一テンプレート内のみの機能。!Refと指定すると、定義済みの論理名を利用できる。
AWSTemplateFormatVersion: 2010-09-09
Resources:
MrbVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
Tags:
- Key: Name
Value: mrb-vpc-cf
#パブリックサブネット
Mrbpubsub1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
VpcId: !Ref MrbVPC
#組み込み関数RefでVPCの論理名を取得
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: Mrb-pub-sub-1a
クロススタック構成
EC2、RDSなどを含むスタック、セキュリティグループ、IAMロールなどを含むスタック、VPC、サブネットなどを含むスタックはそれぞれ別々のスタックで管理する事が推奨されている。
スタックが別のスタックを参照した構成をクロススタック参照という。
既に作成したVPC、サブネット、セキュリティグループを含むスタックとは別にEC2のみのスタックを作成し、クロススタックの構成とする。
クロススタック参照
リソースを別のリソースで参照する場合、同一スタック内なら”Ref!” で完結するが、
別スタックに参照させる場合、”Outputs:“にどのリソースをどういう名前で参照させるかを定義する。
参照先では “ImportValue” で 定義した名前を指定する。
Network.yml
#パブリックサブネット
Mrbpubsub1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
#組み込み関数RefでVPCの論理名を取得
VpcId: !Ref MrbVPC
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: Mrb-pub-sub-1a
Outputs:
Subnet1:
#定義済み論理ID
Value: !Ref Mrbpubsub1a
#別テンプレで参照する際の名前
Export:
Name: Subnet1Name
・ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: mrb-key
#AMIのカタログから指定(64ビット(x86))
ImageId: ami-079cd5448deeace01
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds:
- !ImportValue SG1Name
SubnetId: !ImportValue Subnet1Name
Tags:
- Key: Name
Value: CF-web1
○補足
以下の様に、”GetAtt”を利用する事でも出力が可能。これはセキュリティグループに紐づくVPCのIDをSubnet1Name-VpcIDとして出力
Outputs:
Subnet1:
#定義済み論理ID
Value: !GetAtt Mrbpubsub1a.VpcId
#別テンプレで参照する際の名前
Export:
Name: Subnet1Name-VpcID
GetAttで利用出来る戻り値は公式に記載されている
スタックを作成する
目指す構成
パブリックサブネット2つ、プライベートサブネット2つ
パブリックサブネット内にApacheとMysqlをインストールしたEC2設置
プライベートサブネットにシングル構成でMySQLのRDSを設置。
EC2からRDSにSSH接続できる状態。
作成したテンプレ
Network.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
MrbVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
Tags:
- Key: Name
Value: mrb-vpc-cf
#インターネットゲートウェイ
igwName:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: mrb-igw
#インターネットゲートウェイアタッチ
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MrbVPC
InternetGatewayId: !Ref igwName
#ルートテーブル
routeTableName:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MrbVPC
Tags:
- Key: Name
Value: mrb_rt
#ルートテーブルとサブネットの紐付け
routeTableAssocName:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref Mrbpubsub1a
RouteTableId: !Ref routeTableName
#ルートテーブル
routeName:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref routeTableName
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref igwName
#パブリックサブネット
Mrbpubsub1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
VpcId: !Ref MrbVPC
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: Mrb-pub-sub-1a
MapPublicIpOnLaunch: "true"
Mrbpubsub1c:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
VpcId: !Ref MrbVPC
CidrBlock: 10.0.2.0/24
Tags:
- Key: Name
Value: Mrb-pub-sub-1c
MapPublicIpOnLaunch: "true"
#プライベートサブネット
Mrbprisub1a:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
VpcId: !Ref MrbVPC
CidrBlock: 10.0.3.0/24
Tags:
- Key: Name
Value: Mrb-pri-sub-1a
Mrbprisub1c:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
VpcId: !Ref MrbVPC
CidrBlock: 10.0.4.0/24
Tags:
- Key: Name
Value: Mrb-pri-sub-1c
#Webサーバ用のセキュリティグループ
MrbWebSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: mrb-web-sg
GroupDescription: mrb-web-sg
VpcId: !Ref MrbVPC
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 0.0.0.0/0
FromPort: 22
ToPort: 22
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: SG-web
#DB用のセキュリティグループ
DBsg:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: mrb-db-sg
VpcId: !Ref MrbVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
SourceSecurityGroupId: !Ref MrbWebSG
Tags:
- Key: Name
Value: mrb-db-sg
Outputs:
Subnet1:
Value: !Ref Mrbpubsub1a
Export:
Name: Subnet1Name
OutputPubSubID:
Value: !Ref Mrbpubsub1a
Export:
Name: ExportPubSub1a
WebSGID:
Value: !Ref MrbWebSG
Export:
Name: ExportWebSGID
DBSG:
Value: !Ref DBsg
Export:
Name: MrbDBSG
PriSuba:
Value: !Ref Mrbprisub1a
Export:
Name: ExportPriSub1a
PriSubc:
Value: !Ref Mrbprisub1c
Export:
Name: ExportPriSub1c
EC2.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: mrb-key
#AMIのカタログから指定
ImageId: ami-0adac58024a7f03bb
InstanceType: t2.micro
Monitoring: false
Tags:
- Key: Name
Value: CF-web1
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum install -y httpd
systemctl start httpd
systemctl enable httpd
sudo yum -y install mysql
RDS.yml
AWSTemplateFormatVersion: 2010-09-09
Parameters:
DBInstanceClass:
Description: RDS instance type
Type: String
Default: db.t2.micro
AllowedValues:
- db.t2.micro
- db.t2.small
- db.t2.medium
ConstraintDescription: Must be a valid RDS instance type from the allowed list.
MasterUsername:
Description: The master username for the DB instance.
Type: String
Default: admin
MasterUserPassword:
Description: The password for the master username.
Type: String
NoEcho: True
Resources:
rdsDBInstance:
Type: AWS::RDS::DBInstance
Properties:
Engine: Mysql
AllocatedStorage: 20
DBInstanceClass: !Ref DBInstanceClass
AvailabilityZone: ap-northeast-1a
BackupRetentionPeriod: 0
DBInstanceIdentifier: mrb-db1
DBName: db1
MasterUsername: !Ref MasterUsername
MasterUserPassword: !Ref MasterUserPassword
MultiAZ: false
PubliclyAccessible: false
StorageEncrypted: false
VPCSecurityGroups:
- !ImportValue MrbDBSG
Tags:
- Key: Name
Value: mrb-db
DBSubnetGroupName: !Ref MyDBSubnetGroup
MyDBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: rdssubnetgp
SubnetIds:
- !ImportValue ExportPriSub1a
- !ImportValue ExportPriSub1c
Tags:
- Key: keyname
Value: value
思ったこと
・設定する上ではいかに適切なドキュメントに辿りつけるかが鍵。
意外に苦戦する。最悪ブログを参考にする。
・ymlの構文的に少しでもタブがずれてるとエラーになってしまう。
・VSCodeの拡張機能で表示された文言が大文字小文字が公式と違っているケースもある。
・リソースのIDを必要とする場合、論理IDでも物理IDでも良い。論理を指定した場合は内部的に物理に置き換わる。
・何故かテンプレに問題無いのに取り込むとエラーになるケースが稀にある。一回スタックを削除して再度取り込むべし。
・手動で取り込むよりCLIでの操作が楽。VSCode上でテンプレを表示させつつ、VSCodeの下部にローカルPCのターミナルを表示させてCLIを実行するとやりやすい。
・RDSなどのリソース作成に時間がかかるものは別テンプレが良いかも。
・各種論理名は適当に付けると破滅する。
・謎のエラーだとか疑問はChatGPTへ。