【初心者】AWS CI/CD for Amazon ECS ハンズオン をやってみる

# 1. はじめに
- devops関連の復習をしている。前の記事「[【初心者】CodeCommit, CodeDeploy, CodePipeline を使ってみる](https://qiita.com/mksamba/items/63c87ca7e910eef1e843)」で、初めてcode系サービスのハンズオンを行ったが、もう少し詳しいものをやってみたいと思い、CodeBuildなどが内容に含まれている別のものを実施する。

# 2. やったこと
- AWS Japanから公開されている「[AWS CI/CD for Amazon ECS ハンズオン](https://pages.awscloud.com/rs/112-TZM-766/images/AWS_CICD_ECS_Handson.pdf)」を実施する。
- 2020/4に作成されており少し古いため、そのまま実行できない箇所もある様子だが、まあ大丈夫かなと思いチャレンジする。
- ハンズオンに含まれる内容は以下の通り。
    - ハンズオン1: ECS環境の構築
        - 今回のハンズオンの動作環境となるVPCやALBの構築、サンプルコンテナアプリを作成しECRに登録
    - ハンズオン2: AWS Fargate環境の構築
        - Fargate環境をデプロイしサンプルコンテナアプリを稼働させ、外部からWEBアクセスできることを確認
    - ハンズオン3: AWS Code Services を利用したCI/CDパイプラインの構築
        - 上記のサンプルコンテナアプリの更新をCode系サービスを用いてCI/CD化

# 3. 構成図

![codecommit2構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/0139bb0a-23ed-46eb-8c30-3d79acf9d4b6.png)




# 4. 手順
- ハンズオン手順書はマネージメントコンソールの画面付きとなっており、基本的にそのまま実施可能。つまづいた点などを補足的に記載する。

## ハンズオン1: ECS環境の構築

### VPC作成
- VPC、 Subnet(Public/Private 2個ずつ)、NAT Gateway などをCloudFormationで作成する。指示通りN.Virginiaリージョンで作成する。(別リージョンでも可能だが、後の手順でN.Virginia前提の部分(設定ファイル内にus-east-1の記載など)があり、別リージョンで作業する場合は都度修正必要)
### ALB作成
- 作成するコンテナへのhttpアクセスを中継するためのALBを手動作成する。作成時に必要となるリスナーやターゲットグループをダミーで作成し、すぐ削除する。
### Dockerアプリ開発
- ECRリポジトリを作成する。
    - 可視性設定として「プライベート」を選択する。(もともとは選択肢がなかったが、本ハンズオン資料より後の2020/12に、「パブリック」リポジトリの機能がリリースされている)
- 作業用(gitなどの実行用)として、Cloud9環境を作成する。
    - Platform として、「Amazon Linux 2(recommended)」を選択する。(ハンズオン資料では選択画面なし)
- PHPサンプルアプリ(httpアクセスするとコンテナが稼働するホスト名を返すアプリ)を作成し、ECRのリポジトリに登録する。

## ハンズオン2: AWS Fargate環境の構築
- CodeDeploy用のIAMロールを作成する。
- Fargateクラスターを作成する。
- Fargateタスク定義を作成し、ハンズオン1の手順で作成したコンテナを指定する。
    - オペレーティングシステムファミリーとして、「Linux」を選択する。(ハンズオン資料では選択画面なし)　
- Fargateサービスを作成する。
- ALBにインターネットからアクセスし、PHPサンプルアプリ(ホスト名表示)の結果が表示されることを確認する。

## ハンズオン3: AWS Code Services を利用したCI/CDパイプラインの構築

### 設定作業(手順書どおりに実施)
- CodeCommitリポジトリにファイルを配備する(Cloud9環境でサンプルファイルを編集後、git push)。
- CodePipelineで、パイプラインを作成する。
    - 「出力アーティファクト形式」：「CodePipelineのデフォルト」を選択。
    - build作成時、イメージを「aws/codebuild/standard:6.0」を選択。

- CodePinelineでパイプラインの作成完了後、初回実行が行われるが、まだ全ての設定が済んでいないため失敗する。引き続き手順通りに以下設定を行う。
    - CodeBuildの実行ロールに対してECRのリポジトリ操作の権限を追加する。
    - CodePipelineの設定を編集し、Artifactの選択などを修正する。

### 設定作業(手順書にはない追加作業)

- 手順書通り設定後、パイプラインを実行すると、CodeBuildで失敗する。(以下、ビルドログ)

``` 
[Container] 2022/07/04 09:28:04 Command did not exit successfully $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email) exit status 252
[Container] 2022/07/04 09:28:04 Phase complete: PRE_BUILD State: FAILED
[Container] 2022/07/04 09:28:04 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email). Reason: exit status 252
```

- こちらの記事「[aws ecr get-loginでエラー252](https://www.ninton.co.jp/archives/8514)」で、対処方法が詳しく記載されており、それを参考にbuildspec.ymlを修正する。原因としては、Codebuildの中では現在「ecr get-login」が使えなくなっており、対策として「ecr get-login-password」を使う必要があること。

``` buildspec.yml
# 修正前
- $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)

# 修正後
- DOCKER_URI=https://XXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_URI
```

- 再度、CodeBuildで失敗する。(以下、ビルドログ)

```
Step 1/2 : FROM php:7.4.0-apache
7.4.0-apache: Pulling from library/php
toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
```

- こちらの記事「[AWS CI/CD for Amazon ECS ハンズオンをやってみた](https://dev.classmethod.jp/articles/try-aws-ci-cd-for-amazon-ecs/)」に詳細説明あり。原因はDocker Hubに対する同一SRCIPからのダウンロード制限。対策としては、CodeBuildの実行環境をVPCに変更し、NAT Gateway経由でDocker Hubにアクセスさせる構成に変更する。手順はリンク先のサイトを参照。

- 上記2点を修正した上で、パイプラインを実行すると、無事CodeDeployまでの処理が成功し、Fargate上のコンテナの更新が行われる。また、CodeCommitに対してindex.phpなどのファイルを更新してアップロードすると、パイプラインが再実行され、コンテナが更新されることを確認できる。

# 5. エラーと原因
- ハンズオン実施中、自分の不注意(コピペミス、手順見落としなど)により各種エラーが発生した。備忘のため間違え箇所とエラーメッセージをまとめる。

|エラー位置 |エラー内容 | 原因 |
|---|---|---|
|CodeDeploy| You are missing permissions to access input artifact: BuildArtifact.|buildspec.ymlのインデントミス。「artifacts:」の行に不要なインデントがあり「artifacts:」が「post_build:」 の下に入ってしまっていた。CodeBuildはエラーにならず完了するが、Artifactが出力されていなかった。エラーを見て「Artifactの参照権限がないの？」と思ったがそもそもファイル自体がなかった。
|CodeDeploy| Exception while trying to read the task definition artifact file from: BuildArtifact.|マネコン上での操作ミス。手順上、Deploy実行時に使用するArtifactをBuildArtifactからSourceArtifactへ変更するところがあるが、マネコンで設定画面の「Done」を押した後、「Save」を押すのを忘れて設定が反映されていなかった。
|CodeBuild| [Container] 2022/07/05 07:01:52 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker push $REPOSITORY_URI:latest. Reason: exit status 1 | buildspec.yml で、REPOSITORY_URIの指定時、ハンズオン資料だと us-east-1 になっている。最初、東京リージョンで手順を実行しており、ここを直すのを忘れてリポジトリアクセスに失敗した。

# 6. その他参考サイト
- このハンズオンをやった結果をメモしている記事がいくつかあり、内容把握の参考になった。
    - [Twitter上のメモ](https://twitter.com/YuY_83/status/1530561135183015936)
    - [CodePipelineを利用してECS Fargateでブルーグリーンデプロイメントする](https://tomiko0404.hatenablog.com/entry/2021/10/10/CodePipeline-ECS-BlueGreenDeployment#imageDetail.json%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)

# 7. 所感
- 各サービスの利用の流れを把握するというゴールは達成した。自分でインフラ・アプリを構築する時に使いこなせるかというと、もう少し数をこなして理解を深めることが必要そう。