Amazon ECS Workshop - Cats and Dogs - をやってみた


# 概要
AWSが公式に提供している、「ECS WORKSHOP - CATS AND DOGS-」をやってみたので、
構築した環境をCloudFormationでテンプレート化してみた。

[ECS WORKSHOP - CATS AND DOGS-](https://dcj71ciaiav4i.cloudfront.net/D0B5A980-C9FC-11EB-ABD7-3362918AE194/)


## (結論)以下にテンプレートを入れました

何なりとお使いください。

https://github.com/bamtech1904/aws-hacks/tree/main/009_ecs-workshop-cats-and-dogs


## どんな環境作ってるの？

こんな環境（ワークショップからそのまま拝借）。

![nw-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/f31e8489-dccd-7bb8-9b0a-5ed49c3df920.png)

# デプロイ手順
以下のリポジトリのソースコードを使って実際にデプロイ。

https://github.com/bamtech1904/aws-hacks/tree/main/009_ecs-workshop-cats-and-dogs

尚、この手順はワークショップを見ればわかるので、
この記事の手順が意味不明な場合は大元を参照してください。

ここでは東京リージョンでデプロイを行っていきます。

## `ecs-c9.yml`のスタックを作成
リポジトリにある`ecs-c9.yml`を使ってCloudFormationスタックを作成。スタック名は適当

## Cloud9をセットアップ
1. 作成されたCloud9 IDE環境にアクセス。

2. 歯車のアイコンをクリックして、Preference の設定画面を開きます。メニューバーの左側から AWS SETTINGS を選択します。

3. AWS Managed Temporary Credentials をオフにします。
  ![ecs-handson001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/4b2e607d-3892-5a87-6e6b-aa185fa179d7.png)

4. 「Preference」タブを閉じます。以下に示す一時的な認証情報を削除するコマンドを実行します。
  ```sh
  $ rm -vf ${HOME}/.aws/credentials
  ```

5. 以下に示す GetCallerIdentity コマンドを実行して、Cloud9 IDEが意図したとおりにecs-demogo-WorkstationRoleを使用しているかどうかを確認します。
  ```sh
  $ aws sts get-caller-identity --query Arn | grep ecs-demogo
  ```

6. CLI ツールのインストールと更新をします。
  ```sh
  sudo pip install --upgrade awscli
  sudo yum install -y jq
  ```

7. 現在のリージョンをデフォルトに設定します。
  ```sh
  export TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
  export AWS_REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
  echo "export AWS_REGION=${AWS_REGION}" | tee -a ~/.bash_profile
  aws configure set default.region ${AWS_REGION}
  ```

  ※ Cloud9で指定したAMIによっては、IMDSのバージョンがv2で強制されている場合がある。Modify instance metadata optionsの設定でIMDSv2がRequiredに設定されている場合は、セッショントークンを使用してリージョンのメタデータを取得する必要があるので注意。
  https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-dynamic-data-retrieval.html

  ![ecs-handson002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/75f2fc64-a3ab-348c-c06a-e2c2ae2b42fe.png)

8. デフォルトリージョンを確認します。
  ```sh
  $ aws configure get default.region
  ```

## `ecr.yml`のスタックを作成
リポジトリにある`ecr.yml`を使ってCloudFormationスタックを作成。スタック名は適当

## Dockerイメージを作成、プッシュ
CloudFormationで作成したcats/dogsリポジトリに、実際にDockerイメージをビルド・プッシュしていく

1. Cloud9のIDEを開く

2. 事前に取り込んでいるフォルダーから、Dockerファイルのあるディレクトリまで移動し、ビルド。

  ```sh
  # catsのDockerイメージをビルド
  $ cd ecsworkshop/cats 
  $ docker build -t cats .

  # dogsのDockerイメージをビルド
  cd ..
  cd dogs
  docker build -t dogs .
  ```

3. ビルドした各Dockerイメージをタグ付けして、各ECRにプッシュ。
   プッシュコマンドは、ECRの各リポジトリを選択すると確認することができる。
   各行の右端の四角いボタンをクリックすると、ステップ1、3、4の各コマンドをコピーできます。

   ![ecs-handson003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/806f59e1-47ce-5ad4-9cb7-60973c298037.png)

  以下はcatsのDockerイメージpushコマンド例
  ```sh
  # 1. Retrieve an authentication token and authenticate your Docker client to your registry.
  aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <YOUR_ACCOUNT_NUMBER>.dkr.ecr.ap-northeast-1.amazonaws.com

  # 3. After the build completes, tag your image so you can push the image to this repository
  docker tag cats:latest <YOUR_ACCOUNT_NUMBER>.dkr.ecr.ap-northeast-1.amazonaws.com/cats:latest

  # 4. Run the following command to push this image to your newly created AWS repository
  docker push <YOUR_ACCOUNT_NUMBER>.dkr.ecr.ap-northeast-1.amazonaws.com/cats:latest
  ```

4. ECRに画像が正常にプッシュされているかどうかを確認します。各リポジトリからlatestというタグ付きイメージが表示されるはずです。

  ![ecs-handson004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/9e569084-a21b-07da-d671-282f98d06ead.png)
  ![ecs-handson005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/9ac7de77-4d7d-0e94-2df7-997be3b3bf65.png)

## `ecs-container.yml`のスタックを作成

リポジトリにある`ecs-container.yml`を使ってCloudFormationスタックを作成。スタック名は適当

**注意点**
**ECSサービスはタスク定義作成後にスタック更新で作成してください**
- ECSクラスター環境が整う前にECSサービスを作成しようとすると、タイミング次第でサーキットブレーカーがトリガーして、スタック作成に失敗する事象が発生
- タスク定義やAutoScalingらへんが原因で作成できないらしい。作成は完了してても直後にECSサービスが作成されようとするとなぜか失敗
- ここでは事前にECSサービスの箇所だけコメントアウトして、クラスター周り作成後にECSサービスをコメントインして、スタック更新で作成している
- CloudFormationテンプレート分ければいいのだが、メンド臭いので今回は割愛（誰かプルリクで修正とかしてくんないかな・・・）

```yaml
  TargetGroup03:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      ...

  ↓↓↓↓↓↓↓↓↓↓↓  以下はコメントアウトしておく  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  #-- ECS Service --#
  # Please comment in the following resources after creating the above resources
  # because the ECS Deployment Circuit Breaker may triggerr and fail to create
  # ECSService01:
  #   Type: AWS::ECS::Service
  #   Properties:
      ...
```

## `ecs-container.yml`のスタックを更新

`ecs-container.yml`のコメントアウトしているリソースをすべてコメントインして、スタックを更新かける。
これでECSサービスと、監視周りのリソースも作成されるはず。

**注意点**
ECS Service Link Roleはまだ作成していない場合は、事前に作成しておく必要がある。
  - サービスリンクロールは最初から用意されてないので、自分で作成が必要
  - コンソール操作だと勝手に自動で作成されるが、CFnだと自分で作成が必要

```yaml
  TargetGroup03:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      ...

  #-- ECS Service --#
  # Please comment in the following resources after creating the above resources
  # because the ECS Deployment Circuit Breaker may triggerr and fail to create
  ↓↓↓↓↓↓↓↓↓↓↓  以下をコメントイン  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  ECSService01:
    Type: AWS::ECS::Service
    Properties:
    ...
```

## 環境構築完了
これでワークショップの環境ができ上がりました。
あとは色々と設定をいじったりして遊んでみてください。

そのまま放置すると、料金がかさむので、使わなくなったら環境を削除しましょう。

## その他苦労した点

- ワークショップの情報が古くなっていたので、
  ECS周りの設定手順は自分で調べつつ進める必要があったりした。

- 公式ワークショップで提供しているCFnテンプレートが実行エラー
  - Cloud9の作成エラーが発生した
  - ImageIdプロパティがテンプレート内に追記されていなかったのが原因、設定したら作成できるようになった