目次

Introduction

TerraformでCloudRunを構築することがあり、また構築する時に再度調べるのがめんどくさいので備忘録として残したいと思います。
今回は、Terraformを実行する環境構築は省きます。

作成するリソース

今回作成するGCPリソースとCICDの要件は以下になります。

  • 今回はサンプルアプリケーションは省略
  • CICD環境はGithubActionsを選択
  • アプリケーションサーバーはマネージドなCloudRunを使用
  • GCPリソースは、Terraformで構築
  • tfファイルの記述量を減らすために公式のmoduleを使用
  • ディレクトリ構成は記述してないので、参考にする場合は構成お任せします

作成するインフラ構成図は以下になります。

HandsOn

では、淡々と構築するためのコードを貼っていきます。

環境ごとのファイル構築

最初にプロジェクトごとの設定ファイルを作成します。

locals {
  project-id         = "development-project"
  env                = "development"
  project            = "tech-blog"
  github-repo        = "kita21/tech-blog-sample"
  location           = "asia-northeast1"
}

IAM

ではまず、各リソースを動かすためのServiceAccountを作成していきます。

# https://cloud.google.com/iam/docs/understanding-roles

# https://github.com/terraform-google-modules/terraform-google-service-accounts
module "cloudrun_service_account" {
  source       = "terraform-google-modules/service-accounts/google"
  version      = "~> 4.2.0"
  display_name = "cloudrun-service-account"
  description  = "service-account for cloudrun"
  project_id   = local.project-id
  prefix       = "cloudrun"
  names        = ["sample"]
  project_roles = [
    "${local.project-id}=>roles/secretmanager.secretAccessor"
  ]
}

module "github_actions_service_account" {
  source       = "terraform-google-modules/service-accounts/google"
  version      = "~> 4.2.0"
  display_name = "github-actions-service-account"
  description  = "service-account for github-actions. use cloud-run deploy"
  project_id   = local.project-id
  prefix       = "github-actions"
  names        = ["deploy"]
  project_roles = [
    "${local.project-id}=>roles/artifactregistry.writer",
    "${local.project-id}=>roles/run.developer",
    "${local.project-id}=>roles/iam.serviceAccountUser",
    "${local.project-id}=>roles/secretmanager.secretAccessor"
  ]
}

resource "google_service_account_iam_binding" "iam_workload_identity_user_binding" {
  service_account_id = "projects/${local.project-id}/serviceAccounts/${module.github_actions_service_account.email}"
  role               = "roles/iam.workloadIdentityUser"
  members = [
    "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github_actions_pool.name}/attribute.repository/${local.github-repo}"
  ]
}

次にGithubActionsと連携するためのWorkloadIdentityを作成

resource "google_iam_workload_identity_pool" "github_actions_pool" {
  workload_identity_pool_id = "github-actions-pool"
  display_name              = "github-actions-pool"
  description               = "pool for access from github-actions"
  disabled                  = false
}

resource "google_iam_workload_identity_pool_provider" "github_actions_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.github_actions_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "github-actions-provider"
  display_name                       = "github-actions-provider"
  disabled                           = false
  attribute_mapping = {
    "google.subject"       = "assertion.sub"
    "attribute.actor"      = "assertion.actor"
    "attribute.repository" = "assertion.repository"
  }
  attribute_condition = "assertion.repository==\"${local.github-repo}\""
  oidc {
    issuer_uri = "https://token.actions.githubusercontent.com"
  }
}

CloudRun

CloudRunはコンテナで動くため、イメージを保存するためのレジストリーを作成

resource "google_artifact_registry_repository" "gar" {
  location      = "asia-northeast1"
  repository_id = local.project
  description   = "gcr for cloudrun"
  format        = "DOCKER"
}

resource "google_artifact_registry_repository_iam_binding" "gar_reader_binding" {
  project    = google_artifact_registry_repository.gar.project
  location   = google_artifact_registry_repository.gar.location
  repository = google_artifact_registry_repository.gar.name
  role       = "roles/artifactregistry.reader"
  members = [
    "serviceAccount:${module.cloudrun_service_account.email}"
  ]
}

メインのCloudRunを構築していきます。

  • ポートは3001
  • インスタンス数は料金的を考えてminScaleは0
