Cloud RunとCloud Buildの連携に期待するより楽な継続的デプロイの世界

[2020年7月13日](https://cloud.google.com/run/docs/release-notes#July_13_2020)に、Gitを利用してCloud Buildで継続的なデプロイをするための設定がCloud Runから簡単に行えるようになりました。

感想です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Cloud Run、Dockerfile置いてあるリポジトリにコミット追加されたらCloud Buildでビルド・デプロイされるんか。いよいよPaaSっぽくてめっちゃよいな！<a href="https://t.co/PFCgRlyUCf">https://t.co/PFCgRlyUCf</a></p>&mdash; カエル氏の闘争🐸😽 (@toshi0607) <a href="https://twitter.com/toshi0607/status/1284275124972122112?ref_src=twsrc%5Etfw">July 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 概観

設定手順を見てみましょう。以下の設定が、一連のダイアログで設定できます。

1. Cloud Runを設定する
1. Cloud Buildを設定する

## 1-1. Service settings

ここは特に変更ありません。managedかAnthosか、Service name、Authenticationを指定します。

<img width="555" alt="service-settings.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/4c0f9bed-c7aa-dff1-7bd6-6a6cf2616911.png">

## 1-2. Configure the service's first revision

`Continuously deploy new revisions from a source repository`を選択すると、`SET UP WITH CLOUD BUILD`ボタンが出ます。

<img width="512" alt="cd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/2db9a141-2995-1ffa-9288-870e2ab6eaca.png">

## 2-1. Source repository

Cloud Runにデプロイするコンテナの元になるソースコードとDockerファイルのあるリポジトリを選択するためには、Cloud Source Repositories APIの有効化が必要です。

<img width="550" alt="source-repo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/fd18c888-ffc8-b7d6-d584-0e1177727bdd.png">


Gitリポジトリは、つぎの3つから選択できます。

* Cloud Source Repositories
* GitHub
* Bitbucket

アカウントを認証して、リポジトリを選択します。リポジトリは、認証したアカウントから参照できるものが同期され、表示されます。たくさんあると少し時間がかかるので、待ってください。

今回のテストでは[このリポジトリ](https://github.com/toshi0607/http-server-with-dockerfile)を利用しています。

## 2-2. Build Configuration

デプロイ対象にするブランチを正規表現で指定し、リポジトリ内のDockerファイルのパスと名前を指定します。

<img width="561" alt="build-configuration.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/3610bac4-1eb4-2bd4-fe5d-f6eb11c39115.png">

`SAVE`、`CREATE`するとCloud RunのServiceの作成が始まります。

# Cloud Runの継続的デプロイ

Cloud Run、Cloud Buildの設定が終わると、Cloud RunのServiceやRevisionが作成されます。そのあとは指定したGitリポジトリのブランチに変更をプッシュすることで、ソースコードからCloud Runをデプロイできます。

## Serviceとplaceholderの作成

まず、Cloud RunのRevisionとして作成されるのはSERVICE_NAME-placeholderという名前のRevisionです。

<img width="680" alt="placeholder.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/e5e76804-6561-b9e0-4ce7-6e6adcf051de.png">

これは`gcr.io/cloudrun/hello`というコンテナがデプロイされたものです。まだ、設定したリポジトリからビルドしたコンテナがデプロイされたわけではありません。

ブラウザからアクセスすると、つぎのような画面が表示されます。

<img width="787" alt="placeholder2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/f628b336-bc60-1bfb-e960-1673e5027541.png">

## Revisionの作成

つぎに、Cloud Buildの設定に基づいてビルドされたコンテナがデプロイされます。

<img width="679" alt="revision.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/760669fb-6be8-409b-1c19-a1a74cabf3af.png">

## 継続的デプロイ

今度は、設定したリポジトリのmasterブランチに変更をプッシュしてみましょう。リポジトリへのプッシュをトリガーにCloud Buildが実行され、新しいRevisionが作成されます。

<img width="676" alt="push-commit.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/6a47cf1b-a144-4c0a-ec00-e815ff5ad1db.png">

# Cloud Buildで設定される内容

Cloud RunからCloud Buildを連携すると、Cloud Build側では何が設定されるのでしょうか。結論は、大体このドキュメントに記載されているものです。

[Cloud Build を使用した Git からの継続的なデプロイ](https://cloud.google.com/run/docs/continuous-deployment-with-cloud-build)

具体的には以下の4つです。

* Cloud Build Trigger - Event
* Cloud Build Trigger - Source
* Cloud Build Trigger - Build Configuration
* Cloud Build - Service Account

変更できるのかなども含め、実際に追ってみましょう。

## Cloud Build Trigger

Cloud Buildを見に行くと、指定した内容に基づきCloud Build Triggerが作成されています。

<img width="805" alt="trigger1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/0da25469-f52f-ae56-ed22-3b1eccd9a94b.png">

<img width="805" alt="trigger2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/9d2697a0-aee9-a23d-13f0-bb4c31dbf4c0.png">

Cloud Buildを実行するEventは3種類あるうちの`Push to branch`、Cloud Buildが利用する設定は`Inline`です。

Cloud Build TriggerをGCPコンソールから作成する場合、File typeに`Inline`は選択できないようでした。

## Eventの変更

Eventを`Push new tag`に変更します。

<img width="544" alt="change-event.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/bf4b2133-32f9-e92e-782b-f0b58d6fb110.png">

変更を保存し、リポジトリでv0.1.0などタグを打つとCloud Buildが実行されました。

<img width="782" alt="change-event2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/2b775196-e9c8-5f34-daf3-da85b0fb655c.png">

Cloud BuildのBuild historyを確認すると、Refが`master`（ブランチ名）から`v0.1.0`（タグ名）に変わっています。

<img width="1012" alt="log.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/d3f3732b-f6ae-e767-445c-a6070e8b51d7.png">


## Step

Cloud Buildで実行されるStepも見ておきましょう。シンプルにつぎのような構成になっています。

* `Build`: コンテナイメージのビルド
* `Push`: コンテナイメージのGCRへのプッシュ
* `Deploy`: GCRのイメージをCloud Runにデプロイ

```yaml:ビルド設定ファイル
steps:
  - name: gcr.io/cloud-builders/docker
    args:
      - build
      - '--no-cache'
      - '-t'
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
      - .
      - '-f'
      - Dockerfile
    id: Build
  - name: gcr.io/cloud-builders/docker
    args:
      - push
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
    id: Push
  - name: gcr.io/google.com/cloudsdktool/cloud-sdk
    args:
      - run
      - deploy
      - $_SERVICE_NAME
      - '--platform=managed'
      - '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
      - >-
        --labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS
      - '--region=$_DEPLOY_REGION'
      - '--quiet'
    id: Deploy
    entrypoint: gcloud
images:
  - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
options:
  substitutionOption: ALLOW_LOOSE
substitutions:
  _DEPLOY_REGION: asia-northeast1
  _LABELS: gcb-trigger-id=96560acf-1aa3-4525-b49d-01d4b749d6e4
  _TRIGGER_ID: 96560acf-1aa3-4525-b49d-01d4b749d6e4
  _GCR_HOSTNAME: asia.gcr.io
  _PLATFORM: managed
  _SERVICE_NAME: w-cloud-build
tags:
  - gcp-cloud-build-deploy-cloud-run
  - gcp-cloud-build-deploy-cloud-run-managed
  - w-cloud-build
```

最初の2 Stepは`gcr.io/cloud-builders/docker`イメージを使い`docker build`と`docker push`を、最後のStepは`gcr.io/google.com/cloudsdktool/cloud-sdk`イメージを使い`gcloud run deploy`コマンドを実行しています。

`Inline`に表示されているこれらのStepは、GCPコンソールから変更できなさそうでした。

リポジトリにCloud Buildの設定ファイルを置くように変更すれば、必要に応じてテストなどのStepも追加できそうです。

たとえば、つぎのようにBuild、Push、Deployの前にTestを実行するStepを追加した`cloudbuild.yaml`をリポジトリに置きます。

```yaml:cloudbuild.yaml
steps:
  - name: golang:1.14
    env: ['GO111MODULE=on']
    args: ['go', 'test', './...']
    id: Test # Testを実行するためのStepを追加
  - name: gcr.io/cloud-builders/docker
    args:
      - build
      - '--no-cache'
      - '-t'
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
      - .
      - '-f'
      - Dockerfile
    id: Build
  - name: gcr.io/cloud-builders/docker
    args:
      - push
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
    id: Push
  - name: gcr.io/google.com/cloudsdktool/cloud-sdk
    args:
      - run
      - deploy
      - $_SERVICE_NAME
      - '--platform=managed'
      - '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
      - >-
        --labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS
      - '--region=$_DEPLOY_REGION'
      - '--quiet'
    id: Deploy
    entrypoint: gcloud
images:
  - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
options:
  substitutionOption: ALLOW_LOOSE
substitutions:
  _LABELS: gcb-trigger-id=96560acf-1aa3-4525-b49d-01d4b749d6e4
  _TRIGGER_ID: 96560acf-1aa3-4525-b49d-01d4b749d6e4
  _GCR_HOSTNAME: asia.gcr.io
  _PLATFORM: managed
  _SERVICE_NAME: w-cloud-build
  _DEPLOY_REGION: asia-northeast1
tags:
  - gcp-cloud-build-deploy-cloud-run
  - gcp-cloud-build-deploy-cloud-run-managed
  - w-cloud-build
```

File typeを`Cloud build configuration`に変更すると、このファイルを元にCloud Buildが実行されるようになります。

<img width="642" alt="change-file-type2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/3c6e5f5c-5909-88ff-f1a3-39c10bc67026.png">


ただし、File typeを変更すると`Inline`に記載されていた設定には戻せません。`Inline`も選択できなくなります。

<img width="771" alt="change-file-type.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/dd5f33eb-dc2a-cf1e-a91c-3af3920ca67b.png">


## Service Account

Cloud Buildが実行時に利用するService Accountには、つぎの3つのRoleが割り当てられています。

* `Service Account User`
* `Cloud Run Admin`
* （`Cloud Build Service Account` （GCPコンソールのIAMなどから確認できます））

<img width="783" alt="service-account.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/4df528da-909b-c220-4041-e37d5150d0f7.png">

Roleカラムに表示されていないRoleを割り当てるには、IAMのGCPコンソールやgcloudコマンドを利用します。

<img width="557" alt="iam.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/a98b6ed4-1924-94d6-14e0-2467607f1855.png">


# まとめ

今回の連携で、Cloud Runにコンテナをデプロイするための設定がより簡単になりました。個々のCloud Buildの設定は以前から利用できたものです。しかし、Cloud Run側からほとんど手間をかけずに継続的デプロイが設定できるのは嬉しいものです。一層アプリケーション自体の開発に集中できそうですね。

デプロイ周りでは、`GoogleCloudPlatform/buildpacks`などで、Dockerファイルすら準備しなくて済む世界を想像してみると楽しいかもしれません。

つぎのような実装も、いずれCloud Runで利用できたり、事例が増えたりするかもしません。

* イベントドリブンなワークロード実行のための[google/knative-gcp](https://github.com/google/knative-gcp)
* より楽にFunctionを実装するための[Functions Framework](https://cloud.google.com/functions/docs/functions-framework)

エコシステムへの投資や、今後の更なる成長を期待します。