はじめに
こんにちは、サービス戦略課の森田です。
サービス戦略課では LANSCOPE エンドポイントマネージャー クラウド版の技術的負債解消やフローの自動化など開発者の生産性向上のためのサービス改善に日々取り組んでいます。
今回は AWS CodeBuild のバッチビルド機能を使って、ビルド時間を短縮した方法についてご紹介したいと思います。
AWS CodeBuild のバッチビルドとは
まず、AWS CodeBuild は、開発者がアプリケーションのビルド、テスト、デプロイメントを効率的に管理できる AWS のクラウドベースのサービスです。
CI / CD パイプラインの一部として AWS CodeBuild を活用することで、アプリケーションのビルドプロセスを自動化し、開発プロジェクトの効率性を向上させ、迅速なデプロイメントを実現できます。
しかし、大規模で複雑なアプリケーションでは、ビルドやテストに時間がかかることがあるかもしれません。
AWS CodeBuild のバッチビルドを利用することで、複数のビルドタスクを同時に実行できます。
これにより、ビルド時間を大幅に短縮することができます。
弊社の課題
弊社のあるアプリケーションでは、AWS CodeBuild でのビルドに約 1 時間近くかかっていました。
これにより、開発者がアプリケーションを修正し、AWS 環境にデプロイして動作確認する際、開発者の待ち時間が著しく増加してしまいました。
同様に、本番環境へのリリース作業も時間がかかり、開発者にとって負担となっていました。
ビルド対象のアプリケーションの構成を確認すると、主に以下の 3 つのコマンドが実行されていました。
- API Gateway に統合された Lambda のデプロイ。
- 他のマイクロサービスからのイベントを受けて動作する Lambda のデプロイ。
- 脆弱性を検出するためのスクリプトの実行。
これらの 3 つのコマンドは直列で実行されており、それぞれに時間がかかっていたことから、ビルドに合計で約 1 時間かかっているという状況です。
解決方法
課題解決のために、以下の方法を検討しました。
- ビルドプロセスを並列化する。
- テストを並列化する。
- ビルド成果物をキャッシュする。
- ビルドスクリプトから不要なものを省く。
- コンテナイメージのサイズを小さくする。
- CodeBuild のイメージが旧世代の場合、最新のバージョンに更新する。
- キャッシュされた Docker イメージを利用する。
- ビルド時に不要なソースファイルのアップロードを回避する。
- ビルド実行環境のスペックを向上させる。
- 依存関係のパッケージのダウンロード順序を調整する。
- コンテナのビルドに BuildKit を利用する。
しかし、実際はほとんどの対策が実施されていまして、ビルドプロセスの並列化はできていませんでした。
そこで、費用対効果が高そうだと判断し、取り組むことにしました。
今回、ビルドプロセスの並列化は CodeBuild のバッチビルド機能を活用しました。*1
バッチビルド機能は、以下の 3 つのタイプから選択できます。
- ビルドグラフ:
- 複数のビルドタスクが相互に依存している場合、実行順序を定義し、順次にビルドを実行できます。
- ビルドリスト:
- 複数のビルドタスクを同時に実行できます。
- ビルドマトリックス:
- 同じビルドプロセスで異なるパラメーターが必要な場合、それぞれの組み合わせを並列でビルドできます。
これらのオプションを適切に選択することで、ビルドプロセスを最適化し、効率的な並列ビルドを実現できます。
対象のアプリケーションでは、ビルドタスク間に依存関係はなかったため ビルドリスト
を選択しました。
改修内容
AWS CodeBuild は buildspec ファイルにビルドプロセスを定義します。
改修内容としては、主に buildspec ファイルを変更しています。
変更前
1 つの buildspec ファイルに 5 つのコマンドを定義していました。
buildspec.yml └①脆弱性スキャンの実行 └②API のデプロイ └③Consumer1 のデプロイ └④Consumer2 のデプロイ └⑤Consumer3 のデプロイ └⑥Consumer4 のデプロイ
buildspec ファイルのイメージは以下のとおりです。
version: 0.2 phases: install: runtime-versions: java: corretto8 pre_build: commands: - ①脆弱性スキャンの実行 build: commands: - ビルド実行 post_build: commands: - ②API のデプロイ - ③Consumer1 のデプロイ - ④Consumer2 のデプロイ - ⑤Consumer3 のデプロイ - ⑥Consumer4 のデプロイ cache: paths: - '/root/.ivy2/cache/**/*'
変更後
buildspec ファイルを以下の構成に分割しました。
buildspec_app_root.yml ・・・ ビルド・デプロイを並列で行うためのルート定義。 └buildspec_api.yml ・・・ API └buildspec_consumer.yml ・・・ Consumer(1~4) └buildspec_scan.yml ・・・ 脆弱性スキャン
以下は、それぞれの buildspec ファイルの例です。
# buildspec_app_root.yml version: 0.2 batch: fast-fail: true build-list: - identifier: api buildspec: buildspec_api.yml - identifier: consumer buildspec: buildspec_consumer.yml - identifier: scan buildspec: buildspec_scan.yml
# buildspec_api.yml と buildspec_consumer.yml と buildspec_scan.yml はほとんど同じ以下の内容です。 version: 0.2 phases: install: runtime-versions: java: corretto8 pre_build: commands: - XXXXX build: commands: - XXXXX post_build: commands: - XXXXX cache: paths: - '/root/.ivy2/cache/**/*'
すべての buildspec
ファイルをプロジェクトフォルダのルートに配置します。
buildspec_app_root.yml
ファイルを CodeBuild プロジェクトに設定することで、並行してビルドが実行されます。
権限の付与
AWS CodePipeline から AWS CodeBuild を呼び出す際に、バッチビルドを利用するためには、以下の権限を付与する必要があります。
(適切な権限範囲に絞ってご利用ください。)
- codebuild:StartBuildBatch
- codebuild:StopBuildBatch
- codebuild:RetryBuildBatch
- codebuild:BatchGet*
改善効果
ビルドを 3 つに並列化することで、単純に 3 分の 1 にはなりませんが、大幅に短縮できることが確認できました。
- 改善前:57分21秒
- 改善後:
- API:37分58秒
- Consumer:26分52秒
- 脆弱性スキャン:25分36秒
最も時間がかかる API がバッチビルド全体の最大ビルド時間となります。
つまり、約20分 (34%) の短縮効果を得ることができるため、従来のビルド時間と比較すると、ビルド効率が1.5倍に向上しました。
おわりに
AWS CodeBuild のバッチビルド機能を活用して、ビルド時間の改善に取り組んだ過程をご紹介いたしました。
ここまでお読みいただき、誠にありがとうございます。
本内容がお役に立てれば幸いです。
*1:実際には、バッチビルド機能を利用する以外にも、もう一つの対策を行っています。弊社独自のライブラリを使用したデプロイから、AWS Serverless Application Model (AWS SAM) を使用したデプロイに変更しました。
これにより、最大で 30 分の短縮が可能となっています。この変更については、別の記事で詳しく取り上げる予定です。