AWS CodeBuild をローカルでデバッグする CodeBuild Local 入門

簡単に
========

1. https://github.com/aws/aws-codebuild-docker-images を clone
2. `aws-codebuild-docker-images/ubuntu/standard/2.0/Dockefile` をビルド ( これがビルド用イメージになる )
    * マシンスペックにもよりますが、 Core i7 の Macbook で 20 分程度かかりました
3. ヘルパースクリプト `aws-codebuild-docker-images/local_builds/codebuild_build.sh` を利用して CodeBuild Local 起動

```bash:Getting-started
$ git clone https://github.com/aws/aws-codebuild-docker-images.git
$ docker build -t aws/codebuild/standard:2.0 ./aws-codebuild-docker-images/ubuntu/standard/2.0/
$ ./aws-codebuild-docker-images/local_builds/codebuild_build.sh -i aws/codebuild/standard:2.0 -s /path/to/src -a ./artifacts
```

CodeBuild の `buildspec.yml` のデバッグがつらい！！
=========

CodeBuild の `buildspec.yml` を書いているとき、こんなことありませんか？

* `buildspec.yml` のちょっとした修正の動作確認をしたいけど、この修正でいいかわからない
* 修正途中のコミットを push したくない、後でコミットログを整理したくない
* 修正途中のソースでパイプラインが走りきって、ビルドされたコンテナイメージをリポジトリに push してしまうとまずい
* CodeBuild の待ち時間が長い

それ、 CodeBuild Local なら解決できるかもしれません。

CodeBuild Local とは ？
========

[aws/aws-codebuild-docker-images - GitHub][aws-codebuild-docker-images]

* AWS が提供する CodeBuild のビルド用イメージの Docker ファイルと、それを動かすための Agent Docker イメージとヘルパースクリプト
* ローカルで `buildspec.yml` を走らせてデバッグできる
* 本物の CodeBuild 同様、複数ソースをインプットとしたり、アーティファクトの出力もできる

やってみよう ！
========

CodeBuild Local を簡単に体験できる Makefile を書きました。
使い方がわかってきたら、実際にプロダクトに組み込んでみると良いと思います。

