こんにちは!DX開発事業部 IoT×クラウドセクション コアエンジニアリンググループの高木瑞季です。
これまで Google Cloud の資格学習を進める中で、Cloud Build や Cloud Run などの各サービスについての知識を深めてきましたが、「実際に自分の手で自動化ラインを構築してみたい!」と思い、ハンズオンに挑戦しました。
本記事では、Cloud Run と Cloud Build を連携させて、GitHub へのプッシュをトリガーとした自動デプロイ(CI/CD パイプライン)を構築する手順について紹介します。

処理の流れ

今回構築する CI/CD パイプラインの全体像と処理の流れは以下の通りです。

  1. GitHub の main ブランチにプッシュ
  2. Cloud Build がプッシュを検知してビルドを開始
  3.  Dockerfile をもとにコンテナイメージを作成
  4. 生成したイメージを Artifact Registry へプッシュ
  5. Cloud Run へ デプロイ

実装手順

事前準備

  • Google アカウント作成
  • Google Cloud プロジェクト作成
  • GitHub アカウント作成
  • Google Cloud CLI のインストール

1. Google Cloud の事前準備

1-1. 必要な API を有効化する

今回使用する以下の Google Cloud サービスの API を有効化します。

  • Cloud Build:自動ビルド・デプロイの実行
  • Cloud Run:コンテナアプリケーションの実行環境
  • Artifact Registry:ビルドした Docker イメージを保存
  • Secret Manager:Cloud Build 第2世代連携において、GitHub との認証情報を安全に管理するために必要
gcloud services enable \
    cloudbuild.googleapis.com \
    run.googleapis.com \
    artifactregistry.googleapis.com \
    secretmanager.googleapis.com

1-2. Artifact Registry にリポジトリを作成

Cloud Run へデプロイするコンテナイメージの保存場所(リポジトリ)を作成します。

gcloud artifacts repositories create cloudrun-cicd-demo-repo \
    --repository-format=docker \
    --location=asia-northeast1 \
    --description="Docker repository for CI/CD demo"

1-3. サービスアカウントの作成と権限付与

CI/CD 処理を実行するための専用サービスアカウントを作成し、必要最小限のロールを付与します。

# サービスアカウント作成
gcloud iam service-accounts create cloudbuild-deployer \
    --display-name="Cloud Build Deployer"

SA_EMAIL="cloudbuild-deployer@${PROJECT_ID}.iam.gserviceaccount.com"

# 必要最小限のロールを付与
# 1. Artifact Registry 書き込み権限
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SA_EMAIL}" \
    --role="roles/artifactregistry.writer" \
    --condition=None

# 2. Cloud Run デベロッパー権限
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SA_EMAIL}" \
    --role="roles/run.developer" \
    --condition=None

# 3. ログ書き込み権限
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SA_EMAIL}" \
    --role="roles/logging.logWriter" \
    --condition=None

# 4. サービス アカウント ユーザー権限(Cloud Run への権限割り当てに必須)
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SA_EMAIL}" \
    --role="roles/iam.serviceAccountUser" \
    --condition=None

2. デプロイ用アプリケーションの作成

2-1. ファイルの作成

ローカル環境に以下のような構成でファイルを作成します。

.
├── app.py
├── requirements.txt
├── Dockerfile
└── cloudbuild.yaml

app.py – アプリケーション本体
app.py の中身
import os
from flask import Flask, render_template_string

app = Flask(__name__)

HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>Cloud Run Handson</title>
    <style>
        body { font-family: sans-serif; background-color: #f4f6f9; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
        .card { background: white; padding: 40px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); text-align: center; max-width: 500px; }
        h1 { color: #4285F4; margin-bottom: 20px; }
        p { color: #5f6368; font-size: 16px; }
        .badge { background-color: #34A853; color: white; padding: 6px 12px; border-radius: 20px; font-weight: bold; display: inline-block; margin-top: 15px; }
    </style>
</head>
<body>
    <div class="card">
        <h1>🚀 Cloud Run のデプロイ完了</h1>
        <p>GitHub × Cloud Build による自動CI/CDパイプラインが正常に実行されました!</p>
        <div class="badge">ステータス: 稼働中</div>
    </div>
</body>
</html>
"""

@app.route("/")
def index():
    return render_template_string(HTML_TEMPLATE)

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 8080))
    app.run(host="0.0.0.0", port=port)
requirements.txt – 依存ライブラリの設定
requirements.txt の中身
Flask==3.1.3
gunicorn==23.0.0
Dockerfile – コンテナイメージの定義
Dockerfile の中身
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV PORT=8080

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
cloudbuild.yaml – Cloud Build でのビルド手順・設定
cloudbuild.yaml の中身
steps:
  # 1. Dockerfile をもとにコンテナイメージを作成
  - name: 'gcr.io/cloud-builders/docker'
    args: 
      - 'build'
      - '-t'
      - '${_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:${SHORT_SHA}'
      - '.'

  # 2. Artifact Registry へのプッシュ
  - name: 'gcr.io/cloud-builders/docker'
    args: 
    - 'push'
    - '${_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:${SHORT_SHA}'

  # 3. Cloud Run へデプロイ
  - name: 'gcr.io/cloudsdktool/cloud-sdk:slim'
    args:
    - 'gcloud'
    - 'run'
    - 'deploy'
    - '${_SERVICE_NAME}'
    - '--image=${_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:${SHORT_SHA}'
    - '--region=${_LOCATION}'
    - '--platform=managed'

# 変数
substitutions:
  _LOCATION: 'asia-northeast1'
  _REPO_NAME: 'cloudrun-cicd-demo-repo'
  _SERVICE_NAME: 'cloudrun-cicd-demo-service'

# ビルド成果物
images:
  - '${_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:${SHORT_SHA}'

# オプション
options:
  logging: CLOUD_LOGGING_ONLY # ログの出力先を Cloud Logging のみに限定(カスタムサービスアカウント利用時に必須)

2-2. GitHub へプッシュ

作成したファイルを GitHub リポジトリにプッシュします。

git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/あなたのユーザー名/cloud-run-cicd-demo.git
git push -u origin main

3. Cloud Build と GitHub の連携

3-1. GitHub ホスト接続の作成

  1. Cloud Build > [リポジトリ] を開き、[第2世代] タブを選択して [ホスト接続を作成] をクリックします。
  2. 以下のように設定し、[接続] をクリックします。
    • リージョン:asia-northeast1
    • 名前:github-connection
    • Cloud KMS 鍵の選択:デフォルト(選択なし)
  3. GitHub の認証画面が開くので、[Authorize] をクリックします。
  4. 対象のリポジトリを選択し、[install] をクリックして連携を完了します。

3-2. Cloud Build トリガーの作成

  1. Cloud Build > [トリガー] を開き、[トリガーを作成] をクリックします。
  2. 以下のように設定し、[作成] をクリックします。
    • 名前:deploy-to-cloud-run
    • リージョン:asia-northeast1
    • イベント:ブランチに push する
    • リポジトリサービス:Cloud Build リポジトリ
    • リポジトリの生成:第2世代
      • リポジトリ:事前に作成した GitHubリポジトリ
      • ブランチ:^main$
    • 形式:Cloud Build 構成ファイル(yaml または json)
    • ロケーション:リポジトリ
      • Cloud Build 構成ファイルの場所:/ cloudbuild.yaml
    • サービスアカウント:作成した cloudbuild-deployer を選択

4. 動作確認

1.app.py を編集します。(例:🚀 Cloud Run のデプロイ完了 から 🚀 Deployed to Cloud Run! へ変更)

2.コミットし、git push origin main で main ブランチにプッシュします。

3.Cloud Build > [履歴] を開くと、ビルドが開始されたことが確認できます。
Cloud Build ビルド中

4.ブラウザから閲覧できるよう、Cloud Run の設定を変更します。

本ハンズオンでは動作確認を簡易化するため全ユーザー(allUsers)へアクセスを許可しています。本番環境や検証用の実務環境で運用する際は、適切な IAM 認証や IP 制限・VPC サービスコントロール等を設定してください。

 gcloud run services add-iam-policy-binding cloudrun-cicd-demo-service \
     --region=asia-northeast1 \
     --member="allUsers" \
     --role="roles/run.invoker"

5.Cloud Run > [サービス] へアクセスし、作成されたサービスの URL を開きます。

6.変更後の画面が表示されたら、自動デプロイ成功です!

ビルド・デプロイ成功後の画面

つまずいたポイントと解決策

今回の構築過程で発生したエラーの原因と解決方法のまとめです。

1. cloud-sdk イメージの取得エラー

  • 状況:ビルド中、cloud-sdk イメージのpull時にタイムアウトが発生
  • 原因:重い標準イメージ取得時の Google 内部ネットワーク一時障害やタイムアウト
  • 解決策:cloudbuild.yaml で使用するイメージを軽量版(:slim)に変更
    • 修正前:gcr.io/cloudsdktool/cloud-sdk
    • 修正後:gcr.io/cloudsdktool/cloud-sdk:slim

2. デプロイ時の権限エラー

  • 状況:gcloud run deploy 実行時に権限不足で失敗
  • 原因:Cloud Build がデプロイを行う際、Cloud Run にサービスアカウントを割り当てる(紐付ける)ための許可 roles/iam.serviceAccountUserが不足
  • 解決策:cloudbuild-deployer に roles/iam.serviceAccountUserを追加付与

3. デプロイ成功後に 403 Forbidden が表示される

  • 状況:Cloud Run の URL にアクセスしてもアクセス拒否画面が表示
  • 原因:組織ポリシーなどの影響で未認証アクセス(allUsers)の自動許可が無効化・スキップされていた
  • 解決策:CLI コマンドから手動で roles/run.invoker を allUsers に付与してアクセスを公開設定に変更

まとめ

本記事では、Cloud Run と Cloud Build を連携させて、GitHub へのプッシュをトリガーとした自動デプロイの仕組みを構築する手順について紹介しました。

これまで Google Cloud の資格試験に向けた勉強の中で、Cloud Build や Artifact Registry、IAM 権限などの知識を「座学(点)」として学んできましたが、今回実際に自分の手を動かしてコードの変更から本番環境への自動デプロイまでを構築したことで、それぞれのサービスがどう噛み合っているのか確認でき、まさに「点と点がつながった」感覚を得ることができました。

自動デプロイ環境を作ることで、手動でのビルド・デプロイ作業が不要になり、git push を行うだけで安全かつ迅速に環境へ反映できるようになります。資格勉強で得た知識を実務やハンズオンで試してみると新しい発見や学びが多くあるので、これからもこのような取り組みを継続していきたいと思います。

最後までお読みいただきありがとうございました。