【AWS】知識整理 -CloudFormation-

# はじめに
AWS SOAではよくCloudFormationについて問われる。
SAA勉強時にも問われはしたが、概要くらいしか問われず中身をほぼ知らないので、いったんCloudFormationの知識整理の目的で本記事を執筆することにした。

# CloudFormationとは？
JSONやYAMLで書かれた**テンプレート**を基に、AWSリソースのプロビジョニングを行うことができるサービスのこと。
たとえば一からAWS環境を作る際に、「VPC作って、それが終わったらEC2インスタンスを立ち上げて、それが終わったら…」と一つ一つやるのは面倒なうえに設定ミスなどの危険があるので、立ち上げたい複数のリソースを一気にプロビジョニングしたいときに使用する。
また、「ここで作ったAWS環境を別リージョンでも立ち上げたいな…」というときに、その環境のテンプレートを使うことで、同じ環境を即座に立ち上げることもできる。

まとめると「**インフラストラクチャをコード化して、プロビジョニング、管理、複製を行えるサービスのこと**」

# CloudFormationのスタック
CloudFormationテンプレートを基に作成されたリソースの集合体を**スタック**という。

スタック単位でリソースの管理ができるので、たとえば「いろいろ立ち上げたはいいけど全部いらなくなっちゃった…でも１個ずつ削除するのはだるいな…」って時はスタックを削除すれば、そこに紐づくリソースをまとめて削除することもできる。

複数のAWSアカウントやリージョンにまたがって、スタックを一括で作成、更新、削除したいときは**スタックセット**を使う。
スタックセットを使うには、複数のスタックを管理する**管理者アカウント**と、スタックを実行する**ターゲットアカウント**を作る必要がある

# CloudFormationの変更セット
スタックの更新時に、更新をすることで実行中のリソースに影響がないか、ある場合はどのように影響するのかを把握することができる機能のこと。

# CloudFormationテンプレートの例
AWS公式から引用

~~~md:テンプレートの例
{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Mappings" : {
    "RegionMap" : {
      "us-east-1"      : { "AMI" : "ami-0ff8a91507f77f867"},
      "us-west-1"      : { "AMI" : "ami-0bdb828fd58c52235"},
      "us-west-2"      : { "AMI" : "ami-a0cfeed8"},
      "eu-west-1"      : { "AMI" : "ami-047bb4163c506cd98"},
      "sa-east-1"      : { "AMI" : "ami-07b14488da8ea02a0"},
      "ap-southeast-1" : { "AMI" : "ami-08569b978cc4dfa10"},
      "ap-southeast-2" : { "AMI" : "ami-09b42976632b27e9b"},
      "ap-northeast-1" : { "AMI" : "ami-06cd52961ce9f0d85"}
    }
  },
  
  "Parameters" : {
    "EnvType" : {
      "Description" : "Environment type.",
      "Default" : "test",
      "Type" : "String",
      "AllowedValues" : ["prod", "dev", "test"],
      "ConstraintDescription" : "must specify prod, dev, or test."
    }
  },
  
  "Conditions" : {
    "CreateProdResources" : {"Fn::Equals" : [{"Ref" : "EnvType"}, "prod"]},
    "CreateDevResources" : {"Fn::Equals" : [{"Ref" : "EnvType"}, "dev"]}
  },
  
  "Resources" : {
    "EC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "AMI" ]},
        "InstanceType" : { "Fn::If" : [
          "CreateProdResources",
          "c1.xlarge",
          {"Fn::If" : [
            "CreateDevResources",
            "m1.large",
            "m1.small"
          ]}
        ]}
      }
    },
    
    "MountPoint" : {
      "Type" : "AWS::EC2::VolumeAttachment",
      "Condition" : "CreateProdResources",
      "Properties" : {
        "InstanceId" : { "Ref" : "EC2Instance" },
        "VolumeId"  : { "Ref" : "NewVolume" },
        "Device" : "/dev/sdh"
      }
    }
      }
    }
  }
}
~~~

# CloudFormationのセクション

テンプレートにないものも含む。

### ・Descriptions
テンプレートの説明を入れる。

### ・Parameters
リソースのプロビジョニング時におけるパラメーターの設定ができる。
ようは変数のようなもの。
ここでパラメーターを定義すると、GUI上からも設定ができるようになる。
同じテンプレートを異なる値で利用できるので、開発、ステージング、本番の切り替えをしやすくなる

