CloudFormationウォークスルーにYAMLで入門してみる


AWSリソースの構築を自動化できるCloud Formationについて学んで見ます.

まずは既存のVPC内にSG切ってインスタンス立てて...ぐらいができればいいんだけど...と思っていたのですが、

[ウォークスルー: スタックの更新](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/updating.stacks.walkthrough.html)

がある程度まとまってたので、とりあえず走らせて見て、何が起きてるかを学んでくことにしようと思います.


## 下準備: JSON => YAMLへの変換
このウォークスルーではスタック（CloudFormationで構築されるひとかたまり）を作成したのち、それを更新していく…というチュートリアルですが、一番上のセクション「[単純なアプリケーション](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/updating.stacks.walkthrough.html#updating.simple.application)」に下地となるテンプレートが記載されているのでそれをコピーして進める…

**前にこれをJSONからYAMLへ変換します** (JSONしんどいため&コメントつけられるようにするため)

[AWS CloudFormation Template Flip](https://github.com/awslabs/aws-cfn-template-flip)というツールがAWSから公開されているので、pipでインストールします.

```
pip install cfn-flip
```

次に下地となる、「[単純なアプリケーション](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/updating.stacks.walkthrough.html#updating.simple.application)」セクションの一番下にある、長ーいJSONを`walkthrough01.json`など適当な名前でローカルに保存して、下記のコマンドを実行します.

```
cfn-flip -c walkthrough01.json walkthrough01.yaml
```

するとYAMLへ変換されたファイルが生成されます. 

### 
この際、通常のJSON => YAMLの変換だけでなく、組み込み関数宣言部`Fn::`が短縮形`!`に変換されます. (3文字減るだけですが...[ドキュメント](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-base64.html)をでは短縮形が併記されています）
また、`-c, --clean`オプションをつけると、`Fn::Join` から`Fn::Sub`へと書き換えてくれます.　文字列を連結する際[]で括らなくても良くなるようで、見やすかったのでこちらで進めていきます.

（最初は関数って何してんのと思ったのですが、ユーザーの入力受け取ったり文字列を結合したりできる、といった感じなのでひとまずそのまま進めれば大丈夫です. ）

生成されたテンプレートはこんな感じです（長いですねー...）

```walkthrough01.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS CloudFormation Sample Template: Sample template that can be used
  to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You
  will be billed for the AWS resources used if you create a stack from this template.'
Parameters:
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: m1.small
    AllowedValues:
      - t1.micro
      - t2.micro
      - t2.small
      - t2.medium
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - g2.2xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - i2.xlarge
      - i2.2xlarge
      - i2.4xlarge
      - i2.8xlarge
      - hi1.4xlarge
      - hs1.8xlarge
      - cr1.8xlarge
      - cc2.8xlarge
      - cg1.4xlarge
    ConstraintDescription: must be a valid EC2 instance type.
Mappings:
  AWSInstanceType2Arch:
    t1.micro:
      Arch: PV64
    t2.micro:
      Arch: HVM64
    t2.small:
      Arch: HVM64
    t2.medium:
      Arch: HVM64
    m1.small:
      Arch: PV64
    m1.medium:
      Arch: PV64
    m1.large:
      Arch: PV64
    m1.xlarge:
      Arch: PV64
    m2.xlarge:
      Arch: PV64
    m2.2xlarge:
      Arch: PV64
    m2.4xlarge:
      Arch: PV64
    m3.medium:
      Arch: HVM64
    m3.large:
      Arch: HVM64
    m3.xlarge:
      Arch: HVM64
    m3.2xlarge:
      Arch: HVM64
    c1.medium:
      Arch: PV64
    c1.xlarge:
      Arch: PV64
    c3.large:
      Arch: HVM64
    c3.xlarge:
      Arch: HVM64
    c3.2xlarge:
      Arch: HVM64
    c3.4xlarge:
      Arch: HVM64
    c3.8xlarge:
      Arch: HVM64
    g2.2xlarge:
      Arch: HVMG2
    r3.large:
      Arch: HVM64
    r3.xlarge:
      Arch: HVM64
    r3.2xlarge:
      Arch: HVM64
    r3.4xlarge:
      Arch: HVM64
    r3.8xlarge:
      Arch: HVM64
    i2.xlarge:
      Arch: HVM64
    i2.2xlarge:
      Arch: HVM64
    i2.4xlarge:
      Arch: HVM64
    i2.8xlarge:
      Arch: HVM64
    hi1.4xlarge:
      Arch: HVM64
    hs1.8xlarge:
      Arch: HVM64
    cr1.8xlarge:
      Arch: HVM64
    cc2.8xlarge:
      Arch: HVM64
  AWSRegionArch2AMI:
    us-east-1:
      PV64: ami-50842d38
      HVM64: ami-08842d60
      HVMG2: ami-3a329952
    us-west-2:
      PV64: ami-af86c69f
      HVM64: ami-8786c6b7
      HVMG2: ami-47296a77
    us-west-1:
      PV64: ami-c7a8a182
      HVM64: ami-cfa8a18a
      HVMG2: ami-331b1376
    eu-west-1:
      PV64: ami-aa8f28dd
      HVM64: ami-748e2903
      HVMG2: ami-00913777
    ap-southeast-1:
      PV64: ami-20e1c572
      HVM64: ami-d6e1c584
      HVMG2: ami-fabe9aa8
    ap-northeast-1:
      PV64: ami-21072820
      HVM64: ami-35072834
      HVMG2: ami-5dd1ff5c
    ap-southeast-2:
      PV64: ami-8b4724b1
      HVM64: ami-fd4724c7
      HVMG2: ami-e98ae9d3
    sa-east-1:
      PV64: ami-9d6cc680
      HVM64: ami-956cc688
      HVMG2: NOT_SUPPORTED
    cn-north-1:
      PV64: ami-a857c591
      HVM64: ami-ac57c595
      HVMG2: NOT_SUPPORTED
    eu-central-1:
      PV64: ami-a03503bd
      HVM64: ami-b43503a9
      HVMG2: ami-b03503ad
Resources:
  WebServerInstance:
    Type: AWS::EC2::Instance
    Metadata:
      Comment: Install a simple PHP application
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
              php: []
          files:
            /var/www/html/index.php:
              content: '<?php

                echo ''<h1>AWS CloudFormation sample PHP application</h1>'';

                ?>

                '
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:
              content: !Sub '[main]

                stack=${AWS::StackId}

                region=${AWS::Region}

                '
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub '[cfn-auto-reloader-hook]

                triggers=post.update

                path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init

                action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance  --region     ${AWS::Region}

                runas=root

                '
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'
              cfn-hup:
                enabled: 'true'
                ensureRunning: 'true'
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    Properties:
      ImageId: !FindInMap [AWSRegionArch2AMI, !Ref 'AWS::Region', !FindInMap [AWSInstanceType2Arch,
          !Ref 'InstanceType', Arch]]
      InstanceType: !Ref 'InstanceType'
      SecurityGroups:
        - !Ref 'WebServerSecurityGroup'
      UserData: !Base64
        Fn::Sub: '#!/bin/bash -xe

          yum install -y aws-cfn-bootstrap

          # Install the files and packages from the metadata

          /opt/aws/bin/cfn-init -v          --stack ${AWS::StackName}         --resource
          WebServerInstance          --region ${AWS::Region}

          # Start up the cfn-hup daemon to listen for changes to the Web Server metadata

          /opt/aws/bin/cfn-hup || error_exit ''Failed to start cfn-hup''

          # Signal the status from cfn-init

          /opt/aws/bin/cfn-signal -e $?          --stack ${AWS::StackName}         --resource
          WebServerInstance          --region ${AWS::Region}

          '
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
Outputs:
  WebsiteURL:
    Description: Application URL
    Value: !Sub 'http://${WebServerInstance.PublicDnsName}'

```

## 起動
ともあれ、生成されたテンプレートを元に「[初期スタックの作成](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/updating.stacks.walkthrough.html#updating.create.initial.stack)」を参考にしてCloudFormationをマネジメントコンソールから起動して見ます.
するとデフォルトVPC内にインスタンスが立ち上がっていることが確認できるかと思います.
CloudFormationコンソールの[Output]タブに表示されたアドレスへアクセスすると、*AWS CloudFormation sample PHP application*というメッセージが表示されているかと思います.

## テンプレートを読む
一旦起動し終わったところで、どんな構造になっているか読んでいきたいと思います.
長いようでやってることはシンプルなテンプレートなので、そんに項目数は多くないかと思います.

YAMLの最上位には

- AWSTemplateFormatVersion
- Description
- Parameters
- Mappings
- Resources
- Outputs

が並んでいました. それぞれ、

|項目|内容|
|:--|:--|
|AWSTemplateFormatVersion|テンプレートフォーマットのバージョン、基本固定？|
|Description|テンプレートの説明文|
|Parameters|CloudFormation実行時にユーザーが与えるパラメーター|
|Mappings|与えらた条件に応じて変更される値の定義|
|Resources|起動されるAWSリソースの設定|
|Outputs|起動完了後に出力されるメッセージ|

といった感じです. Version, Description, Outputは簡単そうなので脇に置いて、残りについて見ていきたいと思います.

### Parameters
実行するユーザーが与えるパラメータです.
テンプレートでは下記の通り.

```
Parameters:
  InstanceType:                               # 項目名
    Description: WebServer EC2 instance type  # 説明
    Type: String                              # 入力される値の型
    Default: m1.small                         # デフォルト値
    AllowedValues:                            # 受け付ける値
      - t1.micro
      # ...
      # 中略
      # ...
    ConstraintDescription: must be ...        # 入力値違反時のエラーメッセージ

```

これが反映されるとCloudFormation起動画面ではこんな感じになります.

![Screen Shot 2017-09-07 at 11.42.15.png](https://qiita-image-store.s3.amazonaws.com/0/163756/f03ffa1c-4c04-e8a1-5ac4-a897bc980d17.png "Screen Shot 2017-09-07 at 11.42.15.png")

Prameters 以下にセレクトボックスができているのがわかります.
`AllowedValue`の他にも、`AllowedPattern`で正規表現で入力値を規定することができます(SSHアクセスを許可するIPアドレスレンジを入力させたいときなど)

### Mappings
CloudFormationが実行される条件に応じて、この次のResourcesを変更したいときに利用するための値のマッピングです.

```
Mappings:
  AWSInstanceType2Arch:
    t1.micro:
      Arch: PV64
      # ...
      # 中略
      # ...
  AWSRegionArch2AMI:
    us-east-1:
      PV64: ami-50842d38
      HVM64: ami-08842d60
      HVMG2: ami-3a329952
      # ...
      # 後略
      # ...
```

今回はParameterでユーザーから与えられたインスタンスタイプに応じて仮想化の方式を決定したり、実行されたリージョン（+インスタンスタイプ）に応じて選択するAMIを決定しています.

(ParameterとMappingがこのサンプルテンプレートを長くしちゃってる原因、ですね...)

### Resources
CloudFormationの本体部分になる、起動されるリソースの設定です.

```
Resources:
  WebServerInstance:
  # ...
  # 中略
  # ...
  WebServerSecurityGroup:
  # ...
  # 後略
  # ...

```

と今回はEC2インスタンスとセキュリティグループの2つになります.
ここではEC2の設定について、読んでいこうと思います.
(VPCとサブネットは指定しないとデフォルトが選択される模様)

#### EC2

ここが一番重たい...気がします.

```
  WebServerInstance:          # 項目名
    Type: AWS::EC2::Instance    # リソースタイプ
    Metadata:                   # 追加コメントの記載や起動スクリプトの定義や
      # ...
      # 中略
      # ...
    Properties:                 # EC2自身の起動パラメータ
      # ...
      # 中略
      # ...
    CreationPolicy:             # CloudFormation側とのやりとりの設定
      # ...
      # 後略
      # ...
```

と大きく分けて4つ、要素があります.
Typeはそのままであり、CreationPolicyはこのテンプレートではシンプルなので、ここではMetadataとPropatiesの2つについて見ていきます.

##### Metadata
```
    Metadata:
      Comment: Install a simple PHP application
      AWS::CloudFormation::Init:  # 起動スクリプトの設定
        config:
          packages:  # 利用するパッケージ、今回はyumでapacheとphpをインストール
            yum:
              httpd: []
              php: []
          files:     # 設置する設定ファイル類
            /var/www/html/index.php:  # デモ用phpファイル
              content:  # 略
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:  # Stackを通じてEC2のアップデートをするための設定
              content: !Sub '[main]  # !Subで文字列の結合

                stack=${AWS::StackId}  # Stack IDの取得

                region=${AWS::Region}  # リージョンの取得

                '
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:  # 同じくアップデートのための設定
              content:  # 略
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'
              cfn-hup:
                enabled: 'true'
                ensureRunning: 'true'
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
```


[ドキュメント](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)にあるように、実装の詳細をコメントとして含めたり、`AWS::CloudFormation::Init`を利用した起動スクリプトの設定ができる箇所になります。


AWS::CloudFormation::Initではyumなどによるインストール、設定ファイルの配置、起動するサービスの選択ができます. 今回はApacheと、CloudFormationスタックを通してEC2の方に変更を反映するためのエージェント(`cfn-hup`)の設定をしている形になります. ウォークスルーを進めると早速index.phpファイルを変更しスタックをアップデートするのですが、その際CloudFormation側からインスタンス内のindex.phpファイルを触りに行くのにこれを通じて行う、ようです.

参考: [cfn-hup](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-hup.html)


また[`!Sub`](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html)という組み込み関数を用いて文字列の連結を行なっています.

##### Properties
EC2本体の設定値やスクリプトの実行を行ないます.

```
    Properties:
      ImageId: !FindInMap [AWSRegionArch2AMI, !Ref 'AWS::Region', !FindInMap [AWSInstanceType2Arch,
          !Ref 'InstanceType', Arch]]  # AMIのID取得、Mappingsで設定した値を利用
      InstanceType: !Ref 'InstanceType'
      SecurityGroups:
        - !Ref 'WebServerSecurityGroup'
      UserData: !Base64  # スクリプト実行
        Fn::Sub: '#!/bin/bash -xe

          yum install -y aws-cfn-bootstrap

          # Metadataからのファイルとパッケージのインストール

          /opt/aws/bin/cfn-init -v          --stack ${AWS::StackName}         --resource
          WebServerInstance          --region ${AWS::Region}

          # cfn-hup daemon の起動とStackの変更のリッスン開始

          /opt/aws/bin/cfn-hup || error_exit ''Failed to start cfn-hup''

          # インスタンスの状態をCloudFormation側へ通知

          /opt/aws/bin/cfn-signal -e $?          --stack ${AWS::StackName}         --resource
          WebServerInstance          --region ${AWS::Region}

          '

```
[`!Ref`](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html)でParameterで指定された値を受け取り、[`!FindInMap`](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html)でMappingで設定した値を取得し、EC2の設定パラメータを指定しています. (こうすることでどのリージョンでも起動可能)

また、`UserData`にCloudFormation起動時に実行するスクリプトを渡しています. Metadataで記載したファイルやパッケージもここで読み込まれ、インストールが実行されます.

(UserData側に全てインストール項目記載しても良さそうですが、後からスタックを通しての変更ができない、テンプレートの見通しが悪くなる等々デメリットがあるのだと思います.

### （追記）改行など整えたもの
自動変換の際、改行を表現するのに1行あける、ということがされていましたが、YAMLでは`|`が置かれた後の属性は改行を評価する、ということになっているそうです.
これを用いるともう少しスッキリ書けます

※[リソースのプロパティの追加](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/updating.stacks.walkthrough.html#update.walkthrough.adding.properties)のSSHによるアクセス追加の部分を加えてあります.

```
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS CloudFormation Sample Template: Sample template that can be used
  to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You
  will be billed for the AWS resources used if you create a stack from this template.'
Parameters:
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: m1.small
    AllowedValues:
      - t1.micro
      - t2.micro
      - t2.small
      - t2.medium
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - g2.2xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - i2.xlarge
      - i2.2xlarge
      - i2.4xlarge
      - i2.8xlarge
      - hi1.4xlarge
      - hs1.8xlarge
      - cr1.8xlarge
      - cc2.8xlarge
      - cg1.4xlarge
    ConstraintDescription: must be a valid EC2 instance type.
  KeyName: 
    Description: Name of an existing Amazon EC2 key pair for SSH access
    Type: AWS::EC2::KeyPair::KeyName
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 192.168.0.1/32
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.  
Mappings:
  AWSInstanceType2Arch:
    t1.micro:
      Arch: PV64
    t2.micro:
      Arch: HVM64
    t2.small:
      Arch: HVM64
    t2.medium:
      Arch: HVM64
    m1.small:
      Arch: PV64
    m1.medium:
      Arch: PV64
    m1.large:
      Arch: PV64
    m1.xlarge:
      Arch: PV64
    m2.xlarge:
      Arch: PV64
    m2.2xlarge:
      Arch: PV64
    m2.4xlarge:
      Arch: PV64
    m3.medium:
      Arch: HVM64
    m3.large:
      Arch: HVM64
    m3.xlarge:
      Arch: HVM64
    m3.2xlarge:
      Arch: HVM64
    c1.medium:
      Arch: PV64
    c1.xlarge:
      Arch: PV64
    c3.large:
      Arch: HVM64
    c3.xlarge:
      Arch: HVM64
    c3.2xlarge:
      Arch: HVM64
    c3.4xlarge:
      Arch: HVM64
    c3.8xlarge:
      Arch: HVM64
    g2.2xlarge:
      Arch: HVMG2
    r3.large:
      Arch: HVM64
    r3.xlarge:
      Arch: HVM64
    r3.2xlarge:
      Arch: HVM64
    r3.4xlarge:
      Arch: HVM64
    r3.8xlarge:
      Arch: HVM64
    i2.xlarge:
      Arch: HVM64
    i2.2xlarge:
      Arch: HVM64
    i2.4xlarge:
      Arch: HVM64
    i2.8xlarge:
      Arch: HVM64
    hi1.4xlarge:
      Arch: HVM64
    hs1.8xlarge:
      Arch: HVM64
    cr1.8xlarge:
      Arch: HVM64
    cc2.8xlarge:
      Arch: HVM64
  AWSRegionArch2AMI:
    us-east-1:
      PV64: ami-50842d38
      HVM64: ami-08842d60
      HVMG2: ami-3a329952
    us-west-2:
      PV64: ami-af86c69f
      HVM64: ami-8786c6b7
      HVMG2: ami-47296a77
    us-west-1:
      PV64: ami-c7a8a182
      HVM64: ami-cfa8a18a
      HVMG2: ami-331b1376
    eu-west-1:
      PV64: ami-aa8f28dd
      HVM64: ami-748e2903
      HVMG2: ami-00913777
    ap-southeast-1:
      PV64: ami-20e1c572
      HVM64: ami-d6e1c584
      HVMG2: ami-fabe9aa8
    ap-northeast-1:
      PV64: ami-21072820
      HVM64: ami-35072834
      HVMG2: ami-5dd1ff5c
    ap-southeast-2:
      PV64: ami-8b4724b1
      HVM64: ami-fd4724c7
      HVMG2: ami-e98ae9d3
    sa-east-1:
      PV64: ami-9d6cc680
      HVM64: ami-956cc688
      HVMG2: NOT_SUPPORTED
    cn-north-1:
      PV64: ami-a857c591
      HVM64: ami-ac57c595
      HVMG2: NOT_SUPPORTED
    eu-central-1:
      PV64: ami-a03503bd
      HVM64: ami-b43503a9
      HVMG2: ami-b03503ad
Resources:
  WebServerInstance:
    Type: AWS::EC2::Instance
    Metadata:
      Comment: Install a simple PHP application
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
              php: []
          files:
            /var/www/html/index.php:
              content: |
                <?php
                echo '<h1>AWS CloudFormation sample PHP application</h1>';
                echo 'Updated virsions via UpdateStack';
                ?>
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region}
                runas=root
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'
              cfn-hup:
                enabled: 'true'
                ensureRunning: 'true'
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    Properties:
      ImageId: !FindInMap [AWSRegionArch2AMI, !Ref 'AWS::Region', !FindInMap [AWSInstanceType2Arch,
          !Ref 'InstanceType', Arch]]
      InstanceType: !Ref 'InstanceType'
      SecurityGroups:
        - !Ref 'WebServerSecurityGroup'
      KeyName: !Ref 'KeyName'
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash -xe
          yum install -y aws-cfn-bootstrap
          # Install the files and packages from the metadata
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
          # Start up the cfn-hup daemon to listen for changes to the Web Server metadata
          /opt/aws/bin/cfn-hup || error_exit ''Failed to start cfn-hup''
          # Signal the status from cfn-init
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: !Ref 'SSHLocation'
Outputs:
  WebsiteURL:
    Description: Application URL
    Value: !Sub 'http://${WebServerInstance.PublicDnsName}'
```
phpのところで、`''`で括られていた箇所を`'`に直していますが、これもYAMLの規定で、文字列中でシングルクォーテーションのエスケープには2つ連ねる、というのを変換のスクリプトが利用していたからでした.

-----------------------

なかなか手が出せなかったCloudFormationだったのですが、ウォークスルーの一番最初の部分について、ドキュメント読み読み進めて見ました.  
ウォークスルーでいきなりこの長さはちょっとしんどいですね...