mainブランチにマージ~ドメイン付きでCloud Runサービス公開までをTerraformで管理

## これは?
最近Terraformを使えるようになりたいと思ったので、自分で公開していたcloud runのサービスをTerraformで管理するようにしてみた際のメモです! 自分向けメモなのでリンクペタペタだけです。

## 環境
- Terraform v1.2.8
- Docker version 20.10.17
- Google Cloud SDK 399.0.0

## やること
- mainブランチにマージしたら、Docker imageがGCRにPushされるようにする
- cloud runのサービスを作成する
- 認証済みドメインをマッピングする

上記をほぼTerraformで管理することを目指します（一部の下準備的な部分は手動になります）。図にするとこんな感じです。
![スクリーンショット 2022-09-01 23.59.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533290/f0372130-dbd7-01f9-e858-f7d23272c86a.png)


## やらないこと
- gcpのプロジェクトは作っておいてください
- 環境構築手順は説明しません。Google cloud sdkとTerraformが必要なので、参考になる記事を下に貼ります
  - https://zenn.dev/liam/articles/f4e0e097205301
  - https://christina04.hatenablog.com/entry/gcp-auth
  - https://qiita.com/kamatama_41/items/ba59a070d8389aab7694

## やっていく
### GithubとGCPのプロジェクトを接続
ここは手動。コンソールの[ここ](https://console.cloud.google.com/cloud-build/triggers/connect?hl=ja&_ga=2.139856371.1504674706.1661935681-436704492.1640446996)からポチポチ進めるとできます。トリガーの作成の部分はTerraformでやるのでGUIで設定する必要はありません。下記のような画面です。
![スクリーンショット 2022-09-02 1.08.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533290/aa273562-8d8c-6cf3-76d1-d280e2514785.png)



### Github->GCRにPushするcloudbuildリソースを作成
ここからtfファイルを書いていきます。
今回は`main.tf`にリソースを書いていき、`variable.tf`に`main.tf`で使う定数を定義していきます。Github->GCRは`cloud build`を使って、GithubへのPushをトリガーとして、GCRにDocker imageをビルドしていきます。
先述したように、公式の[google_cloudbuild_trigger](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloudbuild_trigger)ドキュメントを参照して埋めていきます。

```terraform:main.tf
resource "google_cloudbuild_trigger" "default" {
  github {
    name  = var.github_repo
    owner = var.github_owner

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

  build {
    images = ["gcr.io/$PROJECT_ID/$REPO_NAME:latest"]
    # imageをビルド
    step {
      name = "gcr.io/cloud-builders/docker"
      args = [
        "build",
        "-t",
        "gcr.io/$PROJECT_ID/$REPO_NAME:latest",
        "-f",
        "app/Dockerfile",
        "."
      ]
      timeout = "3600s"
    }

    # GCRにPush
    step {
      id   = "Push"
      name = "gcr.io/cloud-builders/docker"
      args = [
        "push",
        "gcr.io/$PROJECT_ID/$REPO_NAME:latest"
      ]
      timeout = "3600s"
    }

    timeout = "7200s"
  }
}
```

```terraform:variable.tf
variable "project_name" {
  default = "<GCPのプロジェクト名>"
}

variable "github_repo" {
  default = "<Githubのリポジトリ名>"
}

variable "github_owner" {
  default = "<Githubのユーザー名>"
}

variable "github_branch" {
  default = "<トリガーとなるブランチ名>"
}
```
タイムアウトが異様に長いのはビルドにめっちゃ時間がかかるものだったからので、他の人はよしなにしてください。リポジトリ名は`https://github.com/<ユーザー名>/<リポジトリ名>`の`<リポジトリ名>`の部分のことです。
基本的にドキュメントを見ながら設定項目を埋めていく感じです。

### cloud runのサービスを作成するリソースを作成
これはGoogleが公開している[cloud run + ロードバランサのチュートリアル](https://cloud.google.com/blog/ja/products/serverless/serverless-load-balancing-terraform-hard-way#:~:text=%E6%AC%A1%E3%81%AB%E3%80%81%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%20%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%80%8Chello%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E5%90%8D%E5%89%8D%E3%81%AE%E6%96%B0%E3%81%97%E3%81%84%20Cloud%20Run%20%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%97%E3%80%81%E6%9C%AA%E8%AA%8D%E8%A8%BC%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)で同じようなことをしている箇所があったので、真似しました。

```terraform:main.tf(追記)
# ↑でPushしたイメージでサービスをビルドする
resource "google_cloud_run_service" "default" {
  name     = var.cloud_run_service_name
  location = var.gcp_location

  template {
    spec {
      containers {
        image = "gcr.io/${var.project_name}/${var.github_repo}:latest"
        ports {
          container_port = 8080
        }
      }
    }
  }
}

# 未認証のアクセスを許可する権限を付与
resource "google_cloud_run_service_iam_member" "cloud_run_member" {
  location = google_cloud_run_service.default.location
  project  = google_cloud_run_service.default.project
  service  = google_cloud_run_service.default.name
  role     = "roles/run.invoker"
  member   = "allUsers"
}
```

```terraform:variable.tf(追記)
variable "cloud_run_service_name" {
  default = "<cloud runのサービス名>"
}

variable "gcp_location" {
  default = "<ロケーション名(us-central1など)>"
}
```

### (ドメインの認証)
マッピングできるカスタムドメインは認証済みのものだけなので、使いたいドメイン、サブドメインが未認証の場合は、[こちらの記事](https://qiita.com/sasamuku/items/d600faf977510989de8c)を参考に認証する必要があります

### カスタムドメインをマッピング
ドメインが用意できたら、作成したcloud runのサービスにドメインをマッピングします

```terraform:main.tf(追記)
resource "google_cloud_run_domain_mapping" "domain_mapping" {
  location = google_cloud_run_service.default.location
  name     = var.custom_domain

  metadata {
    namespace = var.project_name
  }

  spec {
    route_name = google_cloud_run_service.default.name
  }
}
```

```terraform:variable.tf(追記)
variable "custom_domain" {
  default = "<ドメイン名>"
}
```

### Terraformをapply
```terminal
# どのようなリソースが作成されるか（もしくは削除・変更）を確認
terraform plan
# tfファイルに書いた内容を反映
terraform apply
```

## おわり
ドキュメントやチュートリアルが充実しているので、定番なことは調べればすぐできそうだなと感じました。
ただ、GCPの知識が全くないと、何を設定していいかもわからないと思うので、ある程度コンソールでの操作のイメージがつくくらいの感じじゃないと結構難しいのではないかと感じました。GCP力を鍛えていきたいです!
最後まで目を通していただきありがとうございました。（用語の大文字小文字が揺れているのはお許しください）

## 参考
- [Terraform × GCP 入門](https://qiita.com/donko_/items/6289bb31fecfce2cda79)
- [Terraform google](https://registry.terraform.io/providers/hashicorp/google/4.34.0)
- [Google Cloud SDKをHomeBrewでセットアップをする方法](https://zenn.dev/liam/articles/f4e0e097205301)
- [gcloud auth login と gcloud auth application-default login](https://christina04.hatenablog.com/entry/gcp-auth)
- [tfenvでTerraformのバージョン管理をする](https://qiita.com/kamatama_41/items/ba59a070d8389aab7694)
- [Terraform を使用したサーバーレス負荷分散: 地道な方法](https://cloud.google.com/blog/ja/products/serverless/serverless-load-balancing-terraform-hard-way)
- [【GCP】Terraform で Cloud Run にカスタムドメインをマッピング](https://qiita.com/sasamuku/items/d600faf977510989de8c)