terraform でCloudRun のPR駆動CloudBuildトリガーを作成する


# 概要

CloudRun のコンソール”継続的デプロイ”から選択して作成できるGitHub のソースコードトリガーを terraform にてIaCしてみた話

# 背景
CloudRun は2021年10月頃に　Go や　Python のような特定の言語において Dockerfile を必要とせずソースコードから直接デプロイができるようになりました。

https://cloud.google.com/blog/ja/topics/developers-practitioners/trying-out-source-based-deployment-cloud-run

しかもCloudRun のコンソールからCDトリガーを作成でき、ソースコードからデプロイの設定もできて便利だったので、ついでにこれをIaCして使いまわそうと思ったのがきっかけです

「継続的なデプロイの設定」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262578/437714be-0304-7d7f-dec8-2dbf5ecb7524.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262578/ea0ba3b1-40d9-5034-bc2a-6ac5d9b532cd.png)




# ソースコードについて

terraform の概要については割愛します。

## ディレクトリ構成

ディレクトリ構成は以下のような構成です。
実際には環境ごとに分けていたりするのです便宜上、簡易的に表現しました。

```
　　　--modeles/cloudbuild
 |          |- main.tf
 |          |- variabels.tf
 |- main.tf
 |- variables.tf
```

modules にモジュールの詳細を書き、
環境によってはmainのvariablesを上書きして更新するような使い方です。


## コード

``` cloudbuild-trigger.tf
resource "google_cloudbuild_trigger" "default" {
  description = "Build and deploy to Cloud Run service ${var.project} on push to \"^${var.github_branch}$\""
  name        = "rmgpgab-${var.project}-api--${var.region}"

  substitutions = {
    "_DEPLOY_REGION" = "${var.region}"
    "_GCR_HOSTNAME"  = "us.gcr.io"
    "_PLATFORM"      = "managed"
    "_SERVICE_NAME"  = "${var.project}-api"
  }
  tags = [
    "gcp-cloud-build-deploy-cloud-run",
    "gcp-cloud-build-deploy-cloud-run-managed",
    var.project,
  ]

  build {
    images = [
      "$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA",
    ]
    substitutions = {
      "_DEPLOY_REGION"                     = "${var.region}"
      "_GCR_HOSTNAME"                      = "us.gcr.io"
      "_PLATFORM"                          = "managed"
      "_SERVICE_NAME"                      = "${var.project}"
      "_CLOUDRUN_MEMORY"                   = "${var.cloudrun_memory}"
      "_CLOUDRUN_MIN_INSTANCES"            = "${var.cloudrun_min_instances}"
      "_CLOUDRUN_MAX_INSTANCES"            = "${var.cloudrun_max_instances}"
      "_CLOUDRUN_CPU"                      = "${var.cloudrun_cpu}"
      "_CLOUDRUN_APP_PORT"                 = "${var.cloudrun_app_port}"
      "_CLOUDRUN_APP_CLIENT_HOST"          = "${var.cloudrun_app_client_host}"
      "_CLOUDRUN_INSTANCE_CONNECTION_NAME" = "${var.cloudsql_instance}"
      "_CLOUDSQL_PASSWORD"                 = "${var.cloudsql_password}"
      "_CLOUDSQL_PORT"                     = "${var.cloudsql_port}"
      "_CLOUDSQL_DB_NAME"                  = "${var.cloudsql_db_name}"
      "_CLOUDSQL_INSTANCE"                 = "${var.cloudsql_instance}"
      "_CLOUDSQL_USERNAME"                 = "${var.cloudsql_username}"
    }
    tags = [
      "gcp-cloud-build-deploy-cloud-run",
      "gcp-cloud-build-deploy-cloud-run-managed",
      "${var.project}",
    ]

    options {
      disk_size_gb          = 0
      dynamic_substitutions = false
      substitution_option   = "ALLOW_LOOSE"
    }

    step {
      args = [
        "build",
        "$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA",
        "--builder=gcr.io/buildpacks/builder:v1",
        "--path=api",
      ]
      entrypoint = "pack"
      id         = "Buildpack"
      name       = "gcr.io/k8s-skaffold/pack"
    }
    step {
      args = [
        "push",
        "$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA",
      ]
      id   = "Push"
      name = "gcr.io/cloud-builders/docker"
    }

    # https://cloud.google.com/sdk/gcloud/reference/run/services/update
    step {
      args = [
        "run",
        "deploy", // cloud run のリソースは別で作っておいてupdateするのが適切かもしれない
        "$_SERVICE_NAME",
        "--allow-unauthenticated",
        "--platform=managed",
        "--region=$_DEPLOY_REGION",
        "--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_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",
        "--min-instances=$_CLOUDRUN_MIN_INSTANCES",
        "--max-instances=$_CLOUDRUN_MAX_INSTANCES",
        "--memory=$_CLOUDRUN_MEMORY",
        "--cpu=$_CLOUDRUN_CPU",
        "--add-cloudsql-instances=$_CLOUDSQL_INSTANCE",
        "--set-env-vars=APP_PORT=$_CLOUDRUN_APP_PORT",
        "--set-env-vars=INSTANCE_CONNECTION_NAME=$_CLOUDRUN_INSTANCE_CONNECTION_NAME",
        "--set-env-vars=DB_PORT=$_CLOUDSQL_PORT",
        "--set-env-vars=DB_USER=$_CLOUDSQL_USERNAME",
        "--set-env-vars=DB_PASSWORD=$_CLOUDSQL_PASSWORD", 
        "--set-env-vars=DB_NAME=$_CLOUDSQL_DB_NAME",
        "--set-env-vars=APP_CLIENT_HOST=$_CLOUDRUN_APP_CLIENT_HOST",
        "--quiet",
      ]
      entrypoint = "gcloud"
      id         = "Deploy"
      name       = "gcr.io/google.com/cloudsdktool/cloud-sdk:slim"
    }
  }

  github {
    name  = var.github_repo
    owner = var.github_owner

    push {
      branch       = "^${var.github_branch}$"
      invert_regex = false
    }
  }
}

```

※環境変数はシークレットも--set-env-varsで設定していますが、実際にはシークレットマネージャーを用いて設定する必要があります。そうしないとCloudRun の閲覧権限がある人からシークレットが見えてしまします。今後、修正する予定です。


``` main.tf
module "cloudbuild-trigger" {
  source = "./modules/cloudbuild-trigger"

  project    = var.project
  project_id = var.project_id
  region     = var.region

  github_owner = var.github_owner
  github_repo  = var.github_repo

  cloudrun_memory          = var.cloudrun_memory
  cloudrun_max_instances   = var.cloudrun_max_instances
  cloudrun_min_instances   = var.cloudrun_min_instances
  cloudrun_cpu             = var.cloudrun_cpu
  cloudrun_app_client_host = var.cloudrun_app_client_host

  cloudsql_username = var.cloudsql_username
  cloudsql_password = var.cloudsql_password
  cloudsql_db_name  = var.cloudsql_db_name
  cloudsql_instance = var.cloudsql_instance
}
```