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


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

目標

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

費用

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

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

始める前に

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  5. Google Cloud プロジェクトで課金が有効になっていることを確認します

  6. Artifact Registry、Cloud Build、Pub/Sub、Cloud Run API を有効にします。

    API を有効にする

  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 は、次のリージョンで利用できます。

Tier 1 料金を適用

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

Tier 2 料金を適用

  • africa-south1(ヨハネスブルグ)
  • asia-east2(香港)
  • asia-northeast3(ソウル、韓国)
  • asia-southeast1(シンガポール)
  • asia-southeast2 (ジャカルタ)
  • asia-south1(ムンバイ、インド)
  • asia-south2(デリー、インド)
  • australia-southeast1(シドニー)
  • australia-southeast2(メルボルン)
  • europe-central2(ワルシャワ、ポーランド)
  • europe-west10(ベルリン)
  • 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 でトピックを作成する必要があります。

コマンドライン

新しい 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/pubsub/

コードを確認する

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

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

    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/ioutil"
    	"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 := ioutil.ReadAll(r.Body)
    	if err != nil {
    		log.Printf("ioutil.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:18-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 add a package-lock.json speed your build by switching to 'npm ci'.
    # RUN npm ci --only=production
    RUN npm install --production
    
    # 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"
      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 とサービスを統合するには:

コマンドライン

  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. Google Cloud コンソールで、[リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

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

  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 リソースを削除します。

次のステップ