エクサウィザーズ Engineer Blog

株式会社エクサウィザーズのエンジニアチームブログ

GitLab Flow + GitHub Actions ではじめる、デプロイフローの改善・自動化

f:id:tadashi-nemoto0713:20201228172750p:plain


DevOps エンジニアの 根本 征 です。

前回のエントリーでは GitHub Actions の self-hosted runners について紹介しました。

今回はそれらを活用したデプロイフロー(主に API / Frontend)の改善について紹介したいと思います。

これまでのデプロイフローと課題

部署やサービスによって異なりますが、これまでのデプロイにまつわる環境は大まかに下記のような状況でした。

  • 3つの環境
    • develop 環境(主に開発者が使う環境)
    • staging 環境(本番リリース前の検証環境)
    • production 環境(本番環境)
  • Git Flow
  • Jenkins を使った CI / CD
    • develop 環境・staging 環境 → ブランチの更新でデプロイ
    • production 環境 → tag を指定してソフトウェアエンジニアもしくは DevOps エンジニアがデプロイ


f:id:tadashi-nemoto0713:20210118184341p:plain
Git Flow


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 ブランチしかなく、シンプルなブランチ管理を実現することができます。

f:id:tadashi-nemoto0713:20210115112754p:plain
GitHub Flow(Understanding the GitHub flowより)


master ブランチはいつでも本番環境にデプロイができるブランチと考えられ、push をトリガーに本番環境へデプロイしているという事例も多くあると思います。

この GitHub Flow によって先ほど挙げた課題を解決することができそうですが、リリース前の検証環境が課題になると考えました

先述の通り、GitHub Flow だと master ブランチはいつでも本番環境へデプロイができるブランチだと考えられています。

そのため、リリース前の検証にはそれぞれの feature ブランチで検証する必要があります。

f:id:tadashi-nemoto0713:20210119162043p:plain
GitHub Flow における検証環境の問題
(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 ブランチモデルが紹介されており、今回環境ブランチモデルが現状ある環境を有効活用しながらデプロイフローを改善できるのではと考えました。


f:id:tadashi-nemoto0713:20210115113159p:plain
GitLab Flow の production ブランチモデルと環境ブランチモデル
(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 を使い自動化しました。

f:id:tadashi-nemoto0713:20210118142154p:plain
git-pr-release + GitHub Actions で自動生成されたリリース Pull Request

git-pr-release ではブランチ間の差異を検出し、マージされた Pull Request の一覧が表示されたリリース Pull Request を作成することができます。

git-pr-release 自体はコマンドで実行することが可能ですが、下記のような GitHub Actions のワークフローを作成することによって自動化することができます。

on:
  push:
    branches: [ master ]

jobs:
  create-release-pr:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
      with:
        fetch-depth: 0

    - name: Set up Ruby 2.7
      uses: actions/setup-ruby@v1
      with:
        ruby-version: 2.7.x

    - name: Create a staging release pull request
      env:
        GIT_PR_RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        GIT_PR_RELEASE_BRANCH_PRODUCTION: staging
        GIT_PR_RELEASE_BRANCH_STAGING: master
        GIT_PR_RELEASE_LABELS: staging-release
      run: |
        gem install -N git-pr-release -v "1.4.0"
        git-pr-release --no-fetch

これによって、本番環境までのデプロイフローを下記のようになるべくシンプルにすることができました。

  1. feature ブランチの Pull Request をレビュー・master ブランチにマージ
  2. 検証環境へ自動的にデプロイ・本番環境へデプロイするリリース Pull Request が自動的に生成・更新
  3. 検証環境で確認(手動テストもしくは検証環境を使った End to End テストなど)
  4. 問題なければ Pull Request をマージ・本番環境へ自動的にデプロイ

GitHub Actions を使ってデプロイを行う

実際のデプロイに関しても GitHub Actions で行っています。

それぞれの環境ブランチ(master, staging, production)で push がある際にトリガーされるように設定しています。

on:
  push:
    branches: [ master ]

jobs:
  deploy_develop:
    runs-on: self-hosted

また、デプロイする Job に関しては、GitHub Actions の self-hosted runners を使っています。

詳細については下記エントリーをご覧ください。

techblog.exawizards.com

効果と課題

現在いくつかの部署・サービスでこのデプロイフローを導入しており、最初に述べた2点を実現することができました。

  • 小さく自律的にデプロイできるようにする → デプロイ頻度を上げる
  • シンプルなブランチ管理・デプロイができるようにする

また、サービスによっては 1~2週に1回のデプロイ頻度から、1日に数回デプロイ できるようになりました。

f:id:tadashi-nemoto0713:20210115113531p:plain


同時に、課題・注意しないといけない点も出てきました。

GitLab Flow は GitHub Flow を比べると比較的柔軟なフローになっており、本番環境へ1度にデプロイできる Pull Request の数も柔軟に決めることができます。

そのため、状況によっては1度にデプロイする Pull Request のサイズが大きくなってしまい、本来目指していた「小さくデプロイできるようにする」を実現することが困難になる可能性があります。

不具合があった際の手戻りのコストを減らすためにも、今後は GitLab Flow を使う場合には下記のようなポリシーを決めていく必要がありそうです。

  • feature / bugfix は 1 Pull Request 毎にマージ・検証・本番環境までデプロイしていく
  • Dependabot などによって作られる、マイナーな依存関係のアップデートはまとめてマージ・検証・デプロイしていく

おわりに

今回はデプロイフロー(Continuous Deployment)のみの改善でしたが、今後はこのフローに合わせて継続的テスティング(Continuous Testing) や DevSecOps など、サービスを継続的に改善していくための仕組みを拡充していきたいと考えています。

また、このデプロイフロー自体も組織やサービスの成長によって最適な形が変わってくると考えているため、今後も継続的に改善していきたいと考えています。

今回のエントリーが、現場でのデプロイフローの改善に何かしら参考になれば幸いです。


hrmos.co