### ・Conditions
条件式の設定ができる。ANDとかORとかEqualsとか。
例として貼ったテンプレートでは、環境が「dev」なら「DevResource」を作り、環境が「Prod」なら「ProdResource」を作る、といった設定がされている。

### ・Mappings
キーとそれに関連する値を設定できる。
たとえば、「このリージョンで立ち上げる場合はこのAMIを参照してください」といった設定が可能。
また、ここで対応付けた値は**FindInMap関数**で呼び出すことができる。

### ・Resources
なんのリソースを作るか設定できる。

### ・Metadata
Resouruceに指定したAWSリソースに対する補足情報を設定する。
たとえば、ResourceにEC2インスタンスを記述し、Matedataに起動時のアクション(スクリプトの実行)などを指定することができる。

### ・Rules
パラメーターの値を検証する。
定義したルールに反するパラメータが書いてあった場合、無効となりスタックの作成・更新は実施されない。

### ・Outputs
他のテンプレートに、すでに作成したスタックの情報を参照させるときなどに使う。

これ以外にもいろいろあるので随時追加予定

# リソース属性
リソースの動作や、リソースとの相互作用を制御するための設定のこと。
リソースの作成、更新、削除などの挙動を細かく制御できる。

### ・DependsOn属性
スタック内のリソースの作成順を指定するときに使う。
リソースBを作った後にリソースAを作りたい、というときなどに使うとよい。

```
Resources:
  MyBucket:
    Type: AWS::S3::Bucket
  MyBucketPolicy:
    Type: AWS::S3::BucketPolicy
    DependsOn: MyBucket
```

### ・CreationPolicy属性
CloudFormationが、**指定された数の成功シグナルを受信するか、タイムアウト期間を超過するまで、ステータスが作成完了にならないようにする**時に使う。
例えば、EC2インスタンスに特定のソフトウェアがすべてインストールされきるまでは、スタックを完成にしたくないときなどに使うとよい。
```
Resources:
  MyAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    CreationPolicy:
      ResourceSignal:
        Count: 3
        Timeout: PT15M
```

### ・UpdatePolicy属性
リソースの更新方法を指定したいときに使う。
スタックの更新時にAuto Scalingグループ内のインスタンスをまとめて置き換える**AutoScalingReplacingUpdate**や、インスタンスをローリングアップデート(徐々に置き換える)する**AutoScalingRollingUpdate**などを指定できる。
```
UpdatePolicy:
  AutoScalingRollingUpdate:
    MaxBatchSize: 1
    MinInstancesInService: 1
    PauseTime: PT5M
```

### ・UpdateReplacePolicy属性
リソースが更新される際の挙動を設定するときに使う。
以下３つのオプションを指定する。

#### Retain
リソースを置き換える際に、古いリソースを削除せずに保持する。

#### Snapshot
スナップショットを作成できるリソース(EBSボリュームなど)について、リソース削除時にスナップショットを取得する。

#### Delete
リソースを置き換える際に、古いリソースを削除する。

### ・DeletionPolicy
リソースが削除される際の挙動を設定するときに使う。
UpdateReplacePolicyと同様の3つのオプションを指定する。

# ヘルパースクリプト
CloudFormationでは、特定のタスクやプロセスを自動化するためのスクリプトである**ヘルパースクリプト**というものが存在する。
これは、**Metadataセクション**に設定を記述する形で使用する。

### ・cfn-initヘルパースクリプト
メタデータの取得および解析、パッケージのインストール、サービスの開始・停止の処理を実行する。

### ・cfn-signalヘルパースクリプト
EC2インスタンスなどのリソースが正常に作成されたことをCloudForimationの通知する処理を実行する。

### ・cfn-hupヘルパースクリプト
メタデータの変更があった場合に、それを検出して、ユーザー指定の操作を実行する。

### ・cfn-get-metadataヘルパースクリプト
メタデータの内容を取得する。



# CloudFormationのドリフト
**ドリフト検出**を使うことで、スタックの更新後、元との差分を比較できる。
このとき、差分がなければ**IN_SYNC**、差分がある場合は**DRIFTED**と表示される。

# その他

## スタック作成失敗時の挙動
スタックの作成に失敗した場合は、自動的に**ロールバック**が行われる。
リソースA、リソースBまで作成が成功しても、リソースCの作成に失敗した場合は、今まで作成したリソースをすべて削除してロールバックする。

## CloudFormationを実行できるサービス

・AWSマネジメントコンソール
・AWS CLI
・AWS SAM
・AWS CDK
・Code Pipeline