[ikasam/codebuild-local-getting-started - GitHub](https://github.com/ikasam/codebuild-local-getting-started)

```bash:getting-startedの使い方
$ git clone https://github.com/ikasam/codebuild-local-getting-started.git
$ cd codebuild-local-getting-started
$ make
```

## 動作確認環境

* Docker Desktop for Mac v2.1.0.1 (37199)
    * Engine: 19.03.1
* GNU Make 3.81

ヘルパースクリプト `codebuild_build.sh` の使い方がわかれば CodeBuild Local が分かる！!
========

## ヘルパースクリプトがやっていること

スクリプトに渡されたオプションから、実際に実行する `docker` コマンドを組み立てて実行します。最終的にどういうコマンドが実行されるかは、スクリプト実行時の最初に表示されます。

```bash
$ ./aws-codebuild-docker-images/local_builds/codebuild_build.sh \
-i aws/codebuild/standard:2.0 -e ./codebuild.local.env -s . -a ./artifacts
Build Command:

docker run -it -v /var/run/docker.sock:/var/run/docker.sock -e \
"IMAGE_NAME=aws/codebuild/standard:2.0" \
-e "ARTIFACTS=/Users/m_kanno/ikasama/codebuild-local-getting-started/artifacts" \
-e "SOURCE=/Users/m_kanno/ikasama/codebuild-local-getting-started/." \
-v "/Users/m_kanno/ikasama/codebuild-local-getting-started:/LocalBuild/envFile/" \
-e "ENV_VAR_FILE=codebuild.local.env" \
-e "INITIATOR=m_kanno" amazon/aws-codebuild-local:latest
```

※ 見やすさのために出力を改行しています

## 少しクセのあるオプションたち

ここの README にだいたいのことが書いてありますが、少しクセがあるので補足説明をしておきます。

https://github.com/aws/aws-codebuild-docker-images/tree/master/local_builds

| オプション | 意味 | 必須？ |
|:--|:--|:--:|:--|
| `-i` | ビルド用イメージ         | ○ |
| `-a` | アーティファクト出力先     | ○ |
| `-l` | agent イメージを指定する | |
| `-c` | AWS CLI の設定       | |
| `-p` | AWS CLI のプロファイル  | |
| `-b` | `buildspec.yml` の指定 | |
| `-e` | 環境変数 | | env ファイルだけ渡せる |
| `-m` | ソースディレクトリをホストから Volume Mount | |
| `-s` | ソースディレクトリの指定 | |

### `-i` ビルド用イメージ

* カスタム用ビルドイメージはここで指定します

### `-c`, `-p` AWS CLI の設定、プロファイル

* `~/.aws/config`, `~/.aws/credential` をビルド用イメージ内にコピーします
* 例えば、 AWS のリソースにアクセスする際に必要です
    * ECR からイメージを pull するとか
* プロファイルを指定したい場合は `-c` に加えて `-p your_profile` も指定します

### `-e` 環境変数

* ファイルだけ渡せる
* `-e MYENV=hoge` というような渡し方はできません
* 一般的な env ファイルフォーマット
    * 細かい仕様は README に書いてあります
* ローカルで走らせたくない処理があるときは、環境変数で制御すると良いです
    * `CODEBUILD_CI` は CodeBuild 上では `true` となるので、ローカルでは `false` を渡して if で分岐するとか

```bash:環境変数で制御する例
if $CODEBUILD_CI; then echo This line is executed only in the real CodeBuild environment; fi
```

### `-m` ソースディレクトリをホストから Volume Mount

* うまく使うとソース転送時間を短縮できます
* マウント先にビルドの中間生成物を作ったあと削除しないと、ホスト上に中間生成物が残ります

### `-s` ソースディレクトリの指定

* 省略するとカレントディレクトリをソースとします
* 複数ソースを指定する場合、 2 つ目以降は `-s <sourceIdentifier>:<sourceLocation>` の形式で指定します
* `buildspec.yml` の中では、 `$CODEBUILD_SRC_DIR_<sourceIdentifier>` で参照できます [^primary-source]

2 つの異なる Docker イメージ
========

## ビルド用イメージ

ビルド環境となる Docker イメージです。
CodeBuild が標準で提供しているイメージを利用したり、プロジェクトによってはカスタムイメージを用意します。 getting-started では CodeBuild 標準の `aws/codebuild/standard:2.0` を利用しています。
`aws/codebuild/standard:2.0` は、CodeBuild のコンソールでは環境設定で設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62103/5e5f8f7b-cd59-ae15-a8c9-17a0a116d2c5.png)

## CodeBuild Local Agent (agent イメージ)

[AWS CodeBuild Local Builds][aws-codebuild-local-agent]

CodeBuild をエミュレートする Docker イメージです。
こいつが `buildspec.yml` を解釈し、ビルド用イメージ上でのビルドを指示します。
Dockerfile などは公開されていおらず[^agent]、 Docker Hub からイメージを pull して利用します。

CodeBuild Local の制限事項
========

`buildspec.yml` 上での Docker の Volume mount がうまく動きません。
これは、以下の環境差異によるものです。

* CodeBuild: OS [^maybe-ec2]上の Docker でビルド用イメージを動かす
* CodeBuild Local: Docker コンテナ (agent) からホスト OS の Docker でビルド用イメージを動かす 

Docker デーモンが動いている場所とマウントしようとする場所が違うので、 CodeBuild Local では Volume mount がうまく動きません。[^volumemount]

まとめ
========

* CodeBuild Local で `buildspec.yml` を手軽に動作確認できます
* CodeBuild Local を簡単に体験できる Makefile を[作りました](https://github.com/ikasam/codebuild-local-getting-started)。ぜひ試してみてください！
* ヘルパースクリプト `codebuild_build.sh` の使い方をマスターしよう！
* 一部制限事項があるので、気をつけましょう

参考
========

* [CodeBuild のビルド環境リファレンス](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref.html)
* [aws/aws-codebuild-docker-images - GitHub][aws-codebuild-docker-images]
* [AWS CodeBuild Local Builds][aws-codebuild-local-agent]

[aws-codebuild-docker-images]: https://github.com/aws/aws-codebuild-docker-images
[aws-codebuild-local-agent]: https://hub.docker.com/r/amazon/aws-codebuild-local
[^primary-source]: Primary Source は `$CODEBUILD_SRC_DIR`
[^agent]: CodeBuild のリファレンス実装だからかな？
[^maybe-ec2]: たぶん EC2
[^volumemount]: 個人的には CI のパイプラインで Docker Volume Mount するのはあまり筋が良くないと思うので避けたほうがいいと思います