はじめに
今回はMappingsセクションとConditionsセクションを使って、環境ごとの値設定と、条件関数による切り替えを実施してみようと思います。
Mappingsセクションについて
キーと名前付きの値が対応付けられたグループ化機能となります。
「AWS CloudFormationユーザガイド」ではリージョンごとにAMI IDをマッピングした例が紹介されております。
Mappings:
RegionMap:
us-east-1:
"HVM64": "ami-0ff8a91507f77f867"
us-west-1:
"HVM64": "ami-0bdb828fd58c52235"
また、Mappingsセクションで対応付けた値は以下の様にFn::FindInMap:(短縮形!FindInMap)関数で呼び出すことができます。
AWSTemplateFormatVersion: "2010-09-09"
Mappings:
RegionMap:
us-east-1:
HVM64: ami-0ff8a91507f77f867
us-west-1:
HVM64: ami-0bdb828fd58c52235
Resources:
myEC2Instance:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", HVM64]
InstanceType: m1.small
Conditionsセクションについて
条件式を記載するセクションとなります。
他の開発言語と比べると使用できる条件は少ないですが、よほど凝ったことをしなければ問題にはならないでしょう。
| 内容 | 条件関数 | 完全名関数の構文 | 短縮形の構文 |
|---|---|---|---|
| AND条件 | Fn::And | Fn::And: [condition] | !And [condition] |
| 比較 | Fn::Equals | Fn::Equals: [value_1, value_2] | !Equals [value_1, value_2] |
| IF条件 | Fn::If | Fn::If: [condition_name, value_if_true, value_if_false] | !If [condition_name, value_if_true, value_if_false] |
| 否定 | Fn::Not | Fn::Not: [condition] | !Not [condition] |
| OR条件 | Fn::Or | Fn::Or: [condition, ...] | !Or [condition, ...] |
使い方としてはConditionsセクションで判定方法を記載して、他のセクションでリソース作成の条件等で、Conditionsセクションで指定した名前を呼び出して使用します。
最初いまいちイメージが掴みづらかったのですが、シェルスクリプトのif文でいうtestコマンドによる判定部分がConditionsセクションに当たり、後からCondition名として他セクションから呼び出します。
Conditions:
CreateProdResources: !Equals [ !Ref EnvType, prod ]
Resources:
EC2Instance:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
MountPoint:
Type: "AWS::EC2::VolumeAttachment"
Condition: CreateProdResources
Properties:
InstanceId:
!Ref EC2Instance
VolumeId:
!Ref NewVolume
Device: /dev/sdh
NewVolume:
Type: "AWS::EC2::Volume"
Condition: CreateProdResources
Properties:
Size: 100
AvailabilityZone:
!GetAtt EC2Instance.AvailabilityZone
Outputs:
VolumeId:
Condition: CreateProdResources
Value:
!Ref NewVolume
今回作成する構成
今回は以下のようなシナリオを想定して構成を作ってみようと思います。
- 開発環境か本番環境かをユーザに選択させる。
- 選択した環境用のキーペアを
EC2インスタンスに紐づける。 - 本番環境の場合、追加で
EC2インスタンスを作成して2台構成とする。
事前準備
今回は予め各環境用のキーペアを作成しておきます。
| 環境 | キーペア名 |
|---|---|
| 開発環境用キーペア | staging_key |
| 本番環境用キーペア | production_key |
Parametersセクションへの設定追加
今回も前回作成したテンプレートとパラメータファイルをベースに作成していきます。
前回のテンプレート(展開して下さい)
AWSTemplateFormatVersion: 2010-09-09
Metadata:
'AWS::CloudFormation::Designer':
e1390660-013a-4523-9893-ccd6074e430f:
size:
width: 190
height: 190
position:
x: 390
'y': 90
z: 0
embeds:
- e6cc612e-5a0f-459b-8329-3a5852613031
e6cc612e-5a0f-459b-8329-3a5852613031:
size:
width: 140
height: 140
position:
x: 410
'y': 130
z: 1
parent: e1390660-013a-4523-9893-ccd6074e430f
iscontainedinside:
- e1390660-013a-4523-9893-ccd6074e430f
Resources:
EC2VPC1WR8B:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: !Ref VPCRange
Metadata:
'AWS::CloudFormation::Designer':
id: e1390660-013a-4523-9893-ccd6074e430f
EC2SJOWQ:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref EC2VPC1WR8B
CidrBlock: !Ref SubnetRange
Metadata:
'AWS::CloudFormation::Designer':
id: e6cc612e-5a0f-459b-8329-3a5852613031
EC2I3Q8S8:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0cc75a8978fbbc969
InstanceType: t2.micro
NetworkInterfaces:
- SubnetId: !Ref EC2SJOWQ
DeviceIndex: 0
Parameters:
VPCRange:
Type: String
Description: "VPC Subnet Range"
SubnetRange:
Type: String
Description: "Subnet Range"
Outputs:
VPCRegion:
Description: "Region Name"
Value: !Ref AWS::Region
前回のパラメータファイル(展開して下さい)
[
{ "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
{ "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" }
]
今回は環境をユーザに選択させたいためAllowedValuesで選択させるようにしようと思います。
ちなみにAllowedValuesを設定するとデザイナー画面から入力する際に以下のように選択式にすることができます。
まぁ、CLIからやるのであればあまり関係ありませんが・・・
前回VPCRangeとSubnetRangeのパラメータを作成しているので、その下にEnvTypeを追記してください。
Parameters:
EnvType:
Type: String
Description: "Production or Staging"
AllowedValues: ["Production", "Staging"]
Mappingsセクションの記載
事前作業として作成した各環境のキーペアを指定するようにMappingsセクションを作成します。
Mappings:
Keypair: ★Map名
productionkey: ★キー値
"KEYPAIR": "production_key" ★値
stagingkey:
"KEYPAIR": "staging_key"
Mappingsセクションで指定した値は!FindInMap ["Map名", "キー値", "値"]で取得します。
Conditionsセクションの記載
先ほどParametersセクションで作成したEnvTypeを呼び出し、本番環境を選択しているかどうかを判定します。
Conditions:
EnvSelect: {"Fn::Equals": [{"Ref" : "EnvType"}, "Production"]}
Resourcesセクションの記載
Conditionsセクションで作成した本番環境の判定条件を、本番環境用キーペアの作成と、2台目のEC2インスタンス作成条件として使用します。
本番環境用キーペアの作成条件
キーペアを指定するEC2インスタンスリソースのKeyNameにConditionsセクションで作成した条件を使用して本番環境用キーペアと開発環境用キーペアを指定するようにしたいと思います。
前回のテンプレートを使用してKeyNameを以下のように指定します。
EC2I3Q8S8:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0cc75a8978fbbc969
InstanceType: t2.micro
KeyName: {Fn::If: [EnvSelect, !FindInMap [ Keypair, productionkey, KEYPAIR ], !FindInMap [ Keypair, stagingkey, KEYPAIR ]]}
NetworkInterfaces:
- SubnetId: !Ref EC2SJOWQ
DeviceIndex: 0
上記はFn::Ifで条件関数を使用し、判定条件をEnvSelectで呼び出し、EnvSelectの結果が真の場合はMappingsセクションのproductionkeyのキーペア名を指定、偽の場合はMappingsセクションのstagingkeyのキーペア名を指定する条件式となります。
本番環境用インスタンスの作成
本番環境の場合に、2台目のEC2インスタンスを作成するようにします。
下記1行目のインスタンス名以外、「本番環境用キーペアの作成条件」で作成した内容とほぼ同じですが、最終行のConditionでEnvSelectが真の場合にのみEC2インスタンスを作成するようにします。
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0cc75a8978fbbc969
InstanceType: t2.micro
KeyName: {Fn::If: [EnvSelect, !FindInMap [ Keypair, productionkey, KEYPAIR ], !FindInMap [ Keypair, stagingkey, KEYPAIR ]]}
NetworkInterfaces:
- SubnetId: !Ref EC2SJOWQ
DeviceIndex: 0
Condition: EnvSelect
テンプレートの実行
今回もCLIで実行するため、パラメータファイルにも今回追加した設定を記載して実行していきます。
完成したテンプレート(展開して下さい)
AWSTemplateFormatVersion: 2010-09-09
Metadata:
'AWS::CloudFormation::Designer':
e1390660-013a-4523-9893-ccd6074e430f:
size:
width: 190
height: 190
position:
x: 390
'y': 90
z: 0
embeds:
- e6cc612e-5a0f-459b-8329-3a5852613031
e6cc612e-5a0f-459b-8329-3a5852613031:
size:
width: 140
height: 140
position:
x: 410
'y': 130
z: 1
parent: e1390660-013a-4523-9893-ccd6074e430f
iscontainedinside:
- e1390660-013a-4523-9893-ccd6074e430f
Resources:
EC2VPC1WR8B:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: !Ref VPCRange
Metadata:
'AWS::CloudFormation::Designer':
id: e1390660-013a-4523-9893-ccd6074e430f
EC2SJOWQ:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref EC2VPC1WR8B
CidrBlock: !Ref SubnetRange
Metadata:
'AWS::CloudFormation::Designer':
id: e6cc612e-5a0f-459b-8329-3a5852613031
EC2I3Q8S8:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0cc75a8978fbbc969
InstanceType: t2.micro
KeyName: {Fn::If: [EnvSelect, !FindInMap [ Keypair, productionkey, KEYPAIR ], !FindInMap [ Keypair, stagingkey, KEYPAIR ]]}
NetworkInterfaces:
- SubnetId: !Ref EC2SJOWQ
DeviceIndex: 0
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0cc75a8978fbbc969
InstanceType: t2.micro
KeyName: {Fn::If: [EnvSelect, !FindInMap [ Keypair, productionkey, KEYPAIR ], !FindInMap [ Keypair, stagingkey, KEYPAIR ]]}
NetworkInterfaces:
- SubnetId: !Ref EC2SJOWQ
DeviceIndex: 0
Condition: EnvSelect
Parameters:
VPCRange:
Type: String
Description: "VPC Subnet Range"
SubnetRange:
Type: String
Description: "Subnet Range"
EnvType:
Type: String
Description: "Production or Staging"
AllowedValues: ["Production", "Staging"]
Outputs:
VPCRegion:
Description: "Region Name"
Value: !Ref AWS::Region
Mappings:
Keypair:
productionkey:
"KEYPAIR": "production_key"
stagingkey:
"KEYPAIR": "staging_key"
Conditions:
EnvSelect: {"Fn::Equals": [{"Ref" : "EnvType"}, "Production"]}
完成したパラメータファイル(開発環境向け)(展開して下さい)
[
{ "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
{ "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" },
{ "ParameterKey" : "EnvType", "ParameterValue" : "Staging" }
]
開発環境用EC2インスタンスの作成
上記のパラメータファイルはEnvTypeのParameterValueにStagingを指定しているので、以下コマンドを実行すると、開発環境用のキーペアが指定されたEC2インスタンスが作成されます。
aws cloudformation create-stack --template-body file:///home/ec2-user/cloudformation.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json
CloudFormationのリソース画面とEC2のインスタンス画面を見ると、開発環境用のキーペアが付与されたEC2インスタンスが1台作成されているのが確認できます。

次の作業のためにいったんテンプレートを削除しておきます。
aws cloudformation delete-stack --stack-name stack-test
本番環境用EC2インスタンスの作成
パラメータファイルのEnvTypeのParameterValueをProductionに書き換えて再度テンプレートを作成します。
完成したパラメータファイル(本番環境向け)(展開して下さい)
[
{ "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
{ "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" },
{ "ParameterKey" : "EnvType", "ParameterValue" : "Production" }
]
aws cloudformation create-stack --template-body file:///home/ec2-user/cloudformation.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json
CloudFormationのリソース画面とEC2のインスタンス画面を見ると、本番環境用のキーペアが付与されたEC2インスタンスが2台作成されているのが確認できます。
おわりに
MappingsとConditionsを使用することで、1つのソースを複数の環境で使いまわすことができるので、特定の環境だけ追加した設定を反映し忘れたといったことが防げそうです。
次回はまだ使っていないTransformセクションを使ってみようと思います。



