CodeBuildでバッチビルド（並列ビルド）を導入しようとしたけどできなかった話

# 概要

元々、単一のLambda関数のビルドからデプロイまでをCodeBuildを利用して行っていたのですが、Lambda関数をいくつか追加する要件が発生したため、一つのCodeBuildから複数のアプリケーションをビルドし、それぞれのLambda関数にデプロイをできるように変更しました。
この時点では特にデプロイ時間も気にならないほど速かったため直列でビルドする定義で設定を行いました。並列ビルドも考えたのですが、これを行うためにはCodePipelineでビルドステージを複数作る必要があり、インフラ定義もいじらないといけないため、作業ボリュームが見合っていないと感じたため実施しない判断をしました。

しかし、2020/7/30に「[AWS CodeBuild がビルドプロジェクトの並列実行と協調実行のサポートを開始](https://aws.amazon.com/jp/about-aws/whats-new/2020/07/aws-codebuild-now-supports-parallel-and-coordinated-executions-of-a-build-project/)」の発表があり、みた感じ容易に導入できそうだったため使ってみることにしました、ができなかったという話を記事にまとめたいと思います。

# 現状の構成

デプロイパイプラインの構成は以下のようになっています。
CircleCIからS3にソースファイルをPUTしたイベントをCodePipelineが検知し、それを契機にCodeBuildでビルドを行い、Lambdaの更新を行う流れです。

![CodeBuildの並列ビルド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/25ef922c-c14b-e771-6fc0-20ae2d6304e0.png)


# 試したこと
## buildspecの編集

[こちら](https://docs.aws.amazon.com/codebuild/latest/userguide/batch-build-buildspec.html#build-spec.batch.build-matrix)のページを参考にbuildspecを編集しました。
今回はGoアプリケーションでビルドの検証を行いました。


### buildspecの変更前（直列ビルド時）

以下は直列ビルド時のbuildspecの内容になります。
hogehogeアプリケーションとfugafugaアプリケーションをそれぞれ順番にビルドしてバイナリを生成し、その後LambdaにUpdateをかけるという流れです。
（こちらはちゃんと動く定義です）

```yaml
version: 0.2
phases:
  install:
    runtime-versions:
      golang: 1.14
  build:
    commands:
      - echo Build started on `date`
      - echo Building the lambda source...
      # golang build - hogehoge
      - cd $CODEBUILD_SRC_DIR/lambda/hogehoge
      - GOOS=linux GOARCH=amd64 go build -o Handler
      - zip $CODEBUILD_SRC_DIR/HogehogeHandler.zip Handler
      # golang build - fugafuga
      - cd $CODEBUILD_SRC_DIR/lambda/fugafuga
      - GOOS=linux GOARCH=amd64 go build -o Handler
      - zip $CODEBUILD_SRC_DIR/FugafugaHandler.zip Handler
  post_build:
    commands:
      - echo Update lambda on `date`
      - echo Updating lambda function...
      - cd $CODEBUILD_SRC_DIR
      # update lambda function - hogehoge
      - LAMBDA_FUNCTION_NAME_HOGEHOGE=$(aws ssm get-parameter --region ap-southeast-1 --name /lambda_func_name/hogehoge --with-decryption --query 'Parameter.Value' --output text)
      - aws lambda update-function-code --function-name ${LAMBDA_FUNCTION_NAME_HOGEHOGE} --zip-file fileb://HogehogeHandler.zip --publish
      # update lambda function - fugafuga
      - LAMBDA_FUNCTION_NAME_FUGAFUGA=$(aws ssm get-parameter --region ap-southeast-1 --name /lambda_func_name/fugafuga --with-decryption --query 'Parameter.Value' --output text)
      - aws lambda update-function-code --function-name ${LAMBDA_FUNCTION_NAME_FUGAFUGA} --zip-file fileb://FugafugaHandler.zip --publish
```

### buildspecの変更後（並列ビルド）

こちらは並列ビルドに対応できると考えて作ったbuildspecになります。
サンプルをみたところ、build-listに記載した定義が一つの単位としてphasesを実行していくように読み取れたため、phasesの定義を共通で利用できる形に書き換えました。ビルド定義のうち、個別に値を設定する箇所についてはbuild-list内に環境変数として設定しました。
（前述の通り今回はできなかった話なので、この定義が動作するか実際には確認できていません。申し訳ありません。）


```yaml
version: 0.2
batch:
  fast-fail: false
  build-list:
    - identifier: hogehoge-deploy
      env:
        variables:
          BUILD_PATH: ${CODEBUILD_SRC_DIR}/hogehoge
          HANDLER_NAME: HogehogeHandler
          SSM_PATH_FUNC_NAME:  /lambda_func_name/hogehoge
    - identifier: fugafuga-deploy
      env:
        variables:
          BUILD_PATH: ${CODEBUILD_SRC_DIR}/fugafuga
          HANDLER_NAME: FugafugaHandler
          SSM_PATH_FUNC_NAME:  /lambda_func_name/fugafuga
phases:
  install:
    runtime-versions:
      golang: 1.14
  build:
    commands:
      - echo Build started on `date`
      - echo Building the lambda source...
      - cd ${BUILD_PATH}
      - GOOS=linux GOARCH=amd64 go build -o Handler
      - zip $CODEBUILD_SRC_DIR/${HANDLER_NAME}.zip Handler
  post_build:
    commands:
      - echo Update lambda on `date`
      - echo Updating lambda function...
      - cd $CODEBUILD_SRC_DIR
      - LAMBDA_FUNCTION_NAME=$(aws ssm get-parameter --region ap-southeast-1 --name ${SSM_PATH_FUNC_NAME} --with-decryption --query 'Parameter.Value' --output text)
      - aws lambda update-function-code --function-name ${LAMBDA_FUNCTION_NAME} --zip-file fileb://${HANDLER_NAME}.zip --publish
      - echo Update lambda end on `date`
```


## ビルドの実行、そして失敗

![ビルド失敗.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/61073979-de4f-017e-3a13-3ba071693223.jpeg)

上記のキャプチャの通り、ビルドの実行に失敗しました。ログを確認したところ、そもそも並列ビルドもされてないように見えました。
なぜうまく動かなかったか調べていきます。

## 原因調査

ドキュメントベースで調べたところ、並列ビルドを行う場合はビルドタイプとしてバッチビルドという従来のビルド方法とは別のオプションを選択する必要があることがわかりました。
AWSコンソールのCodeBuildサービスからバッチビルドを選択できそうだったので実行してみたところ、以下のキャプチャに示す警告が表示されました。
![バッチビルドの有効化.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/2da5d51f-9d5f-6f48-3641-344ff0db4edb.jpeg)

「アーティファクトの無効化」にチェックを入れて実行したところビルドは開始されたのですが、そのせいかS3からソースのバイナリが取得できず、ビルドは失敗に終わりました。
警告文には直接的に書かれていませんが、どうやらCodePipelineの管理下にあるCodeBuildではバッチビルドは使えなさそうな気配を感じました。
この時点で詰んだなと思いました。

結論として、CodePipelineの管理下のCodeBuildではバッチビルドは利用できないようです。

# 終わりに

調査や開発にそこまで時間を取ったわけではありませんが、無駄な時間を使ってしまったのは間違い無いので、できないとわかったときには徒労感に襲われました。また、ドキュメントでは「バッチビルド」、「バッジビルド」といった表記揺れがあり、検索する際に若干苦しみました。

ドキュメントを眺めつつ実際に動かして、失敗したところから本格的にドキュメントを読み漁ったのですが、事例が少ない中でドキュメントをよく読みもせずに手を動かしてしまった点は反省したいと思います。