搭配 Cloud Run 使用 Pub/Sub 教學課程

本教學課程說明如何撰寫、部署 Cloud Run 服務,並從 Pub/Sub 推送訂閱呼叫服務。

設定 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 定價

採用級別 2 定價

  • africa-south1 (約翰尼斯堡)
  • asia-east2 (香港)
  • asia-northeast3 (韓國首爾)
  • asia-southeast1 (新加坡)
  • asia-southeast2 (雅加達)
  • asia-south2 (印度德里)
  • australia-southeast1 (雪梨)
  • australia-southeast2 (墨爾本)
  • europe-central2 (波蘭華沙)
  • europe-west10 (柏林)
  • europe-west12 (杜林)
  • europe-west2 (英國倫敦) 節能綠葉圖示 二氧化碳排放量低
  • europe-west3 (德國法蘭克福)
  • europe-west6 (瑞士蘇黎世) 節能綠葉圖示 二氧化碳排放量低
  • me-central1 (杜哈)
  • me-central2 (達曼)
  • northamerica-northeast1 (蒙特婁) 節能綠葉圖示 二氧化碳排放量低
  • northamerica-northeast2 (多倫多) 節能綠葉圖示 二氧化碳排放量低
  • southamerica-east1 (巴西聖保羅) 節能綠葉圖示 二氧化碳排放量低
  • southamerica-west1 (智利聖地牙哥) 節能綠葉圖示 二氧化碳排放量低
  • 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

    
    // WrappedMessage is the payload of a Pub/Sub event.
    //
    // For more information about receiving messages from a Pub/Sub event
    // see: https://cloud.google.com/pubsub/docs/push#receive_push
    type WrappedMessage 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 WrappedMessage
    	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) 表示系統會重新嘗試處理訊息。詳情請參閱 「利用推送功能接收訊息」指南

  • 定義服務作業環境的 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 official Go image to create a binary.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.24-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。

如要推送程式碼:

  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

    • 使用 gcloud CLI 憑證輔助程式,授權 Docker 推送至 Artifact Registry。
      gcloud auth configure-docker
    • 使用 Jib Maven 外掛程式建構容器,並推送至 Artifact Registry。
      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 整合」一節。如要進一步瞭解以身分與存取權管理 (IAM) 為基礎的驗證,請參閱「使用 IAM 管理存取權」。

      請等待部署完成,這可能需要半分鐘的時間。 成功完成後,指令列會顯示服務網址。這個網址可用來設定 Pub/Sub 訂閱項目。

    2. 如要將程式碼更新部署到服務,請重複上述步驟。每次部署到服務都會建立一個新的修訂版本,並會在就緒時自動開始處理流量。

    Terraform

    如要建立 Cloud Run 服務,請在現有的 .tf 檔案中新增下列項目。

    resource "google_project_service" "cloudrun_api" {
       service            = "run.googleapis.com"
       disable_on_destroy = false
    }
    
    resource "google_cloud_run_v2_service" "default" {
       name     = "pubsub-tutorial"
       location = "REGION"
    
       template {
          containers {
             image = "IMAGE_URL"
         }
       }
       depends_on = [google_project_service.cloudrun_api]
    }
             
    取代:
    • IMAGE_URL 圖片網址:REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub
    • REGION 改成要用於 Artifact Registry 存放區的 Google Cloud 地區。

與 Pub/Sub 整合

如要整合服務與 Pub/Sub:

gcloud

  1. 建立或選擇服務帳戶,代表 Pub/Sub 訂閱身分。

    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 控制台「Project info」(專案資訊) 面板中。

    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 網址。即使您新增了網域對應,這個網址仍可正常運作。
      • PROJECT_ID 改成您的 Google Cloud 專案 ID。

      --push-auth-service-account 標記的作用是啟動 Pub/Sub 推送功能,以進行驗證和授權

      系統會自動註冊 Cloud Run 服務網域,以搭配 Pub/Sub 訂閱使用。

      如果是 Cloud Run,系統會內建驗證檢查,確認符記是否有效,並進行授權檢查,確認服務帳戶是否具備叫用 Cloud Run 服務的權限。

您的服務現在已與 Pub/Sub 完全整合。

Terraform

  1. 建立或選擇服務帳戶,代表 Pub/Sub 訂閱身分。

    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. 選取 [Logs] (記錄) 分頁標籤。

      記錄需要一些時間才會出現。如果您沒有立即看到記錄,請稍候片刻再查看一次。

  3. 尋找「Hello Runner!」訊息。