Open5

Cloud SchedulerでCloudRun Jobsのバッチ処理を定期実行する構成をTerraformで作る

takumitakumi

バッチ処理の概要

connpass apiで現在の日付から1ヶ月分のイベント情報を取得してきてそれをDBに保存する処理

connpass apiの制限

  • リクエスト間隔は最低5s
  • 一度のリクエストでは最大100件しか取得できない

その他条件

  • DBのeventsテーブルに挿入する
  • eventsテーブルは常に1ヶ月分のデータを保持している
    • 2回目以降に挿入する場合は現在のデータを全削除する
  • 1日1回、午前3:30の定期実行
takumitakumi

バッチ処理をGoアプリケーションで作る

Dockerfileの準備

CloudRunにデプロイするためコンテナ化する必要がある。
以下のようなマルチステージビルドで構成する。

# ============ develop ===============
FROM golang:1.21.4-bullseye as dev

WORKDIR /go/src/app

RUN go install github.com/cosmtrek/air@latest

RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get install git -y

COPY ./go.mod ./go.sum /go/src/app/
RUN go mod download

CMD ["air", "-c", ".air.toml"]

# ============ build ===============
FROM golang:1.21.4-bullseye as build

WORKDIR /go/src/app

RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get install git -y
COPY go.mod go.sum ./
RUN go mod download
COPY . /go/src/app/

RUN CGO_ENABLED=0 GOOS=linux go build -o /main

# ============ production ===============
FROM gcr.io/distroless/base-debian11 AS production

WORKDIR /go/src/app

EXPOSE 8000

COPY --from=build /main /main

ENTRYPOINT ["/main"]

リポジトリは以下
https://github.com/takumi-pro/devlocator_batch

takumitakumi

DBの準備

DBはPlanetScaleを使用する。
https://app.planetscale.com/

PlanetScaleでDBを作成して、テーブルを作成するsql文を流し込む
init.sqlファイルを用意

CREATE TABLE `users` (
  `id` INT PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(255) NOT NULL COMMENT 'ユーザ名',
  `email` varchar(255) NOT NULL COMMENT 'メールアドレス',
  `firebase_uid` varchar(255) NOT NULL COMMENT 'Firebaseが持っているID',
  `image` varchar(255) NOT NULL COMMENT '表示用写真URL',
  `created_at` timestamp,
  `updated_at` timestamp
);

CREATE TABLE `events` (
  `event_id` INT PRIMARY KEY NOT NULL COMMENT 'イベントID',
  `title` VARCHAR(255) NOT NULL COMMENT 'タイトル',
  `catch` VARCHAR(255) COMMENT 'キャッチ文章',
  `description` TEXT COMMENT '概要',
  `event_url` VARCHAR(255) COMMENT 'イベントURL',
  `started_at` DATETIME COMMENT '開始日時',
  `ended_at` DATETIME COMMENT '終了日時',
  `limit` INT COMMENT '定員',
  `hash_tag` VARCHAR(100) COMMENT 'ハッシュタグ',
  `event_type` VARCHAR(50) COMMENT 'イベントタイプ',
  `accepted` INT COMMENT '参加人数',
  `waiting` INT COMMENT '補欠人数',
  `updated_at` DATETIME COMMENT '更新日時',
  `owner_id` INT COMMENT '管理者ID',
  `owner_nickname` VARCHAR(255) COMMENT '管理者ニックネーム',
  `owner_display_name` VARCHAR(255) COMMENT '管理者名',
  `place` VARCHAR(255) COMMENT '開催場所',
  `address` VARCHAR(255) COMMENT '開催住所',
  `lat` VARCHAR(255) NOT NULL COMMENT '緯度',
  `lon` VARCHAR(255) NOT NULL COMMENT '経度'
);

CREATE TABLE `bookmarked_events` (
  `event_id` INT PRIMARY KEY NOT NULL COMMENT 'イベントID',
  `title` VARCHAR(255) NOT NULL COMMENT 'タイトル',
  `catch` VARCHAR(255) COMMENT 'キャッチ文章',
  `description` TEXT COMMENT '概要',
  `event_url` VARCHAR(255) COMMENT 'イベントURL',
  `started_at` DATETIME COMMENT '開始日時',
  `ended_at` DATETIME COMMENT '終了日時',
  `limit` INT COMMENT '定員',
  `hash_tag` VARCHAR(100) COMMENT 'ハッシュタグ',
  `event_type` VARCHAR(50) COMMENT 'イベントタイプ',
  `accepted` INT COMMENT '参加人数',
  `waiting` INT COMMENT '補欠人数',
  `updated_at` DATETIME COMMENT '更新日時',
  `owner_id` INT COMMENT '管理者ID',
  `owner_nickname` VARCHAR(255) COMMENT '管理者ニックネーム',
  `owner_display_name` VARCHAR(255) COMMENT '管理者名',
  `place` VARCHAR(255) COMMENT '開催場所',
  `address` VARCHAR(255) COMMENT '開催住所',
  `lat` VARCHAR(255) NOT NULL COMMENT '緯度',
  `lon` VARCHAR(255) NOT NULL COMMENT '経度'
);

CREATE TABLE `bookmarks` (
  `event_id` INT COMMENT 'イベントID',
  `user_id` INT COMMENT 'ユーザID',
  PRIMARY KEY (`event_id`, `user_id`)
);

mysql -h <db_host> -u <db_user> -p --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/cert.pem < init.sql
takumitakumi

TerraformでGCPリソースの作成

artifact registryの作成

あらかじめAPIを有効化しておく

main.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "4.51.0"
    }
  }
}

provider "google" {
  credentials = file(var.credentials_file)
  project = var.project
  region  = var.region
}

resource "google_artifact_registry_repository" "devlocator_batch_repository" {
  location      = var.region
  repository_id = var.repository_id_batch
  format        = "DOCKER"
  description   = "devlocator batch container repositry"
}

secret managerの作成

あらかじめAPIを有効化しておく

secretmanager.tf
resource "google_secret_manager_secret" "db_password" {
  secret_id = "db-password"
  lifecycle {
    prevent_destroy = true
  }
  replication {
    automatic = true
  }
}

resource "google_secret_manager_secret" "db_username" {
  secret_id = "db-username"
  lifecycle {
    prevent_destroy = true
  }
  replication {
    automatic = true
  }
}

resource "google_secret_manager_secret" "db_host" {
  secret_id = "db-host"
  lifecycle {
    prevent_destroy = true
  }
  replication {
    automatic = true
  }
}

作成したシークレットのバージョンにシークレット値を入れる

takumitakumi

CloudRun Jobsの作成

以下のコマンドでCloudRun Jobsを作成する

gcloud run jobs create [JOB_NAME] \
    --image=[ARTIFACT_REGISTRY_URL]/[PROJECT_ID]/[REPOSITORY]/[IMAGE]:[TAG] \
    --region=[REGION]

すると以下のようにジョブタブにジョブが作成される。

環境変数の設定

ジョブの編集でSecret Managerに設定したシークレットを設定する

手動実行して成功することを確認!