Cloud Run で Pub/Sub を使用するチュートリアル


このチュートリアルでは、Cloud Run サービスの作成、デプロイ、Pub/Sub push サブスクリプションからの呼び出し方法を説明します。

目標

  • Cloud Run でサービスを書き込み、作成、ビルド、デプロイする
  • Pub/Sub トピックにメッセージを公開してサービスを呼び出す

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the Artifact Registry, Cloud Build, Pub/Sub and Cloud Run APIs.

    Enable the APIs

  7. gcloud CLI をインストールして初期化します
  8. コンポーネントを更新します。
    gcloud components update

必要なロール

チュートリアルを完了するために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセスを管理するをご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

gcloud のデフォルトを設定する

Cloud Run サービスを gcloud のデフォルトに構成するには:

  1. デフォルト プロジェクトを設定します。

    gcloud config set project PROJECT_ID

    PROJECT_ID は、このチュートリアルで作成したプロジェクトの名前に置き換えます。

  2. 選択したリージョン向けに gcloud を構成します。

    gcloud config set run/region REGION

    REGION は、任意のサポートされている Cloud Run のリージョンに置き換えます。

Cloud Run のロケーション

Cloud Run はリージョナルです。つまり、Cloud Run サービスを実行するインフラストラクチャは特定のリージョンに配置され、そのリージョン内のすべてのゾーンで冗長的に利用できるように Google によって管理されます。

レイテンシ、可用性、耐久性の要件を満たしていることが、Cloud Run サービスを実行するリージョンを選択する際の主な判断材料になります。一般的には、ユーザーに最も近いリージョンを選択できますが、Cloud Run サービスで使用されている他の Google Cloud サービスのロケーションも考慮する必要があります。使用する Google Cloud サービスが複数のロケーションにまたがっていると、サービスの料金だけでなくレイテンシにも影響します。

Cloud Run は、次のリージョンで利用できます。

ティア 1 料金を適用

  • asia-east1(台湾)
  • asia-northeast1(東京)
  • asia-northeast2(大阪)
  • asia-south1(ムンバイ、インド)
  • europe-north1(フィンランド) リーフアイコン 低 CO2
  • europe-southwest1(マドリッド) リーフアイコン 低 CO2
  • europe-west1(ベルギー) リーフアイコン 低 CO2
  • europe-west4(オランダ) リーフアイコン 低 CO2
  • europe-west8(ミラノ)
  • europe-west9(パリ) リーフアイコン 低 CO2
  • me-west1(テルアビブ)
  • us-central1(アイオワ) リーフアイコン 低 CO2
  • us-east1(サウスカロライナ)
  • us-east4(北バージニア)
  • us-east5(コロンバス)
  • us-south1(ダラス) リーフアイコン 低 CO2
  • us-west1(オレゴン) リーフアイコン 低 CO2

ティア 2 料金を適用

  • africa-south1(ヨハネスブルグ)
  • asia-east2(香港)
  • asia-northeast3(ソウル、韓国)
  • asia-southeast1(シンガポール)
  • asia-southeast2 (ジャカルタ)
  • asia-south2(デリー、インド)
  • australia-southeast1(シドニー)
  • australia-southeast2(メルボルン)
  • europe-central2(ワルシャワ、ポーランド)
  • europe-west10(ベルリン) リーフアイコン 低 CO2
  • europe-west12(トリノ)
  • europe-west2(ロンドン、イギリス) リーフアイコン 低 CO2
  • europe-west3(フランクフルト、ドイツ) リーフアイコン 低 CO2
  • europe-west6(チューリッヒ、スイス) リーフアイコン 低 CO2
  • me-central1(ドーハ)
  • me-central2(ダンマーム)
  • northamerica-northeast1(モントリオール) リーフアイコン 低 CO2
  • northamerica-northeast2(トロント) リーフアイコン 低 CO2
  • southamerica-east1(サンパウロ、ブラジル) リーフアイコン 低 CO2
  • southamerica-west1(サンティアゴ、チリ) リーフアイコン 低 CO2
  • us-west2(ロサンゼルス)
  • us-west3(ソルトレイクシティ)
  • us-west4(ラスベガス)

