CloudFormationをゼロから勉強する。（その４：コマンドからの操作）

# はじめに
以前の記事で何度か紹介してきた`Black Belt Online Seminar`の記事ですが、2020年度版が公開されたようです。

- [AWS Black Belt Online Seminar AWS CloudFormation アップデート](https://www.slideshare.net/AmazonWebServicesJapan/20200826-aws-black-belt-online-seminar-aws-cloudformation)

前回からのアップデートの内容や、新たなツールの紹介もされているので、色々と参考になります。

さて、前回はGUI画面上から値を入出力させましたが、今回は今までGUIで行ってきたスタックの作成＆削除をコマンドで操作してみようと思います。

- 【前】[CloudFormationをゼロから勉強する。（その３：パラメータの入出力）](https://qiita.com/sakai00kou/items/fc34771fa3e150979ac8)
- 【次】[CloudFormationをゼロから勉強する。（その５：マッピングと条件式）](https://qiita.com/sakai00kou/items/f562f02fe0fc8719ef65)

# CloudFormationコマンド
普段使いそうなコマンドを抜粋しました。

その他のコマンドや詳細は以下を参照して下さい。

- [AWS コマンドラインインターフェイスの使用](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-using-cli.html)
- [AWS CLI Command Reference (cloudformation)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudformation/index.html)


|内容|コマンド|
|:--|:--|
|スタックの作成（ローカルファイル）|aws cloudformation create-stack --template-body *[ファイル格納場所]* --stack-name *[stack名]*|
|スタックの作成（リモートURL）|aws cloudformation create-stack --template-url *[ファイル格納場所]* --stack-name *[stack名]*|
|スタックの作成（入力項目指定）|aws cloudformation create-stack --template-[body/url] *[ファイル格納場所]* --stack-name *[stack名]* --parameters *[データタイプ（後述）/jsonファイル格納場所]*|
|テンプレートの構文チェック|aws cloudformation validate-template --template-[body/url] *[ファイル格納場所]*|
|スタックイベント履歴の表示|aws cloudformation list-stacks|
|リソースのリスト表示|aws cloudformation list-stack-resources --stack-name *[stack名]*|
|実行中スタックの表示|aws cloudformation describe-stacks --stack-name *[stack名]*|
|スタックの削除|aws cloudformation delete-stack --stack-name *[stack名]*|

- Parametersのデータタイプ

|内容|コマンド|
|:--|:--|
|パラメータに関連付けられた値|ParameterKey=*[string]*,ParameterValue=*[string]*|
|既存パラメータ値の使用|ParameterKey=*[string]*,UsePreviousValue=*[boolean]*|
|SSMパラメータのスタック定義に使用される値|ParameterKey=*[string]*,ResolvedValue=*[string]*|



# 作業用EC2インスタンスへのファイルコピー
前回作成したテンプレートを、「[その１：前準備](https://qiita.com/sakai00kou/items/46e12aa5936b6d6064f2)」で準備した作業用EC2インスタンスに格納しておきます。

今回はコピー後のテンプレート名を`cloudformation.yaml`とします。

```shell:テンプレートファイルのコピー
aws s3 cp s3://cf-templates-xxxxxxxxxxxx-[リージョン名]/xxxxxxxxxx-designer/new.templatexxxxxxxxxxx ./cloudformation.yaml
```

# VS Codeで作業用EC2インスタンスへ接続
「[その１：前準備](https://qiita.com/sakai00kou/items/46e12aa5936b6d6064f2)」で書き忘れていましたが`VSCode`の拡張機能である`Remote Development`をインストールして`Remote Development`でEC2インスタンスに接続します。（`Remote Development`のインストール＆セットアップは、他サイトを参考にして下さい）

# EC2インスタンスの追加
前回のテンプレートに`EC2インスタンス`を追加してみようと思います。

構成は前回作成した`VPC`、`Subnet`の中に新しく`EC2インスタンス`を追加した構成を想定しています。

![capture_25082020_072051.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/1d8b837b-00c1-d355-76c3-16c2427e345f.jpeg)

上図の構成を組んだ際に生成される`EC2インスタンス`のコードは以下となります。

`Resources`セクションの記載は、前回作成したテンプレート内に記載されているので、`Resources`行を抜かしたコードを`VPC`、`Subnet`リソースの後ろにコピペしておきます。

```yaml:EC2インスタンスデフォルト定義
Resources:
  EC2I3Q8S8:
    Type: 'AWS::EC2::Instance'
    Properties:
      NetworkInterfaces:
        - SubnetId: !Ref EC2SJOWQ
```

## 必要パラメータの追加（AMI設定）
「[EC2インスタンスのテンプレートリファレンス](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html)」で必須項目を確認すると`ImageId`が**条件付き**となっている以外は特に必須項目は無いようです。

`ImageId`は`EC2インスタンス`を作成する際に選択する以下`AMI`のIDになります。

![capture_25082020_074203.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/6ff18f42-ec10-9eb6-1517-d841bfb354ff.jpeg)

今回は`Amazon Linx2 AMI (64ビットx86)`の`AMI`を選択しようと思いますが、`EC2インスタンス`テンプレートのエンティティのうち、`InstanceType`のデフォルト値は`m1.small`となります。

ただ、`Amazon Linx2 AMI (64ビットx86)`には`m1.small`のインスタンスタイプは無いため`InstanceType`も明示的に指定する必要があります。

## 必要パラメータの追加（NetworkInterface設定）
EC2インスタンステンプレートリファレンスの「[NetworkInterface](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-iface-embedded.html)」を確認すると、`DeviceIndex`が**条件付き**となっており、今回は`DeviceIndex`の記載も必要となります。

## EC2インスタンスの設定
最終的な`EC2インスタンス`のテンプレートは以下となりました。

```yaml:EC2インスタンス定義
EC2I3Q8S8:
  Type: 'AWS::EC2::Instance'
  Properties:
    ImageId: ami-0cc75a8978fbbc969
    InstanceType: t2.micro
    NetworkInterfaces:
      - SubnetId: !Ref EC2SJOWQ
        DeviceIndex: 0
```

# コマンドからの実行
`EC2インスタンス`の追加も行ったので、実際にコマンド操作でスタックを作成していこうと思います。

尚、後述するコマンドの指定パラメータは以下表の通りとなるので、適宜読み替えて下さい。

|内容|パラメータ|
|:--|:--|
|スタック名|stack-test|
|テンプレートファイルのパス|/home/ec2-user/cloudformation.yaml|
|パラメータファイルのパス|/home/ec2-user/param.json|

## コマンドからのスタック作成
`aws cloudformation create-stack `コマンドで作成が可能ですが、前回の作業で入力項目を追加していることから、`--parameters`オプションで入力項目を追記する必要があります。

```shell:スタック作成（パラメータ直接指定）
aws cloudformation create-stack --template-body file:///home/ec2-user/cloudformation.yaml --stack-name stack-test --parameters ParameterKey=VPCRange,ParameterValue=172.24.0.0/16 ParameterKey=SubnetRange,ParameterValue=172.24.0.0/24
```

パラメータは直接コマンドオプションで記載する以外に、`json形式`のファイルを読み込むことも可能です。（yaml形式不可）

以下、`/home/ec2-user`の配下に`param.json`というパラメータファイルを作成した場合の例。

```json:/home/ec2-user/param.json
[
  { "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
  { "ParameterKey" : "SubnetRange", "ParameterValue" : "172.24.0.0/24" }
]
```

```shell:スタック作成（パラメータファイル読み込み）
aws cloudformation create-stack --template-body file:///home/ec2-user/cloudformation.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json
```

# おわりに
インプットパラメータを長々書くのは可読性が悪く分かりづらいと感じていましたが、ファイルにまとめられるのは良いですね。

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