GoのAPI serverをGithub Action経由でGCPのCloud Runにデプロイする方法

thumnail
2020-07-19

背景

GCPのCloud RunにGithub Action経由でアプリケーションをデプロイする機構を実装する機会があったのでその備忘録としてこの記事にまとめておく。

Cloud Runとは

GCPを触ったことのないことなら初めて聞く用語かもしれない。Cloud RunはGKE(Google Container Engine)の難しい設定をラップして、インフラの知識に乏しいエンジニアでもdockerコンテナベースのアプリケーション運用を簡単に行えるようにしたGCPのサービスである。今流行りのサーバーレスっていうやつだ。公式には次のように書かれている。

コンテナ化されたアプリケーションをすばやく安全にデプロイ、スケーリングできる、フルマネージド型のコンピューティング プラットフォーム

参考文献:Cloud Run

https://cloud.google.com/run?hl=ja

今回使用したCloud Runの種類はフルマーネージドと呼ばれるものだ。インスタンスの最大数などを設定し、トラフィックに応じて自動スケールを行ってくれる。また自動でHTTPS化や、サービス起動時に適当なドメインを割り振ってくれる。もちろんカスタムドメインを設定することも可能だ。Cloud Runの説明自体はこの記事ではこの辺りで終わりにする。

GitHub Actionに自動デプロイを実装する

まずは一旦コード(.github/workflow/config.yml)の中身を添付する。今回はCloud Runにデプロイ機構を実装するのが目的なのでテストなどの部分は全て省略する。

  
name: Go

on:
  push:
    branches: [master]

env:
  GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
  GCP_REGION: ${{ secrets.GCP_REGION }}
  DB_HOST: ${{ secrets.DB_HOST }}
  DB_DATABASE: ${{ secrets.DB_DATABASE }}
  DB_USER: ${{ secrets.DB_USER }}
  DB_PASS: ${{ secrets.DB_PASS }}

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v2
        with:
          go-version: ^1.13
        id: go

      - name: Check out code into the Go module directory
        uses: actions/checkout@v2

      - name: GCP Authenticate
        uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
        with:
          project_id: ${{ secrets.GCP_PROJECT_ID }}
          service_account_key: ${{ secrets.GCP_SA_KEY }}
          export_default_credentials: true

      - name: Configure docker to use the gcloud cli
        run: gcloud auth configure-docker --quiet

      - name: Deploy to Cloud Run
        run: |
          date_time=`date +%Y%m%d%H%M%S`
          IMAGE=gcr.io/$GCP_PROJECT_ID/golang-api-server:$date_time
          docker build -t $IMAGE .
          docker push $IMAGE
          gcloud run deploy golang-api-server \
                      --image $IMAGE \
                      --platform managed \
                      --region $GCP_REGION \
                      --port 8080 \
                      --project $GCP_PROJECT_ID \
                      --set-env-vars DB_HOST=$DB_HOST,DB_DATABASE=$DB_DATABASE,DB_USER=$DB_USER,DB_PASS=$DB_PASS \
                      --vpc-connector hoge-vpc-connector \
                      --max-instances 3 \
                      --quiet

ではこれらのコードを上から順に解説していく。

setup-gcloudでgcloudコマンドを利用可能に

Github Actionの中でubuntuベースのコンテナを立ち上げているのだが、当然ながらgcloudを叩いて自身のGCPのプロジェクトを操作するようにするためには一度、認証を噛ませないといけない。この認証を行ってくれるのがsetup-gcloudというプラグインだ。

https://github.com/GoogleCloudPlatform/github-actions/tree/master/setup-gcloud

次のように設定すれば良い。

- name: GCP Authenticate
  uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
  with:
    project_id: ${{ secrets.GCP_PROJECT_ID }}
    service_account_key: ${{ secrets.GCP_SA_KEY }}
    export_default_credentials: true

