AWS CodePipelineを使ってAWS CodeBuildでビルドしFargateにデプロイしてみる

## 前置き
書き始めた日付と公開日がかなりずれたため、画像が現状のAWSのものとは異なる場合がございます。ご了承くださいmm

## 概要
下記で作成したものを使って、AWS CodePipelineでFargateにデプロイしてみます。

* [Kotlin+Spring Boot+WebFluxをDockerで動かしてみる](https://qiita.com/yumatsud/items/330fc8a8fd3ddb88b830)
* [Fargateで自作したコンテナイメージを動かしてみる](https://qiita.com/yumatsud/items/0acad37d10a6782ecec8)
* [AWS CodeBuild+Amazon ECRを試してみる](https://qiita.com/yumatsud/items/309c49556b2ac8308a59)

## AWS CodePipelineの設定
基本的には「早速始めてみる」のフローで作成するだけでも設定可能です

###　パイプラインの設定
適当にパイプライン名を設定し、ロールを選択。なければ新規に作成。
<img width="700" alt="スクリーンショット 2019-11-03 16.23.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/fbce9018-dd79-ef2b-bb49-4eb2433f67e1.png">


### ソースの場所
ソースプロバイダはGitHubを選択。
GitHubと連携すると、リポジトリとブランチを選択できるので、該当のリポジトリとブランチを選択。
<img width="700" alt="スクリーンショット 2019-11-03 16.26.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/60b46c2b-acb8-253d-7394-52dbe25042e9.png">


### ビルド
[AWS CodeBuild+Amazon ECRを試してみる](https://qiita.com/yumatsud/items/309c49556b2ac8308a59)で作成したものを選択。

<img width="700" alt="スクリーンショット 2019-11-03 16.28.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/0f233d80-388d-430a-c753-544fd346e862.png">


### デプロイ
デプロイプロパイダーは　`Amazon ECS` を選択し、[Fargateで自作したコンテナイメージを動かしてみる](https://qiita.com/yumatsud/items/0acad37d10a6782ecec8)で作成したものを設定。

<img width="700" alt="スクリーンショット 2019-11-03 16.29.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/e23d2f64-b391-d53c-17fa-59836985e7fc.png">


Image filename は空白でも大丈夫のようです。その場合、imagedefinitions.jsonが利用されるとのこと。


## 作成されたパイプライン
確認画面を経て、作成されたパイプラインは下記。

<img width="700" alt="スクリーンショット 2019-11-03 16.31.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/ae229e50-5dd5-8d61-773e-965009f174ac.png">

## try&error
上記で作成されて、自動的にパイプラインが実行されるが、なかなかうまくいかず＞＜

### 実行権限でエラー
しばらくすると自動的に実行されるが、、、なぜか失敗＞＜
CodeBuildで失敗しているので確認したところ、

```shell
[91m/bin/sh: /work/gradlew: Permission denied
[0mThe command '/bin/sh -c /work/gradlew build' returned a non-zero code: 126
```

CodeBuild上で実行、もしくはGitHubをHookして実行された時はこのようなエラーが出なかったが、
今回はCodeBuildのイニシエーターが `KotlinWebFlux` の場合だけ失敗。

ただし、下記のように実行権限を明示的につけてあげれば無事成功。

```yaml
phases:
  pre_build:
    commands:
    - echo If needing exist before testing, here writing.
    - chmod +x gradlew
```
参考: [コミットが GitHub リポジトリにプッシュされたときに Android アプリをビルドしてテストするパイプラインを作成](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/tutorials-codebuild-devicefarm.html)

### ビルド後のOutput/Inputが合わなくてエラー
実行権限をつけて、無事にテストが通ったと思いきや、今度はビルド部分でエラー、、、エラーログは下記。

```shell
[Container] 2018/10/07 15:21:09 Waiting for agent ping
[Container] 2018/10/07 15:21:09 Waiting for DOWNLOAD_SOURCE
```

ふむふむ、ビルドしたいがDOWNLOAD_SOURCEがなくて怒られる。
CodeBuildをそれぞれ繋ぐだけではダメで、それぞれのOutputを指定してあげないとダメな模様。
今回はGithubから落としてきたソースを全て使うので、下記のようなartifactsを追加。

```yaml:buildspec-test.yml
・・・・・
artifacts:
  files:
    - '**/*'
```
このようにしたら、テスト後のビルドもうまく通るようになった。

### ECSでリソースな見つからないと怒られる
こちらも上記のように `artifacts`　を指定する必要がある。
その指定は、[CodePipeline で ECS にデプロイできるようになり、Docker 環境の継続的デリバリも簡単になりました](https://dev.classmethod.jp/cloud/aws/codepipeline-support-ecs-deploy/) を参考にする限り、タスク定義書を指定すればOKの模様。
上記を参考に下記を追加。

```yaml:buildspec.yml
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - echo Writing image definitions file...
      - echo "[{\"name\":\"kotlinwebflux\",\"imageUri\":\"${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}\"}]" > imagedefinitions.json
artifacts:
  files: imagedefinitions.json
```

・・・・これでも失敗。。。ECSにデプロイできないと怒られる＞＜

### イメージ定義ファイル
`buildspec.json` で吐き出すjsonファイルのフォーマット、吐き出しファイル名が一致しないとダメ＞＜

```json
[
  {
    "name":"<<タスク定義内のnameと同じにしましょ>>",
    "imageUri":"<<ECRのURI>>"
  }
]
```

これで再度実行し、最終的には下記のような画になれば成功。

<img width="700" alt="スクリーンショット 2019-11-03 16.20.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71637/12d52023-cff2-0e21-c883-f35d89b9db7e.png">

→ 最後のコンテナの入れ替えには多少の時間を要するかもしれません。

## 感想
* ポチポチやるだけでbuildからdeployまでのパイプライを作成できるのは楽チン。
* ECSへのデプロイ部分がblackbox化しているのが若干怖い？ ( どのような設定でデプロイがされているのかなど？ ) 気もしましたが、ECSさえ準備できていればCI/CDのパイプラインは簡単に作成できるのは良い。
* ポチポチやると再現性が無くなりそうなので、この辺はTerraformとかで管理できると良さそう ( 複数のコンポーネントがあっても結局は同じことをやりそうなので )
* あとは、、、AWSのドキュメントをちゃんと読めばはまらないので、ちゃんと読むべしですね＞＜ ( 当たり前のことですが、サボるとハマることを学びました )

## 終わりに
この何回かで試したことを実践するチャンスがありました！その辺で考えたことなどは、また書いていければと思います。読んでいただきましてありがとうございましたmm

## 参考
* [CodePipeline で ECS にデプロイできるようになり、Docker 環境の継続的デリバリも簡単になりました](https://dev.classmethod.jp/cloud/aws/codepipeline-support-ecs-deploy/)
* [インフラエンジニアのためのCodeBuild,CodePipelineで覚えるユニットテスト](https://dev.classmethod.jp/cloud/aws/codebuildpipeline-unittest/)