CloudFormationでパラメータごとにEC2インスタンスのUserDataを切り替える

記事タイトルとURLをコピーする

EC2インスタンス作成時に状況に応じて、異なるUserDataを実行したいことがあります。
例えば、CloudFormationのパラメータでインストールするPHPのバージョンを切り替えたいとします。

# デフォルトバージョンをインストール
yum install -y php
yum install -y httpd
# バージョン7.2系をインストール
amazon-linux-extras install -y php7.2
yum install -y httpd

方法1

調べるとよく見る例です。

  • Resourceを2つ定義する
  • Conditionにマッチした一方のResourceのみが実際に作成される
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  PHP:
      Description: Input Default or 7.2
      Type: String
      Default: Default

Conditions:
  PHPverDefault:
    !Equals [ !Ref PHP, Default ]
  PHPver72:
    !Equals [ !Ref PHP, 7.2 ]

Resources:
  EC2Instance:
    Type: "AWS::EC2::Instance"
    Condition: "PHPverDefault"
    Properties:
      ImageId: "ami-0c3fd0f5d33134a76"
      InstanceType: "t3.nano"
      KeyName: "xxxxxxxx"
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet: ["sg-xxxxxxxxxxxxxxxxxx"]
          SubnetId: "subnet-xxxxxxxxxxxxxxxxxx"
      UserData:
        Fn::Base64: |-
          #!/bin/bash

          yum install -y php
          yum install -y httpd

  EC2Instance2:
    Type: "AWS::EC2::Instance"
    Condition: "PHPver72"
    Properties:
      ImageId: "ami-0c3fd0f5d33134a76"
      InstanceType: "t3.nano"
      KeyName: "watanabe-aws"
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet: ["sg-xxxxxxxxxxxxxxxxxx"]
          SubnetId: "subnet-xxxxxxxxxxxxxxxxxx"
      UserData:
        Fn::Base64: |-
          #!/bin/bash

          amazon-linux-extras install -y php7.2
          yum install -y httpd

問題点として、以下を感じました。

  • UserData以外も重複して書くので行数が増える
  • 他からRefで参照する場合、Resource名が複数になってしまう

方法2

Fn::If: を使って、Resource内でUserData部分だけを分岐させる方法です。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  PHP:
      Description: Input Default or 7.2
      Type: String
      Default: Default

Conditions:
  PHPver72:
    !Equals [ !Ref PHP, 7.2 ]

Resources:
  EC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: "ami-0c3fd0f5d33134a76"
      InstanceType: "t3.nano"
      KeyName: "watanabe-aws"
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet: ["sg-xxxxxxxxxxxxxxxxxx"]
          SubnetId: "subnet-xxxxxxxxxxxxxxxxxx"
      UserData:
        Fn::If:
          - PHPver72
          - Fn::Base64: |-
              #!/bin/bash

              amazon-linux-extras install -y php7.2
              yum install -y httpd
          - Fn::Base64: |-
              #!/bin/bash

              yum install -y php
              yum install -y httpd

この場合は、コードの重複は減ります。
また、Resouceが単一なのでRefで参照が簡単です。

ただ、以下の状況だと面倒かもしれません。

  • 3パターン以上になると、 Fn::If: で分岐が難しい

感想

今回、CloudFormationの説明ページの条件関数を見ました。
If文の書き方の説明に以下のように一行で書いてあります。

Fn::If: [condition_name, value_if_true, value_if_false]

ただ、UserDataは複数行になるので、書き方が最初わかりませんでした。
Yamlのリストの書き方を調べたところ、以下のように変形できることが分かり解決しました。

Fn::If: 
  - condition_name
  - value_if_true
  - value_if_false

今回の仕事でyaml力が少し上がりました。