AWS CodeBuild+Amazon ECRを試してみる

## 概要
下記でやってみたことを、今度は　AWS　CodeBuildを使い、
Githubのソースコードを取得し、ビルドしたコンテナイメージを自動的に　Amazon　ECRにPushするところまでやってみたいと思います。

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

## Code Buildの設定
今回はコンソール画面上からやってみました。

### プロジェクト
プロジェクト名や説明を入力。
<img width="950" alt="codebuild1.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/3cf71af5-4a87-6fed-b5eb-8ce93774fcf8.png">

### ビルドの対象
対象は、作成済みのGithubリポジトリを指定。
下記の画面は、Githubと連携後の画面で、Githubとの連携が必要です。
<img width="941" alt="codebuild2.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/bbaa66fd-619a-35d2-758d-8baac9e922a3.png">

### ビルド方法
環境は、CodeBuildで管理されているDockerのランタイム環境を利用。
<img width="817" alt="codebuild11.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/83f0ce51-0177-1198-3ccb-ef17288840d9.png">


buildspecは　[サンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker.html)　をそのまま引用してみました。

```yaml:buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build --no-cache -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  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
```

### アーティファクト
今回は設定なし。ビルドしたイメージをS3などに保存しておく場合は利用しても良さそう。
<img width="947" alt="codebuild4.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/1d67c57f-07a8-9051-cc01-d72d32f6e177.png">

### キャッシュ
今回は設定なし。

### ログ
試してみる用のロググループを適当に作成＆設定。
ビルドログなどをS3に保管する必要がある場合は、チェックボックスにチェックして設定する。
<img width="944" alt="codebuild5.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/3e8a507d-871a-04fa-b2f1-bbd88176687d.png">

### サービスロール
「アカウントでサービスロールを作成」で新しいロールを作成する。
既存のサービスロールがある場合は、そちらを利用するでも可能。

### VPC
今回は設定なし。

### 詳細な設定
`buildspec.yaml` で設定した環境変数をこちらで設定しておく※
<img width="956" alt="codebuild6.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/dedc7b3f-c190-fa64-5fce-827c3ce581f6.png">

※本来は、アカウントIDなどを直接書くべきではないと思うので、
実務で運用する場合は、AWS Key Management Serviceなどを使うのが良いかもしれません。

## 確認
ここまで設定し、「続行」で確認画面に遷移したら、「保存してビルド」ボタンでビルドしてみる。
<img width="1388" alt="codebuild7.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/212d617c-a7e2-922c-7645-f2f280e7eaa2.png">

「ビルドの開始を押す」と、ビルドが始まる。
<img width="1397" alt="codebuild8.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/2a3d7738-1b0f-6069-de5a-01047ec09159.png">

そして、、、失敗すると下記のような画面が表示されます＞＜
<img width="1401" alt="codebuild9.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/d29f07f4-5c61-d738-ff05-85c600902879.png">

内容を確認すると、 `pre-build` でこけていました。
<img width="1187" alt="codebuild10.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/fb544c70-55fd-6b0e-05f0-f62b27c2ceaa.png">

そもそもロールの設定などを一切していないので、その辺を見直してみる

## ロールの設定
### ECRの設定
Amazon ECRの対象リポジトリで「アクセス許可」を実施する。
<img width="1395" alt="ecr1.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/e7781c2e-b0f5-f132-46c4-99a6f7e27f6b.png">

設定内容は下記のようなイメージ。
<img width="1158" alt="ecr2.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/3cae9bf3-34cf-c70d-d935-ab0d475017c3.png">

* ステートメント識別子: 適当に設定。
* 効果: 許可
* プリンシパル: 自分のアカウントIDを入力しておく
* IAMエンティティ: CodeBuildで作成されたサービスロールにチェックして選択
* アクション: プッシュ/プルアクション

### IAMの設定
* ロール　→ CodeBuildで作成されたサービスロールを選択
* 「ポリシーをアタッチします」で選択画面へ遷移
* `AmazonECSTaskExecutionRolePolicy` というポリシーをアタッチ

上記で再度実行したところ、下記のようなエラーが、、、

```
AWSCodeBuild-c7551cb9-bc40-416b-8361-0909b267a041 is not authorized to perform:
ecr:InitiateLayerUpload on resource:
arn:aws:ecr:ap-northeast-1:<<ID>>:repository/<<対象リポジトリ>>
```

確かにアタッチしたポリシーでは　`ecr:InitiateLayerUpload`　がない。。。
ECR側の設定だけでは足らなそうなので、新しく作成してしまうことに。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload"
            ],
            "Resource": "*"
        }
    ]
}
```
上記に適当なポリシー名をつけて、再度CodeBuildで作成されたサービスロールにアタッチし、
再度ビルドを実行してみます。
<img width="1191" alt="codebuild12.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/b733a42f-dbcc-ad3b-e2de-f303e533294a.png">
そうすると、無事に全ての項目が完了していることを確認できました。
Amazon ECRの対象リポジトリも更新されていることが確認できるはずです。

## GithubへのPush時の動作確認
CodeBuild設定時に、GithubのWebhookをONにしていたのでそちらの確認をしてみます。
masterブランチに適当な変更を加えてPushしてみたところ、下記のようにBuildが走っていることを確認できました。
<img width="1370" alt="codebuild13.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/672d2acd-e8bd-f7ff-e2fe-f05cde6e52b0.png">
<img width="1201" alt="codebuild14.png" src="https://qiita-image-store.s3.amazonaws.com/0/71637/a4fbc00f-73c7-f680-62cd-2f946fcb16ad.png">

## 追加でやりたかったところ
ここまでの内容はあくまで `build` して `ECRにPush` するところにフォーカスしましたが、
テストコードの実行ができていないので、テストが完了したらビルドするというのがあると良さそうですね。
ちなみに単純に `buildspec.yml` にテスト実行を埋め込んでも、
今回選択した環境がDockerの環境で、Javaの環境ではないのでテスト実行ができませんでした。
テスト用の　`buildspecファイル` を用意して実施するのが良い？等は別で検証してみたいと思いますmm

## 参考
* [サンプルコード](https://github.com/beta-yumatsud/kotlinwebflux)
* [AWS CodeBuild の Docker サンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker.html)
* [AWS CodeBuild の Amazon ECR サンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-ecr.html)
* [AWS CodeBuild のビルド通知サンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-build-notifications.html)
* [AWS CodeBuild の GitHub プルリクエストサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-github-pull-request.html)