エクサウィザーズ Engineer Blog

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

Improving Continuous Delivery with GitLab Flow + GitHub Actions

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

The Japanese version of this blog post can be found here:

techblog.exawizards.com

Hello, I'm Tadashi Nemoto from the DevOps team.

In this article, I will demonstrate how to improve deployment flows using GitHub Actions.

Standard deployment flows and their problems

Although it varies by departments and services, current deployment flows are as follows.

  • Three environments
    • develop environment
    • staging environment
    • production environment
  • Git Flow as a branching strategy
  • CI / CD using Jenkins
    • develop and staging environments → Deploy with branch updates
    • production environment → Software engineers or DevOps engineers deploy by specifying a tag


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

Git Flow works well for large scale development or projects with fixed release timing (e.g. iOS / Android work).

However, I have found it to be less beneficial for small to medium scale projects where the release windows tend to be arbitrarily decided (such as in API / Frontend work).

On the other hand, Git Flow involves more complex branch management (having to maintain release and hotfix branches for example) than others, and I have thought that this is not suitable for deploying to production frequently.

Therefore, I wanted to achieve the following goals by improving deployment flows.

  • Enable small, autonomous deployments → Increase deployment frequency
  • Simplify branch management and deployment strategies

How about GitHub Flow?

I think GitHub Flow is often used as an alternative to Git Flow.

GitHub Flow is a branching strategy that is actually used in the development of GitHub services, and I initially looked into it as a possibility for this project.

GitHub Flow only has a master(main) branch and a feature branch, allowing for simpler branch management.

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

The master branch is considered to be a branch that can be deployed to the production environment at any time, and there are many examples of deploying to the production environment triggered by push.

This GitHub Flow seems to be able to solve the problem I mentioned earlier, but I thought having a verification environment before release might cause a problem.

As mentioned earlier, in GitHub Flow, the master branch is considered to be the branch that can be deployed to the production environment at any time.

Therefore, each feature branch needs to be used for verification before release.

f:id:tadashi-nemoto0713:20210127144507p:plain
Problem of verification environment in GitHub Flow
(From Introduction to GitLab Flow)

And if you have multiple feature branches / pull requests, you will need to take the following approach.

  • Switch between one or more validation environments as needed
  • Launch an environment for each pull request → close the environment after each release

I've been looking for a simpler way to solve the above issues with validation environments, and this time I've decided on GitLab Flow.

About GitLab Flow

GitLab Flow is documented by GitLab.

Introduction to GitLab Flow | GitLab

The above document also lists some of the issues with Git Flow / GitHub Flow.

GitLab Flow allows you to have the branches you need for a release while maintaining the master branch/feature branch relationship of GitHub Flow.

The GitLab Flow documentation introduces production branch model, environment branches model, and release branches model, and I thought that environment branches model would improve deployment flows while making effective use of the current environments.

f:id:tadashi-nemoto0713:20210115113159p:plain
Production branch model and environment branches model of GitLab Flow
(From Introduction to GitLab Flow)

In the environment branches model, each branch is paired with an environment, and when branches are modified, they are automatically deployed to their respective environments.

In this case, it looks like the following

  • master branch → develop environment
  • staging branch → staging environment
  • production branch → production environment

You can then proceed with deployment by creating and merging pull requests in master → staging → production.

I believe this GitLab Flow has the following advantages

  • Simpler branch management and deployment than Git Flow
  • Easier than GitHub Flow to prepare a verification environment before a production release

Automatically generate release pull requests using git-pr-release + GitHub Actions

As mentioned earlier, GitLab Flow deploys by creating and merging pull requests on the master → staging → production branch.

However, if we were to do this manually, I thought the following might happen.

  • Forgetting to create and merge pull requests
  • It may become difficult to know which changes are in each pull request.

To solve these problems, I automated creating and modification of the above pull requests using git-pr-release + GitHub Actions.

f:id:tadashi-nemoto0713:20210118142154p:plain
Auto-generated release pull request using git-pr-release + GitHub Actions

git-pr-release can detect differences between branches and create a release pull request with a list of merged pull requests.

You can run git-pr-release itself as a command, but you can also automate it by creating a GitHub Actions workflow like below.

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

By doing this, we can simplify the deployment flow to the production environment as much as possible, as shown below:

  1. Review pull requests of feature branches and merge them into the master branch
  2. Automatically deploy to the verification environment
  3. Automatically generate release pull requests to deploy to the production environment
  4. Check the validation environment (manual testing or end-to-end testing using the validation environment, etc.)
  5. If there are no problems, merge the pull request and automatically deploy to the production environment

Deploy using GitHub Actions

The actual deployment is also done with GitHub Actions.

It is set to be triggered when there is a push in each environment branch (master, staging, production).

on:
  push:
    branches: [ master ]

jobs:
  deploy_develop:
    runs-on: self-hosted

We use self-hosted runners of GitHub Actions when deploying, please see the following blog entry for more details:

techblog.exawizards.com

Effects and challenges

We are currently implementing this deployment flow in several departments and services, and have been able to achieve the first two points mentioned.

  • Enable small, autonomous deployments → Increase deployment frequency
  • Simplify branch management and deployment strategies

In addition, some projects now deploy several times a day, previously having deployed only once every 1-2 weeks.

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

At the same time, there are some issues that we need to be aware of.

GitLab Flow is a relatively flexible flow compared to GitHub Flow, and the number of pull requests that can be deployed to the production environment at one time can be decided flexibly.

Therefore, depending on the situation, the size of the pull requests that can be deployed at one time may become quite large, making it difficult to achieve the original goal of "enabling small deployments".

To reduce the cost of rework in case of a bug, we may need to implement the following policy when using GitLab Flow in the future.

  • Merge, validate, and deploy features/bug fixes to the production environment for every pull request.
  • Minor dependency updates created by bot such as Dependabot can be merged, verified, and deployed at once.

Summary

This time, I only improved the deployment flow (Continuous Deployment).

Still, we would like to expand the Continuous Testing, DevSecOps, and other mechanisms to continuously improve the service in line with this flow in the future.

I also believe that the optimal deployment flow itself will change depending on the organisation's growth and its requirements, so we will continue to improve upon this in the future.

I hope that this entry will be of some help in improving your own deployment flow.

hrmos.co