Cloud Run サービスをすでに作成している場合は、Google Cloud コンソールの Cloud Run ダッシュボードにリージョンが表示されます。

Artifact Registry 標準リポジトリを作成する

コンテナ イメージを保存する Artifact Registry 標準リポジトリを作成します。

gcloud artifacts repositories create REPOSITORY \
    --repository-format=docker \
    --location=REGION

次のように置き換えます。

  • REPOSITORY は、リポジトリの一意の名前に置き換えます。
  • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

Pub/Sub トピックを作成する

このサンプル サービスは Pub/Sub トピックに公開されたメッセージによってトリガーされるため、Pub/Sub でトピックを作成する必要があります。

gcloud

新しい Pub/Sub トピックを作成するには、次のコマンドを使用します。

gcloud pubsub topics create myRunTopic

myRunTopic を使用するか、Google Cloud プロジェクト内で一意のトピック名への置き換えが可能です。

Terraform

Terraform 構成を適用または削除する方法については、基本的な Terraform コマンドをご覧ください。

Pub/Sub トピックを作成するには、既存の main.tf ファイルに次の行を追加します。

resource "google_pubsub_topic" "default" {
  name = "pubsub_topic"
}

Cloud プロジェクト内で一意のトピック名を使用できます。

コードサンプルを取得する

使用するコードサンプルを取得するには:

  1. ローカルマシンにサンプルアプリのリポジトリのクローンを作成します。

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    または、zip 形式のサンプルをダウンロードしてファイルを抽出してもかまいません。

    C#

    git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

  2. Cloud Run のサンプルコードが含まれているディレクトリに移動します。

    Node.js

    cd nodejs-docs-samples/run/pubsub/

    Python

    cd python-docs-samples/run/pubsub/

    Go

    cd golang-samples/run/pubsub/

    Java

    cd java-docs-samples/run/pubsub/

    C#

    cd dotnet-docs-samples/run/Run.Samples.Pubsub.MinimalApi/

コードを確認する

