Terraform で GCP Cloud Run をデプロイする

terraform を使って Cloud Run を管理するまでのメモ。

# 前提
- terraform がインストールされている
- gcloud cli がインストールされてる
- GCPのプロジェクトを作成し、`gcloud projects list` を叩いたときに作成したプロジェクトが表示されている

https://cloud.google.com/sdk/docs/authorizing?hl=ja

# ① GCPの設定
基本的にコンソール画面を叩くのではなく、gcloud コマンドを使って操作していきます。

## gcloud コマンドでプロジェクトをアクティブにする
まず初めにterraformで扱うプロジェクトをアクティブにしておきましょう。
```bash
gcloud config set project [PROJECT_ID]
```
実行できたらアクティブになっているか確認しましょう。下記コマンドを叩くと、現在設定されているデフォルトのGCPプロジェクトIDを返します。
```bash
gcloud config get-value project
```

## terraform用のサービスアカウント(SA)を作る
terraform 用にGCPのサービスアカウントを作成します。下記コマンドを実行することでサービスアカウントが作成できます。

```bash
gcloud iam service-accounts create サービスアカウントの名前 \
		--description="説明文（任意）" \
		--display-name="表示名"
```

## SAに対して権限を付与する
先ほど作成したサービスアカウントに対して権限を付与します。

```bash
gcloud projects add-iam-policy-binding プロジェクトID \
		--member="serviceAccount:作成したサービスアカウントの名前@プロジェクトID.iam.gserviceaccount.com" \
		--role="roles/editor"
```

## SA のキーを取得する
作成したサービスアカウントのキー（jsonファイル）を取得します。

```bash
gcloud iam service-accounts keys create 任意のパス/key.json \
		--iam-account 作成したサービスアカウントの名前@プロジェクトID.iam.gserviceaccount.com
```

# ② Docker イメージをプッシュ
Cloud Runでアプリケーションを実行する時に必要になるDockerイメージを、GCR（Google Container Registry）にプッシュしておきましょう。今回は最低限のGo言語のアプリとDockerfile を作成します。

```Dockerfile
# Goの公式イメージをベースにする
FROM golang:1.20 AS build-env

# 作業ディレクトリを設定
WORKDIR /app

# 必要なGoのモジュールをコピー
COPY go.mod .
COPY go.sum .

# 依存関係をダウンロード
RUN go mod download

# ソースコードをコピー
COPY . .

# バイナリをビルド
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# ランタイムイメージのステージ
FROM gcr.io/distroless/base-debian10

# ビルドされたバイナリをコピー
COPY --from=build-env /app/main /app/main

# ポート8080を公開
EXPOSE 8080

# アプリケーションを実行
CMD ["/app/main"]

```

アプリケーションのコードは下記をご参照ください。

https://github.com/Takenari-Yamamoto/golang-gcp-app

次に作成した Docker イメージをローカルでビルドします。Dockerfile が存在するディレクトリで実行してください。
```bash
docker build -t sample-app-001 .
```

イメージにタグを付けます。
```bash
docker tag sample-app-001 asia.gcr.io/sample-pro-395702/sample-app-001
```

イメージを GCR にプッシュします。
```bash
docker push asia.gcr.io/プロジェクトID/sample-app-001
```

イメージがプッシュされたか確認しておきましょう。下記コマンドを叩くとプッシュしたイメージが表示されるはずです。
```bash
gcloud container images list --repository=asia.gcr.io/プロジェクトID
```

# ③ terraform を使って扱うリソースを記述&デプロイ
ここまでできたらようやくインフラのコード化に取り掛かります。ディレクトリ構成は下記のようにしてます。

```bash
└── infrastructure-project
    ├── main.tf
    └── variables.tf
```

まず `variable.tf` に変数を定義します。今回はプロジェクトIDとリージョンを定義しておきます。

```tf
variable "project_id" {
  description = "project id"
  type        = string
  default     = "プロジェクトID"
}

variable "default_region" {
  description = "The default region for resources"
  default     = "asia-southeast1"
}
```

次に `main.tf` にGCP用のgoogleプロバイダを設定します。ちなみにプロバイダとは特定のクラウドサービスやインフラストラクチャ技術を操作・管理するためのプラグインです。

```tf
provider "google" {
  credentials = file("path/key.json") // 「SA のキーを取得する」で生成したkey.jsonまでのパスを指定
  project     = var.project_id // variable.tf を参照してる
  region      = var.default_region
}
```

ここまでできたら `terraform init` を実行して初期化します。
```tf
terraform init
```
成功すると下記のようなログが出力されます。

```
Terraform has been successfully initialized!
```

次に Cloud Run のリソースの定義を記述します。`main.tf` のプロバイダーの下に追記します。

```tf
resource "google_cloud_run_service" "sample-app-001" {
  name     = var.project_id
  location = var.default_region

  template {
    spec {
      containers {
        image = "asia.gcr.io/${var.project_id}/sample-app-001"
      }
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }
}
```

ちなみに `asia.gcr.io/${var.project_id}/sample-app-001`は②で作成したDockerイメージを指定してください。

設定できたら `terrafrom apply` を実行します。
```bash
terrafrom apply
```

Cloud Run へのデプロイが成功したらコンソール画面から作成できているか確認しましょう。

![スクリーンショット 2023-08-12 20.25.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741616/3bb46f60-8179-68e2-050c-cac5fe2fdeae.png)

おしまい。