初学者のためのAWS入門(2) CloudFormation入門-1

（2019/09/29 テンプレートで実際に環境を作る際の画面が変更になっているので更新）
#### 初学者のためのAWS入門シリーズ
- [初学者のためのAWS入門(1)] (https://qiita.com/mshinoda88/items/e7557227f7060b52d8ae) 
- 初学者のためのAWS入門(2) - CloudFormation入門1 -> この記事です。 
- [初学者のためのAWS入門(3) - CloudFormation入門2]
(https://qiita.com/mshinoda88/items/65e7e145c7ec943af403) 
- [初学者のためのAWS入門(4) - S3でBasic認証を設定してリポジトリを公開](https://qiita.com/mshinoda88/items/dfb1ee355fbcb08e47e5)
- [初学者のためのAWS入門(5) - S3+Athena+QuickSightでデータ分析結果の可視化](https://qiita.com/mshinoda88/items/54d1d8c3b660e88e6198)
- [初学者のためのAWS入門(6) - Lambdaでサーバレス実行してみる](https://qiita.com/mshinoda88/items/1b44f2a19c0a0895ab60)

# 1. CloudFormation って何？
・AWSリソース（EC2やRDS、S3等）をテンプレート化して自動で構築できる。
・CloudFormation自体は利用無料（利用したインスタンス等のみ料金がかかる）

## 1-1. テンプレート再利用のメリット

- 同じテンプレートを使いまわせる。
- 検証と本番で同じテンプレートを利用することにより、構成を同じにできる。
- AWSの構成を可視化出来る。
- バージョン管理も出来る。

## 1-2. CloudFormationの概念
#### テンプレート
- JSON形式で記述する、AWSリソースのパラメータ。
- 複数のリソースを連携できる（例えば、EC2作成→EIP割り当て等）

#### スタック
- テンプレートによって管理（作成、更新、削除）されるリソースをスタックと言います。
- AWSではリソースはスタック単位で管理されます。
- スタック作成時にスタックで利用するテンプレートを指定する。

# 2. CloudFormation 利用時のワークフロー
## 2-1. 通常利用時のワークフロー
- テンプレート作成
- ローカルまたはS3へ保存
- スタック作成（作成したテンプレートを指定）
- 自動でプロビジョニングされる

## 2-2. スタックの更新時のワークフロー
- テンプレートの修正
- ローカルまたはS3へ保存
- 更新したテンプレートを指定
- 変更したリソースのみ更新される

# 3. 試行環境を準備する
#### 図1 試行環境
![image8.png](https://qiita-image-store.s3.amazonaws.com/0/199265/fb64280d-9e8f-052d-c1ac-ea4eb4abe211.png)

以下のような内容のシンプルな環境を作っていきます。
1. VPC(10.0.0.0/16)を1つ作る。
    VPC名は「My-VPC01」とする。
2. そのサブネット(10.0.1.0/24)を1つ作ります。
    サブネット名は「My-Subnet01」とする。
3. インスタンスがインターネットにアクセスできるようにインターネットゲートウェイを作ります。
    ゲートウェイ名は「My-IGW01」とする。
4. インターネットゲートウェイへのルーティングテーブルを作ります。
    ルーティングテーブル名は「My-Route01」とします。

# 4. 作業の流れ
作業の大まかな流れは次の通り。
1. 環境を定義した「テンプレート」というファイルを作成する。
2. テンプレートファイルをCloudFormationに読み込ませる。
手順としては以上。

- テンプレートはjson形式です。
- CloudFormationは、テンプレートを作成することが全てです。

## 4-1. テンプレートの作成

図1 試行環境 の内容を書き起こすと以下のような感じになります。

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "MyVPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
      "CidrBlock" : "10.0.0.0/16",
      "EnableDnsSupport" : "true",
      "EnableDnsHostnames" : "true",
        "InstanceTenancy" : "default",
        "Tags" : [ {"Key" : "Name", "Value" : "My-VPC01"} ]
      }
    },
    "MyIGW" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [ {"Key" : "Name", "Value" : "My-IGW01"}]
      }
    },
    "MyAttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "InternetGatewayId" : { "Ref" : "MyIGW" }
      }
    },
    "MySubnet" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : "10.0.0.0/20",
        "AvailabilityZone" : "ap-northeast-1a",
        "Tags" : [ { "Key" : "Name", "Value" : "My-Subnet01" } ]
      }
    },
    "MyRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "Tags" : [ { "Key" : "Name", "Value" : "My-Route01" } ]
      }
    },
    "MySubnetAttache" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "RouteTableId" : { "Ref" : "MyRouteTable" },
        "SubnetId" : { "Ref" : "MySubnet" }
      }
    },
    "MyRoute" : {
      "Type" : "AWS::EC2::Route",
      "Properties" : {
        "RouteTableId" : { "Ref" : "MyRouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : { "Ref" : "MyIGW" }
      }
    }
  }
}
```

全体の構造は以下のようなJSON構造になっており、定義の一塊(リソース)を列挙していく。

```
{
  "AWSTemplateFormatVersion" : "フォーマットバージョン",
 
  "Description" : "説明文",
 
  "Metadata" : {
    テンプレートのメタデータ
  },
 
  "Parameters" : {
    スタック起動時にテンプレート渡す値
  },
 
  "Mappings" : {
    キーと名前付きの値を対応付け
  },
 
  "Conditions" : {
    入力パラメータによって評価される条件
  },
 
  "Resources" : {
    テンプレート化するAWSリソース（VPC,EC2など）を記載
  },
 
  "Outputs" : {
    リソースを追加、変更、削除する変更時に出力する内容
  }
}
```

## 4-2. Resources の設定

Resources にはAWSリソースの列挙をします。

```
"Resources" : {
    <リソース>,
    <リソース>,...
    <リソース>
}
```

各リソースは以下のような構造です。
リソースはリソースタイプ毎に作ります。
リソースタイプとは「何を作るか」の種類の指定の事で「Type」で指定します。

```
<リソースID>:{
   "Type" : "AWS::aws-product-name::data-type-name",
   "Properties" : {
　　　      設定値
    }
}
```

指定できるリソースタイプの種類は公式ドキュメントのリファレンスに詳しく書かれています。
[AWS リソースプロパティタイプのリファレンス](https://goo.gl/kFjA8S)

## 4-3. リソースID(論理ID)

最初の「MyVPC」がこのリソースID(論理ID)になります。
これはリソースの名前のことで、利用可能な文字種は、**英数字(A-Za-z0-9)のみ**。
テンプレート内で一意であれば任意で良い。

マネジメントコンソールで操作する時は、リソースID を押下して値設定などの操作を
することになります。

## 4-4. リソースの参照

テンプレートの中にチラホラ出てくる「Ref」の文字ですが、これが先ほど書いた「リソースID」を参照するという意味です。
下記の部分で説明すると「MyVPC」が参照されていますが、参照されるのは
リソース名「MyVPC」で定義されているリソース内容になります。

```
"MyAttachGateway" : {
  "Type" : "AWS::EC2::VPCGatewayAttachment",
  "Properties" : {
    "VpcId" : { "Ref" : "MyVPC" },
    "InternetGatewayId" : { "Ref" : "MyIGW" }
  }
}
```

「MyAttachGateway」のリソースでは、
　　インターネットゲートウェイ「MyIGW」に
　　VPC「MyVPC」をアタッチしようとしています。
実際に作成される際は、「MyIGW」「MyVPC」で定義されたリソース内容を参照して作成されることになります。

## 4-5. テンプレートの記述する順序

テンプレートを書く順番は特には決まっていません。
VPC作ってからサブネット作るという流れに沿って書かなくても、CloudFormation側で内容を解釈して実行してくれます。
しかし、人がメンテしやすいようにある程度順番を意識して書くと、後で見た時にわかりやすい。

## 4-6. テンプレート記述のまとめ

ここまでの内容でまとめると、以下になります。

- 論理IDを適当に宣言する。
- 何を作るのか「リソースタイプ」Typeを指定する。
- 各Type毎に必要な要素を「Properties」で指定する。
- 他のリソースの参照が必要な場合は、参照したい論理IDを指定する。

今回のテンプレートの構造は大まかに以下の通り。

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "MyVPC" : {
      "Type" : "AWS::EC2::VPC",
    },
    "MyIGW" : {
      "Type" : "AWS::EC2::InternetGateway",
    },
    "MyAttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
    },
    "MySubnet" : {
      "Type" : "AWS::EC2::Subnet",
    },
    "MyRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
    },
    "MySubnetAttache" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
    },
    "MyRoute" : {
      "Type" : "AWS::EC2::Route",
    }
  }
}
```