# https://github.com/GoogleCloudPlatform/terraform-google-cloud-run
module "cloudrun" {
  source  = "GoogleCloudPlatform/cloud-run/google"
  version = "~> 0.8.0"

  service_name = "${local.env}-${local.project}"
  project_id   = local.project-id
  location     = local.location
  image        = "${local.location}-docker.pkg.dev/${local.project-id}/${local.project}/${local.env}-${local.project}-cloudrun:latest"
  template_annotations = {
    "autoscaling.knative.dev/maxScale" = 1
    "autoscaling.knative.dev/minScale" = 0
  }
  ports = {
    name = "http1"
    port = 3001
  }
  limits = {
    cpu    = "1000m"
    memory = "256Mi"
  }
  members = ["allUsers"]
  service_account_email = module.cloudrun_service_account.email
}

GitHubActions

GithubActionsを動かすためのworkflowsファイルを作成します。
developブランチにマージやコミットされたら実行されるような設定にします。
yamlファイルの流れは以下になります

  1. 必要な設定を環境変数に格納
  2. GCPの認証情報取得
  3. Artifact Registryから最新のイメージを取得後、Dockerfileをビルド
  4. ビルドされたイメージをArtifact RegistryにPush後、CloudRunを更新

Dockerfileはアプリケーションによるので今回は記述しないです。

name: Deploy to gcp cloudrun
on:
  workflow_dispatch:
  push:
    branches:
      - develop
permissions:
  id-token: write
  contents: read

env:
  WORKLOAD_IDENTITY_PROVIDER: projects/xxxxxx/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider
  GAR_REPO: tech-blog
  DEPLOY_REGION: asia-northeast1

jobs:
  BuildAndDeploy:
    timeout-minutes: 20
    runs-on: ubuntu-22.04
    steps:
    # env
      - name: Env Each. Env Setting
        if: github.ref == 'refs/heads/develop'
        run: |
          echo NEXT_PUBLIC_SERVICE_ENV=development >> $GITHUB_ENV
          echo GCP_PROJECT_ID=development-project >> $GITHUB_ENV
          echo SERVICE_NAME=development-tech-blog >> $GITHUB_ENV          
      - name: Common. Env Setting
        run: |
          echo GCP_SERVICE_ACCOUNT=github-actions-deploy@${{ env.GCP_PROJECT_ID }}.iam.gserviceaccount.com >> $GITHUB_ENV
          echo GAR_DOCKER_REPO=${{ env.DEPLOY_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/${{ env.GAR_REPO }}/${{ env.SERVICE_NAME }} >> $GITHUB_ENV          

    # setting
      - name: Github Checkout
        uses: actions/checkout@v3
      - id: auth
        name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ env.GCP_SERVICE_ACCOUNT }}
      - name: Setup Cloud SDK
        uses: google-github-actions/setup-gcloud@v1
      - name: Authorize Docker push
        run: gcloud auth configure-docker ${{ env.DEPLOY_REGION }}-docker.pkg.dev

    # build
      - name: Pull Latest Image
        run: docker pull ${{ env.GAR_DOCKER_REPO }}:latest || true
      - name: Build Docker Image
        run: |-
          docker build -f Dockerfile . \
            -t ${{ env.GAR_DOCKER_REPO }}:${{ github.sha }} \
            -t ${{ env.GAR_DOCKER_REPO }}:latest \
            --cache-from ${{ env.GAR_DOCKER_REPO }}:latest          
      - name: Push
        run: docker push --all-tags ${{ env.GAR_DOCKER_REPO }}

    # deploy
      - name: Deploy to CloudRun
        run: |-
          gcloud run deploy $SERVICE_NAME \
            --project=${{ env.GCP_PROJECT_ID }} \
            --image=${{ env.GAR_DOCKER_REPO }}:${{ github.sha }} \
            --region=${{ env.DEPLOY_REGION }} \
            --service-account=${{ env.GCP_SERVICE_ACCOUNT }} \
            --allow-unauthenticated \
            --no-use-http2          

終わりに

以上で、CloudRunのTerraform構築テンプレートになります。
自分のメモ代わりに特に説明なく淡々とtfファイルとgithub-actionsファイルを記載しました。
かなりざっくり書いたのでこれをみて構築しようとしている人は、しっかりTerraformのプロパティやmoduleの詳細を確認しながら構築してくださいね。