AWS CodeシリーズやGitLabCIを利用したCICDを早くするために実践したこと
はじめに
最近、業務である程度の時間をいただいてAWS Codeシリーズを利用したCI/CDの構築を行う機会をいただきました。
何も考えずに実装してしまうと、1度のデプロイが完了するまでに15分以上を要してしまうなど効率が悪いので試行錯誤して時間を短縮した結果をまとめます。
CICDを早くするTipsはいくつもありますが、私の記事がだれかの役に立てば幸いです。
対象読者
- CICDを構築することになった方
- CICD初心者
- CICDの高速化のための施策を探している方
デプロイするアプリケーションについて
アプリケーション側
バックエンド:
PHP 8.2 Laravel 10
フロントエンド:
TypeScript, Vue.js3
アプリケーションはInertia.jsを利用してバックエンド・フロントエンドをモノリスで開発しているものになります。Inertia.jsのSSR機能を利用するためにビルドを実行する必要があります。
インフラ・CICD側
ソースコードはセルフホスト型のGitLabで管理します。
AWS側のCICDはCodeCommit, CodeBuild, CodeDeployをCodePipelineで定義して実装しています。
CodeCommitとGitLabをミラーリングし、Mainブランチへのマージに対してCICDを発火させる形です。
最終的にはALB以下にあるEC2インスタンスに対してデプロイを行います。
また、GitLabへのMRの作成時に静的解析やテストを自動実行できるよう、GitLab CIのワーカーインスタンスをEC2インスタンスを利用して起動しています。
GitLab CIでやっていること
以下を行います。
- バックエンド側の依存関係のインストール
- フロントエンド側の依存関係のインストール
- PHPStan, PHPmdなどの静的解析の実行
- フロントエンド側のビルドの実行
- PHPUnitを利用した自動テスト
GitLab CIの高速化のためにやったこと
1.GitLab CI ワーカーインスタンスのインスタンスタイプの変更
最初はt3.smallを利用していましたが、t3.mediumに変更しました。
GitLab CIでステージを作成し、複数のJobを実行しようとするとメモリ不足でエラーになってしまうことがありました。
t3.smallからt3.mediumに変更することでメモリが2Gibから4Gibになりギリギリたりるようになるようでした。
t3.largeを利用すれば8Gibになりますが私の環境では時間の短縮やエラーの解決にはつながりませんでしたのでt3.mediumで利用しています。
t3.xlargeにすればCPUを2から4にすることができますが、料金を考えて試していません。
2.GitLab CIのvariablesキーワードをいくつか変更する
Overlay2 ストレージドライバを使用する
DOCKER_DRIVER: overlay2
参考元:
https://qiita.com/baby-degu/items/195b498f2e19f620cc30#4-overlay2-ストレージドライバを使用する
記載しておくだけで10秒程度早くなりました。
GIT_CLEAN_FLAGSを利用する
最初はcompser install と npm instal後に生成される、vendor以下とnode_modules以下をキャッシュして使いまわすようにしていましたが、下記記事を参考にし、キャッシュを使用せず、ジョブの中で使いまわす構成に変更しました。
variables:
GIT_CLEAN_FLAGS: -ffdx -e node_modules/ -ffdx -e vendor/
デフォルトではジョブの実行のたびにgit clean -ffdx
が実行されその後キャッシュをアーティファクトから取得しますが、上記のように設定することでnode_moduleやVendorなどのGitリポジトリにないファイルも削除されないように変更できます。
キャッシュの圧縮・展開にかかる時間をスキップできるとのことで、試したところ1分近く短縮することができました。
3.GitLab CIが利用するDockerイメージに依存関係をプリインストールする
私の環境ではビルドや静的解析を実行するための依存関係としてNode.js、Composer、Java SE 17, Compsoer, phpが必要です。
これらをCIジョブの中でやると異常に時間がかかってしまうので、Dockerのカスタムイメージを利用してCIを実行するように設定しました。
下記公式ドキュメントを参考に実装しました。
CodeBuildの高速化のためにやったこと
1.OSにAmazon LinuxではなくUbuntuを利用する
下記記事を参考にしました。
Amazon Linuxを指定した場合、PROVISIONINGフェーズが非常に長くなってしまいます。
Ubuntuに変更してみたところPROVISIONINGフェーズを短縮することに成功しました。
2.実行環境をECRに保存したカスタムイメージに変更する
GitLab CIでも同じようにカスタムイメージを利用する変更を行いましたが、CodeBuildでも同様に変更しました。
Compsoerなどのインストール時間を短縮できる分30秒程度の短縮につながりました
CodeDeployの高速化のためにやったこと
1.EC2に設定しているターゲットグループの設定を変更
HealthCheckの設定を最小値に設定することでHealthy / Unhealthy の判定を早くすることができ、時間短縮につながります。
また、Connection drainingのパラメータの変更も行いました。
https://qiita.com/tomozo6/items/1c436f594e2cce486153#対応その2-connection-drainingのパラメータを変更してみる
デフォルトでは300秒に設定されているためCodeDeployのbeforeinstallイベントで5分以上かかってしまいますが、ここを10秒程度に短縮することができます。
2.CodeBuildのアーティファクトからvendorやnode_modulesを省きCodeBuildのAfterinstallイベントでインストールする
CodeBuildでビルドのためにインストールを実行するため、そのままアーティファクトに追加しCodeDeployに渡していました。
これをしてしまうとアーティファクトの容量が膨らんでしまい、installイベントやDownloadBundleイベントに時間がかかるようになってしまいます。
アーティファクトからvendorやnode_modulesを外すことによって上記イベントの時間をかなり短縮することができます。
3.composer installやnpm ciのオプションに本番用のオプションを付与する
afterinstallイベントで実行するシェルファイルの中でnpm ci や composer installを実行していますが、上記を実行すると本番運用に必要ない開発用の依存関係が含まれてしまうため、afterinstallイベントが遅くなります。
composer instal -optimize-autoloader --no-dev
npm ci —producton
を実行するように変更しました。
4.package.jsonやcomposer.jsonの依存関係を整理する
あまりない状況かもしれませんが、開発用の依存関係が通常の依存関係に設定されていました。本番運用に必要な依存関係と開発用の依存関係を適切に設定しなおすことで上記の3で行った改善の効果を最大化しました。
実践していないがもっと速度改善につながりそうなこと
以下はコストや環境を考えて試していないですが、調査を進めるうえで目にした施策です。
- デプロイ先のEC2インスタンスタイプを変更する
- CodeBuildの実行環境のスペックをあげる
- GitLab CIのスケーリング
- GitLab CIのインタンスのスペックをあげ、設定のconcurrentの数値を変更し並列実行数を増やす
- CodeBuildのキャッシュを活用
さいごに
いろいろ試したことで最終的にCICDを3分程度まで短縮できました。
課題はありますが、最低限のレベルはクリアできたのではないでしょうか。
実装を進めるうえで数多くの記事を参考にできたのは本当に助かりました。
つたない記事ですがこの記事も誰かの役に立つとうれしいです。
Discussion