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


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

目標

  • 撰寫、建構及部署至 Cloud Run 的服務
  • 將訊息發布至 Pub/Sub 主題,藉此叫用服務。

費用

在本文件中,您將使用 Google Cloud的下列計費元件:

您可以使用 Pricing Calculator 根據預測用量產生預估費用。 新 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
  9. 必要的角色

    如要取得完成本教學課程所需的權限,請要求管理員為您授予專案的下列 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 定價

採用級別 2 定價

如果您已建立 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.23-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 建構 Docker 映像檔,並使用常見的 Java 工具。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
    Replace:
    • 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
    Replace:
    • 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 檔案中新增下列內容。

    image 的值替換為圖片網址:REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/pubsub

    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 = "us-central1"
    
       template {
          containers {
             image = "us-docker.pkg.dev/cloudrun/container/hello" # Replace with newly created image gcr.io//pubsub
         }
       }
       depends_on = [google_project_service.cloudrun_api]
    }
             

整合 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!」訊息。

清除所用資源

如要深入瞭解搭配使用 Cloud Run 和 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 是您選擇的服務名稱。

    您也可以從 Google Cloud 控制台刪除 Cloud Run 服務。

  2. 移除您在教學課程設定期間新增的 gcloud 預設區域設定:

     gcloud config unset run/region
    
  3. 移除專案設定:

     gcloud config unset project
    
  4. 刪除本教學課程中建立的其他 Google Cloud 資源:

後續步驟