# 5. CloudFormation実行

## 5-1. CloudFormation実行の流れ

作成したテンプレートで実際に環境を作っていきます。
<img width="762" alt="cloudf_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/d78ea577-3da0-1f27-7b9e-74d0fd149e91.png">


CloudFormationの画面で「新しいスタックの作成」を押下。
<img width="1268" alt="cloudf_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/2d2ad7a8-5acf-969f-85a0-3959afc374a9.png">

今回は先ほどのテンプレートをファイルに保存して、ローカルからアップロードします。
S3に保存しておいてそのURLを指定することもできます。
<img width="1211" alt="cloudf_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/1239c6af-0f42-a698-719a-2fbc351da41f.png">
<img width="925" alt="cloudf_04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/d4aab11d-01f6-b8f0-35d8-49c5ce65fe3a.png">

「デザイナーで表示」を押下して表示されるとテンプレートにエラーがないことが
確認できます。
<img width="1040" alt="cloudf_05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/17995c8f-5b30-e18f-53ba-ec0da4cbffc6.png">

#### 参考：JSONチェッカー
[https://lab.syncer.jp/Tool/JSON-Viewer/](https://lab.syncer.jp/Tool/JSON-Viewer/)

## 5-2. テンプレート検証後

テンプレートに問題がなければ次の画面になるので、適当な名前をつけ、「次へ」を押下。
<img width="1216" alt="cloudf_06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/f63dd6e6-4efb-3a79-6a81-48acc57aad4f.png">

タグの指定、IAMロール選択などは必要に応じて指定します。
<img width="1209" alt="cloudf_07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/2863852f-b3cb-6609-9d56-b1d66eb02fd9.png">
<img width="926" alt="cloudf_08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/8b305300-e9ac-3709-6a67-2070dd0368c5.png">

最後に確認して「スタックの作成」を押下すれば実際の作成が開始されます。
<img width="919" alt="cloudf_09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/99fd66bc-d8c0-d894-3cda-e79d45b0a59c.png">
<img width="926" alt="cloudf_10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/1d8a5d46-0fb1-5b6a-fa37-ec9741b9f167.png">

ステータスが「CREATE_IN_PROGRESS」になる。
「CREATE_COMPLETE」になれば作成完了です。
<img width="1069" alt="cloudf_11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/d5d14af7-e865-b0af-a3aa-8e0705361a4c.png">


ステータスが「アクティブ」で絞り込み、確認します。
<img width="1035" alt="cloudf_12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199265/c2b9ec9b-ee31-939a-3f0c-09dfa5be6874.png">

途中で失敗すれば、作成途中でも全てロールバックされます。
途中で失敗するのは、例えば、指定したリソースタイプで使えない「Properties」要素が
入ってしまっている場合などです。

## 5-3. 注意事項

### 作成権限
自動でプロビジョニングさせるにはIAMでの権限が必要
→EC2作成権限がなければ作成はできずに失敗する

### 失敗時
途中で失敗した場合、ロールバックされ、途中まで作成したものは全て削除されます。

# 6. スタックの削除

スタック一覧で、該当スタックを選択、「アクション」→「スタックの削除」でスタックが削除されます。
<img width="753" alt="image4.png" src="https://qiita-image-store.s3.amazonaws.com/0/199265/f97594d6-5dbb-60fe-4e0d-c25776b27cd1.png">

スタックを削除すると、スタック内のAWSリソースはすべて削除される。
→これで、環境一式を作ったり消したりといったことが簡単に出来ます。

### 削除ポリシー
削除ポリシーにより、削除したくないリソースを削除しないように出来ます。（Retain、スナップショット）

# 7. その他

Stack作成時にユーザが動的に値を指定できる「パラメータ」や
リージョン毎にAMIなどを指定できる「マッピング」
といった便利機能もあります。
詳細、応用は別途まとめる。

続きはこちら。
[CloudFormation入門2](http://qiita.com/mshinoda88/items/65e7e145c7ec943af403)

# 参考資料
CloudFormation超入門
http://dev.classmethod.jp/beginners/chonyumon-cloudformation/

AWS CloudFormation とは
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html

AWS リソースプロパティタイプのリファレンス
https://goo.gl/kFjA8S

【AWS】CloudFormationまとめ
http://qiita.com/iron-breaker/items/a12d1228de12663e7d32

CloudFormationのスタックをDeleteしてもデータを残す方法
http://dev.classmethod.jp/cloud/aws/how-to-keep-datas-when-deleting-stacks/

AWS設計図作成ツール
https://www.draw.io/

draw.io awsアイコン
https://www.draw.io/?splash=0&libs=aws2