Cloud Run에서 Pub/Sub 사용 튜토리얼


이 튜토리얼에서는 Cloud Run 서비스를 작성, 배포하고 Pub/Sub 푸시 구독으로부터 호출하는 방법을 보여줍니다.

목표

  • 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. API Artifact Registry, Cloud Build, Pub/Sub and Cloud Run 사용 설정

    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은 다음 리전에서 사용할 수 있습니다.

등급 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

등급 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"
}

클라우드 프로젝트 내에서 고유한 주제 이름을 사용할 수 있습니다.

코드 샘플 검색

사용할 코드 샘플을 검색하려면 다음 안내를 따르세요.

  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 200 또는 204와 같은 성공 코드는 Pub/Sub 메시지 처리가 완료되었음을 나타냅니다. HTTP 400 또는 500과 같은 오류 코드는 푸시를 사용하여 메시지 수신 가이드에 설명된 것처럼 메시지가 재시도됨을 나타냅니다.

  • 서비스의 작동 환경을 정의하는 Dockerfile입니다. Dockerfile 콘텐츠는 언어별로 다릅니다.

    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를 사용해서 일반적인 자바 도구로 Docker 이미지를 빌드합니다. Jib는 Dockerfile을 사용하거나 Docker를 설치할 필요 없이 컨테이너 빌드를 최적화합니다. Jib로 자바 컨테이너 빌드에 대해 자세히 알아보세요.

    <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, 생성 시간, 이미지 이름이 포함된 성공 메시지가 표시됩니다. 이미지는 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, 생성 시간, 이미지 이름이 포함된 성공 메시지가 표시됩니다. 이미지는 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 푸시 기능을 활성화합니다.

      Cloud Run 서비스 도메인은 Pub/Sub 구독에 사용할 수 있도록 자동으로 등록됩니다.

      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!' 메시지를 찾습니다.

삭제

Pub/Sub에서 Cloud Run을 사용하는 보다 세부적인 심화 사용 사례를 연습하려면 지금 삭제 단계를 건너뛰고 계속해서 Cloud Run으로 이미지 처리 튜토리얼을 진행하세요.

이 튜토리얼용으로 새 프로젝트를 만든 경우 이 프로젝트를 삭제합니다. 기존 프로젝트를 사용한 경우 이 튜토리얼에 추가된 변경사항은 제외하고 보존하려면 튜토리얼용으로 만든 리소스를 삭제합니다.

프로젝트 삭제

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

프로젝트를 삭제하려면 다음 안내를 따르세요.

  1. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

튜토리얼 리소스 삭제

  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 리소스를 삭제합니다.

다음 단계