公式のReadmeではversionを指定しているが、versionを指定すると使用できないflagなどが出てきたので、あえて指定しないようにしている。(指定しない場合、最新のgcloudコマンドに対応するのか...?) GCPPROJECTIDやGCPSAKEYはGitHubのsecretに登録した。GitHubの「setting→secret」で簡単に登録できる。基本的に鍵情報をコードに書くのはアンチパターンなのでsecretなどに環境変数として定義・使用するべきである。projectidとserviceaccount_keyが正しければ、次の部分で認証が成功するはず。

- name: Configure docker to use the gcloud cli
  run: gcloud auth configure-docker --quiet

Cloud Runにデプロイする

GitHub Actionsのコンテナ内でコンテナをbuildする。buildしたimageにtagをつけてGCPのContainer Registoryにpushする。tagに関して、いまいち良いつけ方ではないと思うが、日時をtagとして使用する。

- name: Deploy to Cloud Run
  run: |
    date_time=`date +%Y%m%d%H%M%S`
    IMAGE=gcr.io/$GCP_PROJECT_ID/golang-api-server:$date_time

    docker build -t $IMAGE .
    docker push $IMAGE

GCPのContainer Registoryにimageをpushした後、imageを指定してCloud Runにコンテナをデプロイする。

    gcloud run deploy golang-api-server \
                --image $IMAGE \
                --platform managed \
                --region $GCP_REGION \
                --port 8080 \
                --project $GCP_PROJECT_ID \
                --set-env-vars DB_HOST=$DB_HOST,DB_DATABASE=$DB_DATABASE,DB_USER=$DB_USER,DB_PASS=$DB_PASS \
                --vpc-connector hoge-vpc-connector \
                --max-instances 3 \
                --quiet

--image $IMAGEでimageを指定、今回はフルマネージのCloud Runを利用するので--platform managedと指定する。この記事にはソースコードは書いてないが、GoのAPI serverを8080番でリッスンするように指定したのでポートは--port 8080で8080番にロードバランサーがトラフィックを送信するように設定する。Cloud RunでアプリケーションをデプロイするとGCP側でロードバランサーが自動で設定される。ユーザー側は特別何か設定をする必要はない。(サーバーレス凄い...) projectはそのままでGCPのプロジェクトID、regionは東京とかを指定すれば良い。指定方法は次のリンクに書いてある。

https://cloud.google.com/run/docs/locations

set-env-varsでコンテナ内で使用する環境変数を定義することができる。今回はCloud SQLの接続情報を渡している。Cloud SQLをVPC内で使用している場合、Cloud Runにvpc-connectorをアタッチしなければ、DB_HOSTなどが正しくても接続することはできない。vpc-connectorをVPCに設定する方法はGCPの「VPCネットワーク→サーバレスVPCアクセス」で設定可能。今回はhoge-vpc-conectorというvpc-connectorを作ったのでこれを--vpc-connectorに指定する。トラフィックに応じた最大インスタンス数は--max-instancesに3を指定することで3台に設定した。--quietを付与するとCI実行時に入力が必要とされる場面があったときにdefalutが設定される。

Cloud Runにデプロイが完了したら

Cloud Runにデプロイが無事終了したら、Cloud Runのサービスに緑色のチェックマークが現れる。それと同時にHTTPS化された適当なドメインが発行するので、ローカルから適当にcurlコマンドを打ってレスポンスが返ってきたら無事デプロイ完了になる。ちなみにデプロイ中のダウンタイムは心配する必要はなさそう。というのもロードバランサーが新しいクラスターが生成されるまで更新前のクラスターにトラフィックを100%送信してくれるっぽい。(この辺はちゃんと根拠を持って言いたいのであとで調べます...)

profile

KATUO

web developer

六本木で月間利用者数数千万のサービスを運営するミドルベンチャーでWeb系エンジニアをやってます。フロントエンドはVue.js/Nuxt.js,サーバーサイドはGolang, クラウドはAWS, GCPを良く扱います。お仕事・イベント等の依頼はContactのフォームからお願いします。

KATUBLO

Copyright since 2018 KATUO All Rights Reserved.