6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CloudFormationをゼロから勉強する。(その5:マッピングと条件式)

Last updated at Posted at 2020-09-20

はじめに

今回はMappingsセクションとConditionsセクションを使って、環境ごとの値設定と、条件関数による切り替えを実施してみようと思います。

Mappingsセクションについて

キーと名前付きの値が対応付けられたグループ化機能となります。

AWS CloudFormationユーザガイド」ではリージョンごとにAMI IDをマッピングした例が紹介されております。

Mappingsサンプル(抜粋)
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サンプル(抜粋)
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

今回作成する構成

今回は以下のようなシナリオを想定して構成を作ってみようと思います。

  1. 開発環境か本番環境かをユーザに選択させる。
  2. 選択した環境用のキーペアをEC2インスタンスに紐づける。
  3. 本番環境の場合、追加でEC2インスタンスを作成して2台構成とする。

事前準備

今回は予め各環境用のキーペアを作成しておきます。

環境 キーペア名
開発環境用キーペア staging_key
本番環境用キーペア production_key

Parametersセクションへの設定追加

今回も前回作成したテンプレートとパラメータファイルをベースに作成していきます。

前回のテンプレート(展開して下さい)
/home/ec2-user/cloudformation.yaml
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
前回のパラメータファイル(展開して下さい)
/home/ec2-user/param.json
[
  { "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
  { "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" }
]

今回は環境をユーザに選択させたいためAllowedValuesで選択させるようにしようと思います。

ちなみにAllowedValuesを設定するとデザイナー画面から入力する際に以下のように選択式にすることができます。

capture_11092020_091321.jpg

まぁ、CLIからやるのであればあまり関係ありませんが・・・

前回VPCRangeSubnetRangeのパラメータを作成しているので、その下に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インスタンスリソースのKeyNameConditionsセクションで作成した条件を使用して本番環境用キーペアと開発環境用キーペアを指定するようにしたいと思います。

前回のテンプレートを使用して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行目のインスタンス名以外、「本番環境用キーペアの作成条件」で作成した内容とほぼ同じですが、最終行のConditionEnvSelectの場合にのみEC2インスタンスを作成するようにします。

本番環境用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で実行するため、パラメータファイルにも今回追加した設定を記載して実行していきます。

完成したテンプレート(展開して下さい)
/home/ec2-user/cloudformation.yaml
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"]}
完成したパラメータファイル(開発環境向け)(展開して下さい)
/home/ec2-user/param.json
[
  { "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
  { "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" },
  { "ParameterKey" : "EnvType", "ParameterValue" : "Staging" }
]

開発環境用EC2インスタンスの作成

上記のパラメータファイルはEnvTypeParameterValueStagingを指定しているので、以下コマンドを実行すると、開発環境用のキーペアが指定された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台作成されているのが確認できます。
capture_13092020_125253.jpg

capture_13092020_125709.jpg

次の作業のためにいったんテンプレートを削除しておきます。

テンプレートの削除
aws cloudformation delete-stack --stack-name stack-test

本番環境用EC2インスタンスの作成

パラメータファイルのEnvTypeParameterValueProductionに書き換えて再度テンプレートを作成します。

完成したパラメータファイル(本番環境向け)(展開して下さい)
/home/ec2-user/param.json
[
  { "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台作成されているのが確認できます。

capture_13092020_132356.jpg

capture_13092020_132556.jpg

おわりに

MappingsConditionsを使用することで、1つのソースを複数の環境で使いまわすことができるので、特定の環境だけ追加した設定を反映し忘れたといったことが防げそうです。

次回はまだ使っていないTransformセクションを使ってみようと思います。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?