🤫
CloudFormationのテンプレートは Mappingを使った方が良いかも
この記事の要点
intro
『インフラのコード化』としてお馴染みのCloudFormationですが
リソースが増えるに連れてコードの行数が増え
例えばインスタンスタイプなどを変更する際に、コードを追うのが面倒になってきます。
そこで、CloudFormationの書式 "Mapping" を使ってちょっと楽してみましょう。
Mappingの書式
ユーザーガイド[1]より
定義する時
Mappings:
Map01:
Key01:
Name01: Value01
呼び出す時
!FindInMap [Map01, Key01, Name01]
※この場合は "Value01" という値が返ります。
使用・不使用での比較
EC2インスタンスを2つ作成するテンプレートを例に、比較してみましょう。
Mappingを使わない場合(クリックで開く)
Mapping不使用
AWSTemplateFormatVersion: "2010-09-09"
Resources:
Server01:
Type: "AWS::EC2::Instance"
Properties:
ImageId: "ami-1a2b3c4d5f6g7h8i9"
InstanceType: "r5.large"
KeyName: "myKey-xxxxx"
AvailabilityZone: "ap-northeast-1a"
DisableApiTermination: true
Tenancy: "default"
SubnetId: "subnet-12ab34cd56ef78gh9"
EbsOptimized: true
SecurityGroupIds:
- "sg-123abc456def789gh"
SourceDestCheck: true
IamInstanceProfile: "my-role"
Tags:
- Key: "Name"
Value: "Server01"
HibernationOptions:
Configured: false
Server02:
Type: "AWS::EC2::Instance"
Properties:
ImageId: "ami-9i8h7g6f5d4c3b2a1"
InstanceType: "r5d.2xlarge"
KeyName: "myKey-xxxxx"
AvailabilityZone: "ap-northeast-1c"
DisableApiTermination: true
Tenancy: "default"
SubnetId: "subnet-9hg87fe65dc43ba21"
EbsOptimized: true
SecurityGroupIds:
- "sg-123abc456def789gh"
SourceDestCheck: true
IamInstanceProfile: "my-role"
Tags:
- Key: "Name"
Value: "Server02"
HibernationOptions:
Configured: false
Mappingを使う場合(クリックで開く)
Mapping使用
AWSTemplateFormatVersion: "2010-09-09"
Mappings:
Constant:
SubnetId:
PrivateA: "subnet-12ab34cd56ef78gh9"
PrivateC: "subnet-9hg87fe65dc43ba21"
PublicA: "subnet-123abc456def789gh"
Variable:
KeyName:
Common: "myKey-xxxxx"
ImageId:
Server01: "ami-1a2b3c4d5f6g7h8i9"
Server02: "ami-9i8h7g6f5d4c3b2a1"
InstanceType:
Server01: "r5.large"
Server02: "r5d.2xlarge"
Subnet:
Server01: "PrivateA"
Server02: "PublicA"
Resources:
Server01:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [ Variable, ImageId, Server01 ]
InstanceType: !FindInMap [ Variable, InstanceType, Server01 ]
KeyName: !FindInMap [ Variable, KeyName, Common ]
AvailabilityZone: "ap-northeast-1a"
DisableApiTermination: true
Tenancy: "default"
SubnetId: !FindInMap [ Constant, SubnetId, !FindInMap [Variable, Subnet, Server01] ]
EbsOptimized: true
SecurityGroupIds:
- "sg-123abc456def789gh"
SourceDestCheck: true
IamInstanceProfile: "my-role"
Tags:
- Key: "Name"
Value: "Server01"
HibernationOptions:
Configured: false
Server02:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [ Variable, ImageId, Server02 ]
InstanceType: !FindInMap [ Variable, InstanceType, Server02 ]
KeyName: !FindInMap [ Variable, KeyName, Common ]
AvailabilityZone: "ap-northeast-1a"
DisableApiTermination: true
Tenancy: "default"
SubnetId: !FindInMap [ Constant, SubnetId, !FindInMap [Variable, Subnet, Server02] ]
EbsOptimized: true
SecurityGroupIds:
- "sg-123abc456def789gh"
SourceDestCheck: true
IamInstanceProfile: "my-role"
Tags:
- Key: "Name"
Value: "Server02"
HibernationOptions:
Configured: false
いかがでしょうか。
仮に、テンプレート内に30個リソースがあったら
Mappingを修正するだけで完結します。
コードをスクロールして該当部分まで行く必要が無いわけです。
コマンドで作ろう
Mapを用いた記述を一つずつ作るのは面倒・コピペミスが怖い という場合は
ベースになるymlを作成し、コマンドで置換すると楽です。
今回のインスタンスを10個作るとしたら
base-model.yml
Resources:
@:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [ Variable, ImageId, @ ]
InstanceType: !FindInMap [ Variable, InstanceType, @ ]
KeyName: !FindInMap [ Variable, KeyName, Common ]
AvailabilityZone: "ap-northeast-1a"
DisableApiTermination: true
Tenancy: "default"
SubnetId: !FindInMap [ Constant, SubnetId, !FindInMap [Variable, Subnet, @] ]
EbsOptimized: true
SecurityGroupIds:
- "sg-041bb99af7da0f6d8"
SourceDestCheck: true
IamInstanceProfile: "my-role"
Tags:
- Key: "Name"
Value: "@"
HibernationOptions:
Configured: false
上記ymlをテンプレート元に、コマンドで増やしてあげます。
for name in Server{01..10}
do
cat base-model.yml | sed -e "s/@/${name}/g"
done
といった具合でしょうか。(多少の調整は必要)
outro
パラメータ入力をCLIで回すというのも考えたのですが、
Git上でのレビューが楽かなと思ったのと、ベタ書きより可読性が上がったらいいな
という話でした。
特定の接尾次・接頭辞をNameタグなどに付与したいときも
Mappingでもたせて、!join
でくっつけたら便利そうですね。
Discussion