データプラットフォームグループ Livesense Brain チームの富士谷です。 機械学習基盤 Livesense Brain の開発・運用を行っています。
ここでは、Livesense Brain で開発するシステムのバージョニングの見直しと、 GitHub Actions を使ったタグ・リリース作成の自動化について紹介したいと思います。
はじめに
Livesense Brain では、開発するシステムのほとんどをコンテナ化しており、大きく「アプリケーション」と「コンポーネント」の2つに分けて開発しています。 「アプリケーション」は、例えば「マッハバイト向けのレコメンド」といった、特定の事業部向けにデータやサービスを提供するコンテナイメージを指します。 また、全社向けのA/Bテスト基盤(Brain Optimizer)も「アプリケーション」に位置づけています。
一方、「コンポーネント」は、複数の「アプリケーション」で共通して使える機能を切り出したコンテナイメージを指します。 例えば、レコメンドアルゴリズムをまとめたものや、自然言語処理の実装をまとめたものがあります。コンポーネントを開発した背景などは、こちらの資料をご確認ください。
事業横断組織でのMLシステム開発・運用と基盤設計 - Speaker Deck
アプリケーションやコンポーネントのリポジトリでは、master/mainにマージするかタグを作成したタイミングで、Cloud Buildを用いて、イメージがビルドされるようにしています。 また、GKEなどにデプロイする際に、利用するコンテナイメージのバージョンを指定するため、タグを付けて、バージョニングを行っています。
デプロイは以下のような流れで行っています。
- 各リポジトリでバージョン名のタグ・リリースを作成する
- manifestsを管理するリポジトリで、デプロイするコンテナイメージのバージョンを記載したPRを作りマージする
デプロイを集中管理する、という点について詳しくは、先日のblog記事をご確認ください。 made.livesense.co.jp
これまでの課題
これまで、アプリケーション、コンポーネントともに、セマンティックバージョニング(SemVer)を利用していました。SemVerは、後方互換性がある改変であるかがわかるため、複数のアプリケーションで利用されるコンポーネントには有用でした。 しかし、アプリケーションでは、その改変の影響を受けるものはコンポーネントに比べて少なく、後方互換性がない改変も多くなりがち(例えば、A/Bテストの開始・終了などmanifestsで管理するWorkflowなどの改変が必要なときには毎回メジャーバージョンを上げていた)で、SemVerのメリットをあまり享受できていませんでした。
さらに、リリース担当者が、前回のリリース以降のPRを確認し、メジャー・マイナー・パッチいずれのバージョンを上げるかを考えて、GitHub で手作業でタグ・リリースを作成しており、小さいながらも負担がありました。
まとめると、課題は以下のとおりです。
- アプリケーションとSemVerの相性が悪い
- SemVerはどのバージョンを上げるかリリースのときに考えるのが大変
- 手動でタグ・リリースを作成するのが大変
そこで、今回、以下のような運用の変更と自動化に取り組み、手間の軽減を図りました。
- アプリケーションはSemVerからCalVerに変更
- コンポーネントはSemVerのまま、PRごとに上げるバージョンを明記
- タグ・リリースを自動作成する GitHub Actions の導入
アプリケーションはSemVerからCalVerに変更
アプリケーションにおいては、後述するタグ・リリースの自動作成のため、Calendar Versioning(CalVer)を参考にしたバージョニングに変更しました。 CalVerの命名規則は様々ですが、「いつ作ったものかわかる」かつ「同日複数回のリリースも問題ない」ように、「vYYYYMMDD-コミットハッシュ7桁」(例: v20211202-abcdefg)という規則を採用しました。 これにより、人がどのバージョンを上げるべきかを考える必要がなくなり、自動化できるようになりました。 一方、コンポーネントについては、SemVerが有用であると考え、そのままにしました。
コンポーネントはSemVerのまま、PRごとに上げるバージョンを明記
SemVerの利用を続けるコンポーネントでは、後述のリリースの自動作成に用いるanothrNick/github-tag-actionの仕様に則って、PRごとに、PR作成者自らが、
- メジャー(
#major
) - マイナー(
#minor
) - パッチ(
#patch
)
のいずれに該当する改変であるかを、PRタイトルに明記するような運用にしました。
明示的に表現することで、後述する自動化にも繋がり、負担軽減にも繋がりますが、「このPRは後方互換性を損なうような変更ですが、#minor
で大丈夫ですか?」のようなコミュニケーションが可能になるメリットもあります。
タグ・リリースを自動作成する GitHub Actions の導入
最後に、以下の2つを用いて、タグの付与、リリースの作成を自動化する GitHub Actions を各リポジトリで導入しました。
アプリケーションのリポジトリで用いたものは以下のとおりです。 これにより、mainへのマージで自動的に、「v20211202-abcdefg」のようなタグが付与され、さらにリリースが作成されます。
name: Bump version on: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Get tag id: tag run: | echo "::set-output name=date::$(date +'%Y%m%d')" echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - name: Bump version and push tag uses: anothrNick/github-tag-action@1.36.0 id: bump env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CUSTOM_TAG: v${{ steps.tag.outputs.date }}-${{ steps.tag.outputs.sha_short }} - name: Release uses: softprops/action-gh-release@v1 with: name: ${{ steps.bump.outputs.new_tag }} tag_name: ${{ steps.bump.outputs.new_tag }}
一方で、コンポーネントではSemVerを採用しているため、以下のような設定を用いました。 anothrNick/github-tag-action はSemVerが想定されているため、先程よりもややシンプルになります。
ちょっとした工夫として、DEFAULT_BUMP
を none にしておくことで、誤って、PRタイトルに#minor
などを付け忘れても、後から手作業で付けられるようにしています。
name: Bump version on: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: '0' - name: Bump version and push tag uses: anothrNick/github-tag-action@1.36.0 id: bump env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} WITH_V: true DEFAULT_BUMP: none - name: Release uses: softprops/action-gh-release@v1 with: name: ${{ steps.bump.outputs.new_tag }} tag_name: ${{ steps.bump.outputs.new_tag }}
おわりに
今回、バージョニングの見直しと、タグ・リリースの作成の自動化について説明しました。 実際やったことは、少し運用を変えて、ちょっとした設定を追加しただけですが、 タグ・リリースの作成は、繰り返し行うような作業であり、このようなものを自動化しておくと、負担が軽減する効果を実感できます。 チームやシステムごとに適切なバージョニングは様々だと思いますが、参考になれば幸いです。