🌊

【Go】複数のCloud Run Jobsをモノレポで管理する

に公開

はじめに

本記事のゴール

  • モノレポ構成でJobごとのディレクトリを整理
  • Dockerマルチステージビルドでバイナリを効率的に生成
  • Cloud Buildのループ処理でCI/CDを自動化

ディレクトリ構成

ディレクトリ構成
.
├── cloudbuild.yaml
├── cmd
│   ├── cloud-run-jobs1
│   │   ├── Dockerfile
│   │   └── main.go
│   ├── cloud-run-jobs2
│   │   ├── Dockerfile
│   │   └── main.go
│   └── cloud-run-jobs3
│       ├── Dockerfile
│       └── main.go
├── go.mod
├── go.sum
├── internal
│   └── shared
│       ├── utils.go
│       └── config.go
└── README.md
  • cmd/配下にJob単位のディレクトリを配置し、それぞれで main.go を実装。
  • internal/shared/ に共通ロジック(設定読込、ユーティリティ)を切り出し、重複を防止。
  • ルートに cloudbuild.yaml を置き、全Jobを横断するビルド・デプロイ設定を記述。

Dockerfile

Dockerfile
# --- ビルドステージ ---
FROM golang:1.23-alpine3.20 AS builder
WORKDIR /workspace

# 依存モジュールを先にキャッシュ
COPY go.mod go.sum ./
RUN go mod download && go mod verify

# ソース一式をコピー
COPY . .

# 各Jobディレクトリでバイナリをビルド
WORKDIR /workspace/cmd/cloud-run-jobs1
RUN go build -o main main.go

# --- 実行ステージ ---
FROM alpine:3.20
WORKDIR /app
# ビルド済みバイナリをコピー
COPY --from=builder /workspace/cmd/cloud-run-jobs1/main .
# デフォルトのコマンドを指定
CMD [ "/app/main" ]

cloudbuild.yaml

cloudbuild.yaml
steps:
  # (1) Build & Push
  - name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        set -e
        DIRS=(
          cmd/cloud-run-jobs1
          cmd/cloud-run-jobs2
          cmd/cloud-run-jobs3
        )
        for DIR in "$${DIRS[@]}"; do
          NAME=$$(basename $$DIR)
          IMAGE=${_REGION}-docker.pkg.dev/${PROJECT_ID}/$${NAME}/$${NAME}:$COMMIT_SHA

          docker build -f $$DIR/Dockerfile -t $$IMAGE .
          docker push $$IMAGE
        done

  # (2) Deploy to Cloud Run Jobs
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        set -e
        DIRS=(
          cmd/cloud-run-jobs1
          cmd/cloud-run-jobs2
          cmd/cloud-run-jobs3
        )
        for DIR in "$${DIRS[@]}"; do
          NAME=$$(basename $$DIR)
          IMAGE=${_REGION}-docker.pkg.dev/${PROJECT_ID}/$${NAME}/$${NAME}:$COMMIT_SHA

          gcloud run jobs deploy $${NAME} \
            --image $$IMAGE \
            --region ${_REGION} \
            --command /app/main \
            --service-account ${_SERVICE_ACCOUNT}
        done
        
substitutions:
  _REGION: 'region'
  _SERVICE_ACCOUNT: 'service-account@${PROJECT_ID}.iam.gserviceaccount.com'
options:
  logging: CLOUD_LOGGING_ONLY

まとめ

  • モノレポ構成でJobごとの責務を分離しつつ、共通ライブラリは internal/shared へ集約
  • Dockerマルチステージビルド+Goモジュールキャッシュでビルド効率化
  • Cloud Buildループ+サブスティテューションでCI/CDを簡潔に自動化

工夫した点

  • モノレポでの拡張性

    • cmd/ 配下にJobを追加するだけで自動検知
  • ビルドキャッシュの活用

    • モジュール依存を先読みしてネットワークI/Oを最小化
  • 共通ロジックの集中管理

    • internal/shared に設定・ユーティリティを切り出し、変更時の影響範囲を限定
  • Cloud Buildの一元化

    • ループ処理とサブスティテューションで設定を集中管理し、YAMLの冗長性を大幅に削減

Discussion