DevOps エンジニアの 根本 征 です。
前回のエントリーでは GitHub Actions の self-hosted runners について紹介しました。
今回はそれらを活用したデプロイフロー(主に API / Frontend)の改善について紹介したいと思います。
- これまでのデプロイフローと課題
- GitHub Flow はどうか
- GitLab Flow とは
- git-pr-release + GitHub Actions を使った、リリース Pull Request の自動生成
- GitHub Actions を使ってデプロイを行う
- 効果と課題
- おわりに
これまでのデプロイフローと課題
部署やサービスによって異なりますが、これまでのデプロイにまつわる環境は大まかに下記のような状況でした。
- 3つの環境
- develop 環境(主に開発者が使う環境)
- staging 環境(本番リリース前の検証環境)
- production 環境(本番環境)
- Git Flow
- Jenkins を使った CI / CD
- develop 環境・staging 環境 → ブランチの更新でデプロイ
- production 環境 → tag を指定してソフトウェアエンジニアもしくは DevOps エンジニアがデプロイ
Git Flow は大規模な開発や、リリースタイミングが決められているもの(iOS / Android など)とは相性が良いです。
しかし、API / Frontend などリリースタイミングが恣意的に決めることができ、かつ小・中規模の開発だとあまりメリットがないと感じました。
逆に、Git Flow は他と比べて複雑なブランチ管理(release ブランチや hotfix ブランチ)になってしまい、これによってデプロイ頻度が下がっている可能性もあると考えました。
そのため、今回のデプロイフローの改善によって下記を実現したいと考えました。
- 小さく自律的にデプロイできるようにする → デプロイ頻度を上げる
- シンプルなブランチ管理・デプロイができるようにする
GitHub Flow はどうか
上記の Git Flow の代替としてよく導入されているのが GitHub Flow だと思います。
GitHub Flow は実際に GitHub のサービス開発において活用されているブランチ戦略であり、私も最初は GitHub Flow を導入できないか検討しました。
GitHubにおける継続的デリバリー/How GitHub builds and deploy software - Speaker Deck
GitHub Flow では master(main) ブランチと feature ブランチしかなく、シンプルなブランチ管理を実現することができます。
master ブランチはいつでも本番環境にデプロイができるブランチと考えられ、push をトリガーに本番環境へデプロイしているという事例も多くあると思います。
この GitHub Flow によって先ほど挙げた課題を解決することができそうですが、リリース前の検証環境が課題になると考えました。
先述の通り、GitHub Flow だと master ブランチはいつでも本番環境へデプロイができるブランチだと考えられています。
そのため、リリース前の検証にはそれぞれの feature ブランチで検証する必要があります。
(Introduction to GitLab Flowより)
そして、複数の feature ブランチ / Pull Request が存在する場合には下記のような方法を取る必要が出てきます。
- 1つあるいは複数の検証環境を必要に応じて切り替える
- Pull Request 毎に環境が立ち上がる → リリース後にその環境を閉じる
私はよりシンプルに上記の検証環境にまつわる課題を解決できないか考え、今回導入したのが GitLab Flow です。
GitLab Flow とは
GitLab Flow に関しては GitLab がドキュメントを公開しています。
Introduction to GitLab Flow | GitLab
またこちらの記事で翻訳がされています。
GitLab flowから学ぶワークフローの実践 | POSTD
上記のドキュメントでも Git Flow / GitHub Flow に対する課題点を挙げています。
そして GitLab Flow では、GitHub Flow の masterブランチ と featureブランチの関係はそのままに、リリースに必要なブランチを用意することができます。
GitLab Flow のドキュメントでは、production ブランチモデル、環境ブランチモデル、release ブランチモデルが紹介されており、今回環境ブランチモデルが現状ある環境を有効活用しながらデプロイフローを改善できるのではと考えました。
(Introduction to GitLab Flowより)
環境ブランチモデルでは、それぞれのブランチと環境を対にして、ブランチに変更があった場合には自動でそれぞれの環境へデプロイがされるようにします。
今回の場合だと下記のようになります。
- master ブランチ → develop 環境
- staging ブランチ → staging 環境
- production ブランチ → production(本番)環境
そして、master → staging → production に Pull Request を作成・マージしていくことでデプロイを進めることができます。
これによって下記のようなメリットがあると考えています。
- Git Flow よりシンプルなブランチ管理・デプロイを行うことができる
- GitHub Flow よりも容易に本番リリース前の検証環境を用意することができる
git-pr-release + GitHub Actions を使った、リリース Pull Request の自動生成
先述の通り、GitLab Flow では master → staging → production ブランチに Pull Request を作成・マージしていくことでデプロイを進めていきます。
しかし、手動でこれを行うとなると、下記の恐れがあると考えました。
- Pull Request の作成・マージのし忘れが発生する
- どの変更が入った Pull Request なのか分かりづらくなる
これらを解決するために、上記の Pull Request の作成・更新を git-pr-release + GitHub Actions を使い自動化しました。
git-pr-release ではブランチ間の差異を検出し、マージされた Pull Request の一覧が表示されたリリース Pull Request を作成することができます。
git-pr-release 自体はコマンドで実行することが可能ですが、下記のような GitHub Actions のワークフローを作成することによって自動化することができます。
これによって、本番環境までのデプロイフローを下記のようになるべくシンプルにすることができました。
- feature ブランチの Pull Request をレビュー・master ブランチにマージ
- 検証環境へ自動的にデプロイ・本番環境へデプロイするリリース Pull Request が自動的に生成・更新
- 検証環境で確認(手動テストもしくは検証環境を使った End to End テストなど)
- 問題なければ Pull Request をマージ・本番環境へ自動的にデプロイ
GitHub Actions を使ってデプロイを行う
実際のデプロイに関しても GitHub Actions で行っています。
それぞれの環境ブランチ(master, staging, production)で push がある際にトリガーされるように設定しています。
また、デプロイする Job に関しては、GitHub Actions の self-hosted runners を使っています。
詳細については下記エントリーをご覧ください。
効果と課題
現在いくつかの部署・サービスでこのデプロイフローを導入しており、最初に述べた2点を実現することができました。
- 小さく自律的にデプロイできるようにする → デプロイ頻度を上げる
- シンプルなブランチ管理・デプロイができるようにする
また、サービスによっては 1~2週に1回のデプロイ頻度から、1日に数回デプロイ できるようになりました。
同時に、課題・注意しないといけない点も出てきました。
GitLab Flow は GitHub Flow を比べると比較的柔軟なフローになっており、本番環境へ1度にデプロイできる Pull Request の数も柔軟に決めることができます。
そのため、状況によっては1度にデプロイする Pull Request のサイズが大きくなってしまい、本来目指していた「小さくデプロイできるようにする」を実現することが困難になる可能性があります。
不具合があった際の手戻りのコストを減らすためにも、今後は GitLab Flow を使う場合には下記のようなポリシーを決めていく必要がありそうです。
- feature / bugfix は 1 Pull Request 毎にマージ・検証・本番環境までデプロイしていく
- Dependabot などによって作られる、マイナーな依存関係のアップデートはまとめてマージ・検証・デプロイしていく
おわりに
今回はデプロイフロー(Continuous Deployment)のみの改善でしたが、今後はこのフローに合わせて継続的テスティング(Continuous Testing) や DevSecOps など、サービスを継続的に改善していくための仕組みを拡充していきたいと考えています。
また、このデプロイフロー自体も組織やサービスの成長によって最適な形が変わってくると考えているため、今後も継続的に改善していきたいと考えています。
今回のエントリーが、現場でのデプロイフローの改善に何かしら参考になれば幸いです。