このチュートリアルのコードは、次のものから構成されています。

  • 受信リクエストを処理するサーバー。

    Node.js

    Node.js サービスをテストしやすくするため、サーバー構成はサーバーの起動とは別になっています。

    Node.js ウェブサーバーは、app.js 内で設定されています。

    const express = require('express');
    const app = express();
    
    // This middleware is available in Express v4.16.0 onwards
    app.use(express.json());

    ウェブサーバーは index.js で開始します。

    const app = require('./app.js');
    const PORT = parseInt(parseInt(process.env.PORT)) || 8080;
    
    app.listen(PORT, () =>
      console.log(`nodejs-pubsub-tutorial listening on port ${PORT}`)
    );

    Python

    import base64
    
    from flask import Flask, request
    
    
    app = Flask(__name__)
    

    Go

    
    // Sample run-pubsub is a Cloud Run service which handles Pub/Sub messages.
    package main
    
    import (
    	"encoding/json"
    	"io"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", HelloPubSub)
    	// Determine port for HTTP service.
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    	// Start HTTP server.
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    

    Java

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class PubSubApplication {
      public static void main(String[] args) {
        SpringApplication.run(PubSubApplication.class, args);
      }
    }

    C#

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    var port = Environment.GetEnvironmentVariable("PORT");
    if (port != null)
    {
        app.Urls.Add($"http://0.0.0.0:{port}");
    }
    

  • Pub/Sub メッセージを処理し、応答メッセージをログに記録するハンドラ。

    Node.js

    app.post('/', (req, res) => {
      if (!req.body) {
        const msg = 'no Pub/Sub message received';
        console.error(`error: ${msg}`);
        res.status(400).send(`Bad Request: ${msg}`);
        return;
      }
      if (!req.body.message) {
        const msg = 'invalid Pub/Sub message format';
        console.error(`error: ${msg}`);
        res.status(400).send(`Bad Request: ${msg}`);
        return;
      }
    
      const pubSubMessage = req.body.message;
      const name = pubSubMessage.data
        ? Buffer.from(pubSubMessage.data, 'base64').toString().trim()
        : 'World';
    
      console.log(`Hello ${name}!`);
      res.status(204).send();
    });

    Python

    @app.route("/", methods=["POST"])
    def index():
        """Receive and parse Pub/Sub messages."""
        envelope = request.get_json()
        if not envelope:
            msg = "no Pub/Sub message received"
            print(f"error: {msg}")
            return f"Bad Request: {msg}", 400
    
        if not isinstance(envelope, dict) or "message" not in envelope:
            msg = "invalid Pub/Sub message format"
            print(f"error: {msg}")
            return f"Bad Request: {msg}", 400
    
        pubsub_message = envelope["message"]
    
        name = "World"
        if isinstance(pubsub_message, dict) and "data" in pubsub_message:
            name = base64.b64decode(pubsub_message["data"]).decode("utf-8").strip()
    
        print(f"Hello {name}!")
    
        return ("", 204)
    
    

    Go

    
    // PubSubMessage is the payload of a Pub/Sub event.
    // See the documentation for more details:
    // https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage
    type PubSubMessage struct {
    	Message struct {
    		Data []byte `json:"data,omitempty"`
    		ID   string `json:"id"`
    	} `json:"message"`
    	Subscription string `json:"subscription"`
    }
    
    // HelloPubSub receives and processes a Pub/Sub push message.
    func HelloPubSub(w http.ResponseWriter, r *http.Request) {
    	var m PubSubMessage
    	body, err := io.ReadAll(r.Body)
    	defer r.Body.Close()
    	if err != nil {
    		log.Printf("io.ReadAll: %v", err)
    		http.Error(w, "Bad Request", http.StatusBadRequest)
    		return
    	}
    	// byte slice unmarshalling handles base64 decoding.
    	if err := json.Unmarshal(body, &m); err != nil {
    		log.Printf("json.Unmarshal: %v", err)
    		http.Error(w, "Bad Request", http.StatusBadRequest)
    		return
    	}
    
    	name := string(m.Message.Data)
    	if name == "" {
    		name = "World"
    	}
    	log.Printf("Hello %s!", name)
    }
    

    Java

    import com.example.cloudrun.Body;
    import java.util.Base64;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    // PubsubController consumes a Pub/Sub message.
    @RestController
    public class PubSubController {
      @RequestMapping(value = "/", method = RequestMethod.POST)
      public ResponseEntity<String> receiveMessage(@RequestBody Body body) {
        // Get PubSub message from request body.
        Body.Message message = body.getMessage();
        if (message == null) {
          String msg = "Bad Request: invalid Pub/Sub message format";
          System.out.println(msg);
          return new ResponseEntity<>(msg, HttpStatus.BAD_REQUEST);
        }
    
        String data = message.getData();
        String target =
            !StringUtils.isEmpty(data) ? new String(Base64.getDecoder().decode(data)) : "World";
        String msg = "Hello " + target + "!";
    
        System.out.println(msg);
        return new ResponseEntity<>(msg, HttpStatus.OK);
      }
    }

    C#

    app.MapPost("/", (Envelope envelope) =>
    {
        if (envelope?.Message?.Data == null)
        {
            app.Logger.LogWarning("Bad Request: Invalid Pub/Sub message format.");
            return Results.BadRequest();
        }
    
        var data = Convert.FromBase64String(envelope.Message.Data);
        var target = System.Text.Encoding.UTF8.GetString(data);
    
        app.Logger.LogInformation($"Hello {target}!");
    
        return Results.NoContent();
    });
    

    正確な HTTP レスポンス コードを返すようにサービスをコーディングする必要があります。HTTP 200204 などの成功コードは、Pub/Sub メッセージの処理の完了を意味します。HTTP 400500 などのエラーコードは、push を使用したメッセージの受信で説明されているように、メッセージが再試行されることを示します。

  • サービスの動作環境を定義する DockerfileDockerfile の内容は言語によって異なります。

    Node.js

    
    # Use the official lightweight Node.js image.
    # https://hub.docker.com/_/node
    FROM node:20-slim
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install dependencies.
    # if you need a deterministic and repeatable build create a
    # package-lock.json file and use npm ci:
    # RUN npm ci --omit=dev
    # if you need to include development dependencies during development
    # of your application, use:
    # RUN npm install --dev
    
    RUN npm install --omit=dev
    
    # Copy local code to the container image.
    COPY . .
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Python

    
    # Use the official Python image.
    # https://hub.docker.com/_/python
    FROM python:3.11
    
    # Allow statements and log messages to immediately appear in the Cloud Run logs
    ENV PYTHONUNBUFFERED True
    
    # Copy application dependency manifests to the container image.
    # Copying this separately prevents re-running pip install on every code change.
    COPY requirements.txt ./
    
    # Install production dependencies.
    RUN pip install -r requirements.txt
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Run the web service on container startup.
    # Use gunicorn webserver with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    # Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
    

    Go

    
    # Use the offical golang image to create a binary.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.21-bookworm as builder
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Retrieve application dependencies.
    # This allows the container build to reuse cached dependencies.
    # Expecting to copy go.mod and if present go.sum.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build the binary.
    RUN go build -v -o server
    
    # Use the official Debian slim image for a lean production container.
    # https://hub.docker.com/_/debian
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM debian:bookworm-slim
    RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        ca-certificates && \
        rm -rf /var/lib/apt/lists/*
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/server /server
    
    # Run the web service on container startup.
    CMD ["/server"]
    

    Java

    このサンプルでは、Jib を使用して一般的な Java ツールにより Docker イメージをビルドします。Jib は、Dockerfile や Docker をインストールせずにコンテナのビルドを最適化します。Jib を使用して Java コンテナを構築する方法の詳細を確認します。

    <plugin>
      <groupId>com.google.cloud.tools</groupId>
      <artifactId>jib-maven-plugin</artifactId>
      <version>3.4.0</version>
      <configuration>
        <to>
          <image>gcr.io/PROJECT_ID/pubsub</image>
        </to>
      </configuration>
    </plugin>
    

    C#

    # Build in SDK base image
    FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
    WORKDIR /app
    
    COPY *.csproj ./
    RUN dotnet restore
    
    COPY . ./
    RUN dotnet publish -r linux-x64 --no-self-contained -p:PublishReadyToRun=true -c Release -o out
    
    # Copy to runtime image
    FROM mcr.microsoft.com/dotnet/aspnet:6.0
    WORKDIR /app
    COPY --from=build-env /app/out .
    
    # Port passed in by Cloud Run via environment variable PORT.  Default 8080.
    ENV PORT=8080
    
    ENTRYPOINT ["dotnet", "Run.Samples.Pubsub.MinimalApi.dll"]

Pub/Sub リクエストの送信元を認証する方法の詳細については、Pub/Sub と統合するをご覧ください。

コードを配布する

コードの配布は、Cloud Build でコンテナ イメージをビルドする、Artifact Registry にコンテナ イメージをアップロードする、Cloud Run にコンテナ イメージをデプロイするという 3 つのステップで構成されます。

コードを配布するには:

  1. コンテナをビルドして、Artifact Registry に公開します。

    Node.js

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
    次のように置き換えます。
    • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
    • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
    • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

    pubsub はイメージ名です。

    成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Artifact Registry に保存されます。このイメージは必要に応じて再利用できます。

    Python

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
    次のように置き換えます。
    • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
    • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
    • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

    pubsub はイメージ名です。

    成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Artifact Registry に保存されます。このイメージは必要に応じて再利用できます。

    Go

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
    次のように置き換えます。
    • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
    • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
    • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

    pubsub はイメージ名です。

    成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Artifact Registry に保存されます。このイメージは必要に応じて再利用できます。

    Java

    • Docker を承認して Artifact Registry に push するには、gcloud CLI 認証ヘルパーを使用します。
      gcloud auth configure-docker
    • Jib Maven プラグインを使用して、コンテナをビルドし Artifact Registry に push します。
      mvn compile jib:build -D image=REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
      次のように置き換えます。
      • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
      • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
      • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

      pubsub はイメージ名です。

      ビルドが成功すると、BUILD SUCCESS メッセージが表示されます。イメージが Artifact Registry に保存されます。このイメージは必要に応じて再利用できます。

    C#

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
    次のように置き換えます。
    • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
    • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
    • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

    pubsub はイメージ名です。

    ビルドが成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Artifact Registry に保存されます。このイメージは必要に応じて再利用できます。

  2. アプリケーションをデプロイします。

    コマンドライン

    1. 次のコマンドを実行して、アプリをデプロイします。

      gcloud run deploy pubsub-tutorial --image REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub  --no-allow-unauthenticated
      次のように置き換えます。
      • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
      • REPOSITORY は、Artifact Registry リポジトリの名前に置き換えます。
      • REGION は、Artifact Registry リポジトリに使用する Google Cloud リージョンに置き換えます。

      pubsub はイメージ名、pubsub-tutorial はサービスの名前です。コンテナ イメージは、前に gcloud の設定で構成したサービスとリージョンにデプロイされることに注意してください。

      --no-allow-unauthenticated フラグは、サービスへの未認証アクセスを制限します。サービスを非公開にすることで、Cloud Run と Pub/Sub の自動統合でリクエストの認証を行うことができます。構成の詳細については、Pub/Sub と統合するをご覧ください。Identity and Access Management(IAM)に基づく認証の詳細については、IAM を使用したアクセスの管理をご覧ください。

      デプロイが完了するまで待ちます。30 秒ほどかかる場合があります。 成功すると、コマンドラインにサービス URL が表示されます。この URL は、Pub/Sub サブスクリプションの構成で使用します。

    2. サービスにコードの更新をデプロイする場合は、上記のステップを繰り返します。サービスをデプロイするたびに、リビジョンが作成されます。準備ができると、トラフィックの送信が自動的に開始します。

    Terraform

    Cloud Run サービスを作成するには、既存の .tf ファイルに次の行を追加します。

    image の値は、イメージ URL の REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub に置き換えます。

    resource "google_cloud_run_v2_service" "default" {
      name     = "pubsub-tutorial"
      location = "us-central1"
    
      deletion_protection = false # set to true to prevent destruction of the resource
    
      template {
        containers {
          image = "us-docker.pkg.dev/cloudrun/container/hello" # Replace with newly created image gcr.io/<project_id>/pubsub
        }
      }
      depends_on = [google_project_service.cloudrun_api]
    }

Pub/Sub と統合する

Pub/Sub とサービスを統合するには:

gcloud

  1. Pub/Sub サブスクリプションの ID を表すサービス アカウントを作成または選択します。

    gcloud iam service-accounts create cloud-run-pubsub-invoker \
        --display-name "Cloud Run Pub/Sub Invoker"

    cloud-run-pubsub-invoker を使用するか、Google Cloud プロジェクト内で一意の名前への置き換えが可能です。

  2. このサービス アカウントを使用して Pub/Sub サブスクリプションを作成します。

    1. 呼び出し元のサービス アカウントに、pubsub-tutorial サービスを呼び出すための権限を付与します。

      gcloud run services add-iam-policy-binding pubsub-tutorial \
      --member=serviceAccount:cloud-run-pubsub-invoker@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/run.invoker

      IAM の変更が反映されるまでに数分かかることがあります。その間に、サービスログに HTTP 403 エラーが報告されることがあります。

    2. Pub/Sub がプロジェクトで認証トークンを作成できるようにします。

      gcloud projects add-iam-policy-binding PROJECT_ID \
         --member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
         --role=roles/iam.serviceAccountTokenCreator

      次のように置き換えます。

      • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。
      • PROJECT_NUMBER は、Google Cloud プロジェクト番号に置き換えます。

      プロジェクト ID とプロジェクト番号は、Google Cloud コンソール で、対象プロジェクトの [プロジェクト情報] パネルに表示されます。

    3. このサービス アカウントを使用して Pub/Sub サブスクリプションを作成します。

      gcloud pubsub subscriptions create myRunSubscription --topic myRunTopic \
      --ack-deadline=600 \
      --push-endpoint=SERVICE-URL/ \
      --push-auth-service-account=cloud-run-pubsub-invoker@PROJECT_ID.iam.gserviceaccount.com

      次のように置き換えます。

      • myRunTopic は、以前に作成したトピックに置き換えます。
      • SERVICE-URL は、サービスのデプロイ時に提供された HTTPS URL で置き換えます。この URL は、ドメイン マッピングを追加している場合でも機能します。
      • PROJECT_ID は、Google Cloud プロジェクト ID に置き換えます。

      --push-auth-service-account フラグは、認証と認可のために Pub/Sub の push 機能を有効にします。

      Pub/Sub サブスクリプションで使用するための Cloud Run サービス ドメインが自動的に登録されます。

      Cloud Run の場合のみ、トークンが有効であるという組み込みの認証チェックと、サービス アカウントに Cloud Run サービスを起動する権限があることの承認チェックがあります。

これで、サービスが Pub/Sub と完全に統合されました。

Terraform

  1. Pub/Sub サブスクリプションの ID を表すサービス アカウントを作成または選択します。

    resource "google_service_account" "sa" {
      account_id   = "cloud-run-pubsub-invoker"
      display_name = "Cloud Run Pub/Sub Invoker"
    }
  2. このサービス アカウントを使用して Pub/Sub サブスクリプションを作成します。

    1. 呼び出し元のサービス アカウントに、pubsub-tutorial サービスを呼び出すための権限を付与します。

      resource "google_cloud_run_service_iam_binding" "binding" {
        location = google_cloud_run_v2_service.default.location
        service  = google_cloud_run_v2_service.default.name
        role     = "roles/run.invoker"
        members  = ["serviceAccount:${google_service_account.sa.email}"]
      }
    2. Pub/Sub がプロジェクトで認証トークンを作成できるようにします。

      resource "google_project_service_identity" "pubsub_agent" {
        provider = google-beta
        project  = data.google_project.project.project_id
        service  = "pubsub.googleapis.com"
      }
      
      resource "google_project_iam_binding" "project_token_creator" {
        project = data.google_project.project.project_id
        role    = "roles/iam.serviceAccountTokenCreator"
        members = ["serviceAccount:${google_project_service_identity.pubsub_agent.email}"]
      }
    3. このサービス アカウントを使用して Pub/Sub サブスクリプションを作成します。

      resource "google_pubsub_subscription" "subscription" {
        name  = "pubsub_subscription"
        topic = google_pubsub_topic.default.name
        push_config {
          push_endpoint = google_cloud_run_v2_service.default.uri
          oidc_token {
            service_account_email = google_service_account.sa.email
          }
          attributes = {
            x-goog-version = "v1"
          }
        }
        depends_on = [google_cloud_run_v2_service.default]
      }

これで、サービスが Pub/Sub と完全に統合されました。

試してみる

エンドツーエンドのソリューションをテストするには、次の手順を行います。

  1. トピックに Pub/Sub メッセージを送信します。

    gcloud pubsub topics publish myRunTopic --message "Runner"

    このチュートリアルで説明したコマンドラインを使用する代わりに、プログラムでメッセージを発行することもできます。詳しくは、メッセージの公開をご覧ください。

  2. サービスログに移動します。

    1. Google Cloud コンソール に移動します。
    2. pubsub-tutorial サービスをクリックします。
    3. [ログ] タブを選択します。

      ログが表示されるまで少し時間がかかることがあります。すぐに表示されない場合は、しばらくしてからもう一度確認してください。

  3. 「Hello Runner!」というメッセージを見つけます。

クリーンアップ

Cloud Run with Pub/Sub を使用する場合の詳しい使用方法については、今すぐクリーンアップをスキップし、Cloud Run を使用した画像処理のチュートリアルをご覧ください。

このチュートリアル用に新規プロジェクトを作成した場合は、そのプロジェクトを削除します。既存のプロジェクトを使用し、このチュートリアルで変更を加えずに残す場合は、チュートリアル用に作成したリソースを削除します。

プロジェクトを削除する

課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

チュートリアル リソースを削除する

  1. このチュートリアルでデプロイした Cloud Run サービスを削除します。

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME は、選択したサービス名です。

    Cloud Run サービスは Google Cloud コンソール から削除することもできます。

  2. チュートリアルの設定時に追加した gcloud のデフォルト リージョン構成を削除します。

     gcloud config unset run/region
    
  3. プロジェクト構成を削除します。

     gcloud config unset project
    
  4. このチュートリアルで作成した他の Google Cloud リソースを削除します。

次のステップ