はじめに
こんにちは。 開発2部の浅香です。
私たちのチームではDependabotを使ってフロントエンドのパッケージのバージョン管理や、脆弱性のチェックを行っています。
今回の記事ではDependabotとは何かといったようなツールの説明は行わず、どのようなフローでDependabotを使用しバージョンアップデートを定期的に行っているのかという運用方法についてご紹介していきます。
なぜDependabotを使うのか?
そもそもなぜDependabotを使ってパッケージのバージョン管理をしているのでしょうか?
改めて理由を考えてみると2点挙げられます。
セキュリティ関連のアラート情報に自動で気づける
Dependabotアラート機能を設定することにより、依存するパッケージにセキュリティアップデートが発生したタイミングで 迅速に更新用のPull Request(以下PR)を作ってくれます。
これは常に使用するパッケージを把握し、それらのパッケージの更新に対してアンテナを張り続けていれば対応できますが、 Dependabotであれば自動的に対応してくれます。
パッケージの最新機能をすぐに使える
DependabotがPRを自動生成してくれることによりすぐにそのパッケージのリリース内容を知ることができます。 対象パッケージの最新機能をproduct開発に使用することで、車輪の再発明を防ぐことができます。
運用課題について
Dependabotを運用し始めた頃、以下のような課題が出てきました。
放置されてしまう
私たちのフロントエンドでは数多くのパッケージを使用しています。
devDependency、dependency, パッチバージョンからマイナーバージョンのアップデートまで全ての変更を監視しているとすぐに数十個のPRが出来上がってしまい、どれから手をつけて良いのかわからなくなってしまいました。
また定期的に確認するような仕組み作りもできていなかったため出来上がったPRが滞留してしまっている状態でした。
PRが大量に生成される
Dependabotの設定を行いPRを自動作成してくれるようになりました。 しかし、すぐに大量のPRが作成されてしまうため、毎回差分を確認してマージしていく作業が負担となっていました。
目視で確認しなくても良いPRに関してはなるべく自動化したいと考えていましたが、自動化のためのワークフローが未整備でした。
管理が属人化する
運用フローを定義するまでは、フロントエンドが得意なエンジニアが空いた時間でPRを処理していくという状態になっていました。 メンテナンスを積極的に行っていたエンジニアが他プロジェクトへ移動してしまうと、その運用知識が失われるといった、属人化した状況に陥っていました。
課題の解決策
上記の放置されてしまう, PRが大量に生成される という課題を解決するために自動アップデートのためのワークフローを設定しました。
また管理が属人化する 点については、エンジニアが隔週で集まりアップデートのためのテストを行う時間を確保し、運用のための知識を標準化するように変更しました。
基本的な方針としては、自動化できるものは自動アップデートのワークフローを組んで自動化し、できないものは手動アップデートを定期的に行うようにしました。
この章では自動アップデート、手動アップデートそれぞれのアップデートするまでのフローをご紹介します。
自動アップデートの運用
パッケージのインストール方法の違い、バージョンの違いごとに6つのパターンに分類しました。
自動アップデートでの更新をするパターンを2パターン選定し、その場合に自動的にアップデートを行い、本番環境にリリースしてくれるようなフローを構築しました。
自動アップデートの場合のフローは以下のようになっています。
- DependabotがPRを作成
- 自動アップデートか手動アップデートかを判定するワークフローが実行される
- 2のワークフロー上で自動マージ対象かつCIをパスしたら、Staging環境にデプロイ
- Stagingにマージ完了後、Staging環境上でE2Eテストを実行
- E2Eテストをパスしたら本番環境にリリース
手動アップデートの運用
自動化のワークフローのCIで落ちてしまったPRと自動アップデート対象ではない4つのパターンは隔週でエンジニアが集まる時間をとって、その時間内に確認するような体制を取りました。
フローは以下のようになっています。
- 対象のPRを洗い出す
- 手動アップデート対象のPRのリリースノートを確認し、破壊的な変更がされていないか確認
- 2で問題なければ、Staging環境にマージ
- E2Eテストの実行
- モンキーテストで最終チェックを行う
- 本番環境にリリース
実装・設定方法の紹介
自動アップデートの2で実装しているワークフローをご紹介します。 自動アップデート対象か手動アップデート対象かを判定し、自動アップデート対象だった場合に Staging環境へのマージまで行うワークフローになっています。
# See: https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/automating-dependabot-with-github-actions#enable-auto-merge-on-a-pull-request name:Dependabotauto-merge on: pull_request permissions: pull-requests: write contents: write jobs: call-test: # dependabotで作成されたPRのみを対象とする if: ${{ github.actor == 'dependabot[bot]' }} # FE関連のbuild, lint-check, unit testなどを実行 # ここで落ちた場合はコードの編集が必要なため、次のステップには進まない。 uses: buysell-technologies/{リポジトリ名}/.github/workflows/_test.yaml@staging secrets: inherit dependabot: needs: call-test runs-on: ubuntu-latest steps: - name:Dependabotmetadata id: metadata uses: dependabot/fetch-metadata@v1.1.1 with: github-token: '${{ secrets.GITHUB_TOKEN }}' # devDependencyのマイナーバージョン更新の場合は `IS_DEV_DEPENDENCY_MINOR` フラグをtrueにする - name: Declare env variable (devDependency minor output) run: echo "IS_DEV_DEPENDENCY_MINOR=${{ steps.metadata.outputs.dependency-type == 'direct:development' && steps.metadata.outputs.update-type == 'version-update:semver-minor' }}" >> $GITHUB_ENV # devDependencyのパッチバージョン更新の場合は `IS_DEV_DEPENDENCY_PATCH` フラグをtrueにする - name: Declare env variable (devDependency patch output) run: echo "IS_DEV_DEPENDENCY_PATCH=${{ steps.metadata.outputs.dependency-type == 'direct:development' && steps.metadata.outputs.update-type == 'version-update:semver-patch' }}" >> $GITHUB_ENV # 自動アップデート対象の場合はマージする。 - name: Enable auto-merge forDependabotPRs if: ${{ env.IS_DEV_DEPENDENCY_MINOR == 'true' || env.IS_DEV_DEPENDENCY_PATCH == 'true' }} run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Approve a PR if: ${{ env.IS_DEV_DEPENDENCY_MINOR == 'true' || env.IS_DEV_DEPENDENCY_PATCH == 'true' }} run: gh pr review --approve "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
導入後の変化
自動化のワークフロー導入後の変化としては以下です。
Before
導入する前はPRの自動生成は行っていましたが定期的なメンテナンスはしていませんでした。
気づいた時に不定期でフロントエンドが得意なエンジニアが一括アップデートをしていました。
1回の対応で2時間ほど時間がかかり注意してみるべきPRも特定できない状態でした。
After
自動アップデートされるものは随時マージされるようになり、手動アップデート対象のもののみを定期的にメンテナンスするようになりました。
頻度としては2週間おきに、エンジニアが集まりPRをマージする時間をとるようにしました。
注視するべきPRのみが残っている状況なので、事前準備を含めて1時間以内で全てのパッケージをアップデートできるようになりました。
当初課題としていた、チームの入れ替え前後で俗人化してしまう という課題については定期的にエンジニアが集まる時間を作ることで解決できました。
また、その時間内にパッケージについての知見の共有もできることで、副次的なメリットも得ることができました。
課題
ここまで書いてきたような運用ルールの整備やワークフローの実装を行い、当初課題として挙げられていた箇所は改善されました。
しかし、まだ解決できていない課題もあります。
dependancyは全て手動更新が必要
当初はdependancyのパッチバージョンは自動アップデートで運用していました。
しかし別の対応で動作確認をしている最中にこのバージョンアップが原因のバグを偶然発見しました。
幸い、大きな障害にはつながらなかったのですが、それ以来、dependancyは全て手動アップデートする運用に切り替えました。
このバグはE2Eテストで異常系までをカバーしていれば検知できたものです。 そのため今後はE2Eテストの対象を増やすことで、今手動になっているパターンに対しても自動アップデートを適応できるようにしていきたいと思っています。
まとめ
以上のような仕組みを作ることで、ライブラリのバージョンアップを半自動化できました。
自動化のワークフローや、自動化・手動化の使い分けなどDependabotの運用方法に困っている方の参考になれば幸いです。
今後の展望としては自動化の範囲はまだ少なく、手動での確認も残っているのが現状のため、 E2Eテストをより充実させて自動化の範囲を広くして、運用工数を減らしていきたいと考えています。
最後にBuySell Technologiesではエンジニアを募集しています。興味がある方はぜひご応募ください。