ドクターズプライム Official Blog

「救急車たらい回しをゼロにする」ドクターズプライムの公式ブログです

Google App Engine(Go)のデプロイを速くした話

こちらはドクターズプライム Advent Calendar 2021の4日目の記事です。昨日3日目の記事はこちら

こんにちは、ソフトウェアエンジニアのoinumeです。今日はGoogle App Engineのデプロイを速くした話をお届けします。

はじめに

こちらの記事にあるように、弊社のWebアプリケーションのバックエンドはGoで作っています。アプリケーションを動かす環境としてはGoogle App Engine(以下GAE)を使用しており、リクエスト特性に応じて以下の3種類のServiceが存在しています。

  • api: フロントエンドから呼ばれるAPI Service
  • batch: Cloud Schedulerから呼ばれるバッチ処理向けService
  • task: Cloud Tasksから呼ばれる非同期処理向けService

f:id:drsprime:20211202104448p:plain

上記の3種類のServiceにデプロイする必要があるため、gcloud app deployコマンドを3回実行することになり、1回のデプロイに8分ほど時間がかかっていました。個人的には8分という時間は短いようで長いと感じており、このぐらい待ち時間があるとデプロイを忘れて他の作業(Twitterを見るなど)をしてしまう弊害があります。

また、デプロイの待ち時間が長くなってしまうと、デプロイ頻度の低下につながり、機能追加やバグ修正などのデリバリーサイクルが回りにくくなってしまうという課題もありました。そのため、重い腰をあげてデプロイ速度の改善に取り組みました。具体的にはGitHub Actionsのbuild matrixを使って速度改善したので、その紹介をしたいと思います。

GitHub Actionsのbuild matrix

GAEへのデプロイにはGitHub Actionsを使用しているのですが、GitHub Actionsにはbuild matrixと呼ばれる仕組みがあります。一般的には以下のようにCIで複数のランタイム(Go 1.15, 1.16, 1.17など)でテストを実行するなどの用途で使われることが多いです。

jobs:
  test:
    strategy:
      matrix:
        go-version: [1.15, 1.16, 1.17]
    runs-on: ubuntu-latest
    steps:
      - name: Install Go
        uses: actions/setup-go@v2
        with:
          go-version: ${{ matrix.go-version }}
      - name: Checkout code
         uses: actions/checkout@v2
      - name: Test
         run: go test ./...

GAEの3種類のSerivceへのデプロイも3回ほぼ同じことをやっていたので、このbuild matrixが使えそうだと気付きました。実際のGitHub ActionsのYAMLを一部抜粋すると、以下のように変更してapi, batch, task のserviceをmatrixとして定義して、3並列でデプロイのjobを実行するようにしています。3並列化されたことにより、デプロイにかかる時間が8分30秒から5分程度になりました。

BEFORE

    steps:
      - name: Check out the repository
        uses: actions/checkout@v2
        with:
          path: ${{ env.GOPATH }}/src/github.com/${{ github.repository }}
     <中略>
      - name: Install App Engine Go SDK
        run: sudo apt-get install google-cloud-sdk-app-engine-go
      - name: Initialize Google Cloud SDK
        uses: google-github-actions/setup-gcloud@master
        with:
          project_id: ...
          service_account_key: ...
          service_account_email: ...
          export_default_credentials: true
      - name: Deploy beer-server to production
        run: |
          go mod vendor
          GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/api/app_prod.yaml
          GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/task/app_prod.yaml
          GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/batch/app_prod.yaml

AFTER

   strategy:
      max-parallel: 3
      matrix:
        service: ["api", "batch", "task"]
    steps:
      - name: Check out the repository
        uses: actions/checkout@v2
        with:
          path: ${{ env.GOPATH }}/src/github.com/${{ github.repository }}
     <中略>
      - name: Install App Engine Go SDK
        run: sudo apt-get install google-cloud-sdk-app-engine-go
      - name: Initialize Google Cloud SDK
        uses: google-github-actions/setup-gcloud@master
        with:
          project_id: ...
          service_account_key: ...
          service_account_email: ...
          export_default_credentials: true
      - name: Run go mod vendor
        run: |
          go mod vendor
      - name: Deploy beer-server to production
        run: |
          GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/${{ matrix.service }}/app_prod.yaml

DIFF

>    strategy:
>       max-parallel: 3
>       matrix:
>         service: ["api", "batch", "task"]
16c20
<       - name: Deploy beer-server to production
---
>       - name: Run go mod vendor
19,21c23,25
<           GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/api/app_prod.yaml
<           GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/task/app_prod.yaml
<           GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/batch/app_prod.yaml
---
>       - name: Deploy beer-server to production
>         run: |
>           GO111MODULE=off gcloud app deploy --version $DEPLOY_VERSION --no-promote --quiet ./entrypoint/${{ matrix.service }}/app_prod.yaml

最後に

簡単ですが、GitHub Actionsの機能を使うことでデプロイを高速化する手法を紹介しました。この記事が読者の方のCI/CD環境の改善につながれば幸いです。

一緒に働く仲間を募集しています

ドクターズプライムでは「救急車のたらい回しをゼロにする」というビジョンの実現に向けて、病院向けのSaaSプロダクトおよび、医師/病院間の最適なマッチングを提供するマッチングプラットフォームを展開しており、一緒に働く仲間を募集しています。(CI/CDの改善などDevOps領域にも興味があるソフトウェアエンジニアも大募集しています)

私もMeetyを公開しているので、まずはカジュアルにお話ししてみませんか?

speakerdeck.com