AWS入門 - CloudFormation 使ってみる
AWSを使う必要が出てきたので、色々と試してみる。
ここでは、CloudFormation を試す。
AWS CloudFormation
AWSのリソース構成をモデル化し、それを元にリソースを構築してくれるやつ。
いわゆる、IaCなやつ。
Templates
テンプレートは、どのようなリソース構成にするのかを記述したもの。
YAMLかJSONで記述できる。
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "A sample template",
"Resources" : {
"MyEC2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"ImageId" : "ami-0ff8a91507f77f867",
"InstanceType" : "t2.micro",
"KeyName" : "testkey",
"BlockDeviceMappings" : [
{
"DeviceName" : "/dev/sdm",
"Ebs" : {
"VolumeType" : "io1",
"Iops" : 200,
"DeleteOnTermination" : false,
"VolumeSize" : 20
}
}
]
}
}
}
}
Stacks
スタックは、AWSリソースを管理するための単位。
スタックには複数のリソースが紐付いていて、スタックを作成・更新・削除することで、リソースも作成・更新・削除できる。
スタックはテンプレートを元に作られる。
Change sets
変更セットは、スタックの変更内容。
変更セットをスタックに適用するとどうなるかを事前確認できる。
まとめるとこんな感じ。
スタックの更新
スタックを更新する方法(=スタックに紐付いているリソースの更新)は、2種類あるらしい。
- 直接更新
- 変更セットによる更新
変更セットによる更新の場合は、更新内容を実際に反映する前に確認できる。
CloudFormation Designer
図を描くようにテンプレートを作成できるツール。
D&Dでリソースを配置し、特定のプロパティは矢印をつなげて依存関係を指定できたりする。
テキストエディタでテンプレートを書いていると具体的にどのような構成になっているのか把握しづらいが、Designer上であればそういった課題が解消される。
Former2
既に構築済みのリソースを元にテンプレートとして出力できるツール。
プロトタイプ的にコンソール画面をポチポチしてリソースを構築し、Former2でテンプレートとして出力すると、0からテンプレートを書くよりも楽な気がする。
ただし、AWS公式のツールではないので、おまけ程度に使う感じかもしれない。
CloudFormationでEC2を立ち上げてみる
実際にCloudFormationを使って環境を構築してみる。
テンプレート作成
CloudFormation Designer を使ってテンプレートを作成してみる。
VPC・サブネット・EC2インスタンスと順番に配置し、依存関係の矢印をつなげたり、プロパティを直接指定したりしていく。
いちおう上の方にバリデーションするボタンはあるが、YAMLやJSONとして正しいか を確認できるぐらいで、各プロパティや構成が正しいかは全く確認できない。
別途、テンプレートをバリデーションするツールを探したほうが良さそうな感じがする。
AWSTemplateFormatVersion: 2010-09-09
Metadata:
'AWS::CloudFormation::Designer':
9fab3b90-1d19-4661-8864-e4df1a422b20:
size:
width: 390
height: 370
position:
x: 230
'y': 130
z: 0
embeds:
- c206bd08-4348-4325-9f65-2d4320851fa1
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- eb941550-fda8-473a-8e1a-85796b4a8fd8
5932e6f4-ca41-4c64-918e-02a45c97fcf0:
size:
width: 100
height: 120
position:
x: 260
'y': 180
z: 1
parent: 9fab3b90-1d19-4661-8864-e4df1a422b20
embeds:
- 00a6e911-9e65-4f17-9c68-5d0283368cf7
iscontainedinside:
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
00a6e911-9e65-4f17-9c68-5d0283368cf7:
size:
width: 60
height: 60
position:
x: 280
'y': 220
z: 2
parent: 5932e6f4-ca41-4c64-918e-02a45c97fcf0
embeds: []
isassociatedwith:
- eb941550-fda8-473a-8e1a-85796b4a8fd8
iscontainedinside:
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
- 5932e6f4-ca41-4c64-918e-02a45c97fcf0
44c9d192-fbd9-4c04-ac0c-6848dc43fd80:
size:
width: 60
height: 60
position:
x: 660
'y': 130
z: 0
embeds: []
dbaa5783-b2b2-4a5d-9357-7fd2d55a8d74:
source:
id: 9fab3b90-1d19-4661-8864-e4df1a422b20
target:
id: 44c9d192-fbd9-4c04-ac0c-6848dc43fd80
z: 0
c206bd08-4348-4325-9f65-2d4320851fa1:
size:
width: 100
height: 120
position:
x: 410
'y': 180
z: 1
parent: 9fab3b90-1d19-4661-8864-e4df1a422b20
embeds:
- 57901186-5650-4cb5-83c6-12227c4ad128
18d0301a-cfa9-4816-be9c-64d81d369c88:
source:
id: c206bd08-4348-4325-9f65-2d4320851fa1
target:
id: 5932e6f4-ca41-4c64-918e-02a45c97fcf0
z: 1
57901186-5650-4cb5-83c6-12227c4ad128:
size:
width: 60
height: 60
position:
x: 430
'y': 220
z: 2
parent: c206bd08-4348-4325-9f65-2d4320851fa1
embeds: []
isassociatedwith:
- 44c9d192-fbd9-4c04-ac0c-6848dc43fd80
iscontainedinside:
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
- c206bd08-4348-4325-9f65-2d4320851fa1
eb941550-fda8-473a-8e1a-85796b4a8fd8:
size:
width: 60
height: 60
position:
x: 280
'y': 340
z: 1
parent: 9fab3b90-1d19-4661-8864-e4df1a422b20
embeds: []
iscontainedinside:
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
- 9fab3b90-1d19-4661-8864-e4df1a422b20
e79b0b90-5f6f-42a7-bf20-fb2569a19b3c:
source:
id: c206bd08-4348-4325-9f65-2d4320851fa1
selector: 'g:nth-child(1) g:nth-child(5) g:nth-child(3) circle:nth-child(1) '
port: 'AWS::DependencyLink-*'
target:
id: 9fab3b90-1d19-4661-8864-e4df1a422b20
z: 4
Resources:
EC2VPCG3QQG7:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Metadata:
'AWS::CloudFormation::Designer':
id: dbaa5783-b2b2-4a5d-9357-7fd2d55a8d74
EC2SRTA38T7L:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet
Metadata:
'AWS::CloudFormation::Designer':
id: 18d0301a-cfa9-4816-be9c-64d81d369c88
SecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Allow SSH access
VpcId: !Ref VPC
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 22
IpProtocol: tcp
ToPort: 22
Metadata:
'AWS::CloudFormation::Designer':
id: eb941550-fda8-473a-8e1a-85796b4a8fd8
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: "ami-0e60b6d05dc38ff11"
InstanceType: "t2.micro"
KeyName: "kp-1114"
NetworkInterfaces:
-
DeviceIndex: "0"
SubnetId: !Ref Subnet
AssociatePublicIpAddress: "true"
GroupSet:
- !Ref SecurityGroup
Metadata:
'AWS::CloudFormation::Designer':
id: 00a6e911-9e65-4f17-9c68-5d0283368cf7
Route:
Type: 'AWS::EC2::Route'
Properties:
DestinationCidrBlock: 0.0.0.0/0
RouteTableId: !Ref RouteTable
GatewayId: !Ref InternetGateway
Metadata:
'AWS::CloudFormation::Designer':
id: 57901186-5650-4cb5-83c6-12227c4ad128
Subnet:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/24
Metadata:
'AWS::CloudFormation::Designer':
id: 5932e6f4-ca41-4c64-918e-02a45c97fcf0
RouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Metadata:
'AWS::CloudFormation::Designer':
id: c206bd08-4348-4325-9f65-2d4320851fa1
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
Properties: {}
Metadata:
'AWS::CloudFormation::Designer':
id: 44c9d192-fbd9-4c04-ac0c-6848dc43fd80
VPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: vpc-d1114
Metadata:
'AWS::CloudFormation::Designer':
id: 9fab3b90-1d19-4661-8864-e4df1a422b20
スタック作成
失敗するとこんな感じになり、途中まで作成されたリソースは全てロールバックすることもできる。
間違ったプロパティ名を指定してもスタック作成には認識できず、スタック作成あとのリソース作成中にエラーになって初めて気づける。
エラーが出ているので、修正して再度スタックを作成してみる。
スタック名の重複はNGな仕様っぽいので、エラーが出たスタックは削除しておく。
成功するとこんな感じ。
スタックから作成された各リソースがわかる。
EC2インスタンスへと問題なくSSHできることも確認できた。
$ ssh -i kp-1114.pem ec2-user@x.x.x.x
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
スタック更新(直接更新)
スタックの更新も試してみる。
変更内容は何でも良いので、とりあえずタグを追加してみる。
...
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
...
Tags:
- Key: Name
Value: ec2-name-1
...
テンプレート差し替えとして、スタックの更新を進めてみる。
細かい部分は見れないが、大まかな更新内容が事前に確認できる。
更新が完了した。
タグも反映されている。
スタック更新(変更セットによる更新)
変更セットによる更新も試してみる。
最初に更新したテンプレートを指定できる点は先程と同じ感じ。
変更セットが作成され、先程と同じく大まかに更新内容が確認できる。
"JSON changes"を見てみると、どのリソースのどのプロパティが更新されるのか確認できた。
ただし、視認性は良くないので、これを人間に分かりやすい形でUIに出してほしい。
[
{
"resourceChange": {
"logicalResourceId": "EC2Instance",
"action": "Modify",
"physicalResourceId": "i-086b9877b80852834",
"resourceType": "AWS::EC2::Instance",
"replacement": "False",
"moduleInfo": null,
"details": [
{
"target": {
"name": null,
"requiresRecreation": "Never",
"attribute": "Tags"
},
"causingEntity": null,
"evaluation": "Static",
"changeSource": "DirectModification"
}
],
"changeSetId": null,
"scope": [
"Tags"
]
},
"hookInvocationCount": null,
"type": "Resource"
}
]
この変更セットを実行すると、実際にスタック(リソース)が更新される。
スタック削除
最後に、不要になったスタック(リソース)を削除してみる。
スタックを削除すると、スタックに紐付いている各リソースが削除される。
削除されたら困るやつにはロックをかけられるっぽいが、それは別途調べてみる。
各リソースが削除され、コンソール画面上から来ていることが確認できる。
スタック自体は物理削除されず、削除済みのスタックとして後から内容を確認することもできる。
まとめ
コードとしてリソースを管理できるようになるのは良い。
既に構築済みの場合はちょっと手間がかかりそうだが、テンプレートと既存リソースを紐付ける仕組みもあるっぽいので何とかなりそう。
ただ、テンプレートを書くハードルが結構高そうではある。
CloudFormation Disgner で簡単に作れるかと思いきや、普通にリソース作成に失敗する。
そのままだと、必須プロパティが未指定だったり、指定してるがエラーになったりする場合がある。
なので、細かいプロパティは直接テンプレートをいじる必要がある。
スタックを作成するまでエラーに気づけないので、ある程度細かいバリデーションを行ってくれるツールがあると非常に助かる感じがする。
Discussion