AWS CodeBuild のビルド環境に利用するコンテナイメージについて

[AWS Containers Advent Calendar 2020](https://qiita.com/advent-calendar/2020/aws-containers) の 1 日目の記事です。

突然ですが、AWS CodeBuild というサービスをご存知でしょうか。

AWS CodeBuild は、完全マネージド型のビルドサービスです。
AWS でコンテナワークロードのための CI/CD パイプラインを構築する際、コンテナイメージのビルドに AWS CodeBuild を利用している方も多いのではないかと思います。
（つまり、AWS CodeBuild もコンテナファミリー？の一員ですね！）

本記事では、この AWS CodeBuild について Tips を紹介したいと思います。

### ビルド環境に利用する Docker イメージ

AWS CodeBuild では、ビルドプロジェクトに設定された Docker イメージを利用してビルド環境が作成されます。

ビルド環境の Docker イメージには、ユーザーによるカスタムイメージか、もしくは [AWS CodeBuild が管理している Docker イメージ](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-available.html)を利用することができます。コンテナイメージをビルドするという目的の場合、Docker Engine がインストール済みであるため AWS CodeBuild が管理している Docker イメージをビルド環境に利用している方も多いかと思います。

### イメージバージョンとビルド時間

AWS CodeBuild が管理している Docker イメージには「バージョン」が存在しています。例えば、イメージ `aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.09.14` における **-20.09.14** の部分がイメージバージョンとなります。

このイメージバージョンですが、バージョンの指定内容によってビルド時間が変化することがあります。

例えば、ビルド仕様やビルドプロジェクトの設定など、イメージバージョン以外を同一にした 2 つのビルドを比較してみます。

```shell-session
$ aws codebuild batch-get-builds --ids <MY_BUILD_ID_1> --query 'builds[0].environment.image'
"aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.09.14"
```

```shell-session
$ aws codebuild batch-get-builds --ids <MY_BUILD_ID_2> --query 'builds[0].environment.image'
"aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.08.14"
```

本記事を執筆している 11/30 における、イメージ `aws/codebuild/amazonlinux2-x86_64-standard:3.0` のバージョンを確認してみます。

```shell-session
$ aws codebuild list-curated-environment-images | jq '.platforms[] | select(.platform == "AMAZON_LINUX_2") | .languages[0].images[] | select(.name | endswith("amazonlinux2-x86_64-standard:3.0"))'
{
  "name": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
  "description": "AWS CodeBuild - Docker image based on Amazon Linux 2 (x86_64) with multiple language support",
  "versions": [
    "aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.03.13",
    "aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.05.05",
    "aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.06.15",
    "aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.08.14",
    "aws/codebuild/amazonlinux2-x86_64-standard:3.0-20.09.14"
  ]
}
```

上記より、`MY_BUILD_ID_1` は最新バージョン、`MY_BUILD_ID_2` は一つ前のバージョンを指定してビルドを実行していることが分かります。

ここで、`MY_BUILD_ID_1` と `MY_BUILD_ID_2`、それぞれのビルドにおけるビルドフェーズを比較してみます。

```shell-session
$ aws codebuild batch-get-builds --ids <MY_BUILD_ID_1> --query 'builds[0].phases[].[phaseType, durationInSeconds]' --output table
------------------------------
|       BatchGetBuilds       |
+-------------------+--------+
|  SUBMITTED        |  0     |
|  QUEUED           |  1     |
|  PROVISIONING     |  37    |
|  DOWNLOAD_SOURCE  |  4     |
|  INSTALL          |  0     |
|  PRE_BUILD        |  8     |
|  BUILD            |  3     |
|  POST_BUILD       |  3     |
|  UPLOAD_ARTIFACTS |  0     |
|  FINALIZING       |  2     |
|  COMPLETED        |  None  |
+-------------------+--------+
```

```shell-session
$ aws codebuild batch-get-builds --ids <MY_BUILD_ID_2> --query 'builds[0].phases[].[phaseType, durationInSeconds]' --output table
------------------------------
|       BatchGetBuilds       |
+-------------------+--------+
|  SUBMITTED        |  0     |
|  QUEUED           |  1     |
|  PROVISIONING     |  262   |
|  DOWNLOAD_SOURCE  |  4     |
|  INSTALL          |  0     |
|  PRE_BUILD        |  2     |
|  BUILD            |  2     |
|  POST_BUILD       |  2     |
|  UPLOAD_ARTIFACTS |  0     |
|  FINALIZING       |  2     |
|  COMPLETED        |  None  |
+-------------------+--------+
```

`PROVISIONING` フェーズの所要時間について、`MY_BUILD_ID_1` と `MY_BUILD_ID_2` で大きく差が開いている様子が伺えます。

ではなぜ、このような状況が発生しているのでしょうか。

### 各イメージの最新バージョンはキャッシュされる

AWS CodeBuild が管理している Docker イメージについて、各イメージの最新バージョンはキャッシュされています。これは言い換えると、最新以外のバージョンについては、ビルド時にそのバージョンのプロビジョニングが行われているということになります。

[CodeBuild に用意されている Docker イメージ \- AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-available.html)
> 各イメージの最新バージョンがキャッシュされます。具体的なバージョンを指定すると、キャッシュされたバージョンではなく、そのバージョンのプロビジョニングが CodeBuild によって行われます。これにより、ビルド時間が長くなることがあります。

すなわち、AWS CodeBuild が管理している Docker イメージについては、最新バージョンを指定するとキャッシュが利用できるため、最新以外のバージョンを指定した場合よりもビルド時間が短縮できる、ということです。

なお、最新バージョンの利用については、ビルド環境の設定にて `aws/codebuild/amazonlinux2-x86_64-standard:3.0` のように具体的なバージョンを指定しない形で設定することで、常に最新バージョンを利用するように設定することも可能です。

[CodeBuild に用意されている Docker イメージ \- AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-available.html)
> たとえば、キャッシュのメリットを得るには、aws/codebuild/amazonlinux2-x86_64-standard:3.0-1.0.0 のような詳細バージョンではなく aws/codebuild/amazonlinux2-x86_64-standard:3.0 を指定します。

### 最後に

今回は、AWS CodeBuild が管理している Docker イメージについて、最新バージョンを指定すると最新以外のバージョンを指定した場合よりもビルド時間が短縮できる、という内容について紹介しました。

ビルドの内容が特定のバージョンに依存しない場合は、キャッシュのメリットを受けられるように、最新バージョンを利用してビルドプロジェクトを設定することを検討されてみてはいかがでしょうか。

この情報が、みなさんのビルドライフのお役に立てますと幸いです 🙌