튜토리얼: Eventarc를 사용하여 Cloud Run 서비스 디버깅

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

이 튜토리얼에서는 Cloud 감사 로그를 사용하여 Cloud Storage의 이벤트를 인증되지 않은 Cloud Run 서비스에 배포할 때 발생하는 런타임 오류 문제를 해결하는 방법을 설명합니다.

목표

  • 이벤트 소스로 사용할 Cloud Storage 버킷을 만듭니다.
  • 컨테이너 이미지를 Cloud Run에 빌드, 업로드, 배포합니다.
  • Eventarc 트리거를 만듭니다.
  • 파일을 Cloud Storage 버킷에 업로드합니다.
  • 런타임 오류 문제를 해결합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 튜토리얼을 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않게 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

Cloud 감사 로그 이벤트 수신의 기본 요건을 따릅니다.

Cloud Storage 버킷 만들기

2개의 리전에 Cloud Run 서비스의 이벤트 소스로 2개의 스토리지 버킷을 만듭니다.

us-east1

export BUCKET1="troubleshoot-bucket1-PROJECT_ID"
gsutil mb -l us-east1 gs://${BUCKET1}

us-west1

export BUCKET2="troubleshoot-bucket2-$PROJECT_ID"
gsutil mb -l us-west1 gs://${BUCKET2}

이벤트 소스가 생성되면 Cloud Run에 이벤트 수신자 서비스를 배포합니다.

코드 샘플 검색

저장소를 복제합니다.

Go

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

자바

git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
cd java-docs-samples/eventarc/audit-storage

.NET

git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git
cd dotnet-docs-samples/eventarc/audit-storage

Node.js

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
cd nodejs-docs-samples/eventarc/audit-storage

Python

git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
cd python-docs-samples/eventarc/audit-storage

코드 검토

이 튜토리얼의 코드는 다음과 같이 구성됩니다.

  • HTTP POST 요청 내에서 CloudEvent에 래핑된 수신 메시지를 처리하는 서버:

    Go

    
    // Sample audit_storage is a Cloud Run service which handles Cloud Audit Log events with Cloud Storage data.
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    // HelloEventsStorage receives and processes a Cloud Audit Log event with Cloud Storage data.
    func HelloEventsStorage(w http.ResponseWriter, r *http.Request) {
    	s := fmt.Sprintf("Detected change in Cloud Storage bucket: %s", string(r.Header.Get("Ce-Subject")))
    	log.Printf(s)
    	fmt.Fprintln(w, s)
    }
    

    자바

    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestHeader;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class EventController {
    
      private static final List<String> requiredFields =
          Arrays.asList("ce-id", "ce-source", "ce-type", "ce-specversion");
    
      @RequestMapping(value = "/", method = RequestMethod.POST)
      public ResponseEntity<String> receiveMessage(
          @RequestBody Map<String, Object> body, @RequestHeader Map<String, String> headers) {
        for (String field : requiredFields) {
          if (headers.get(field) == null) {
            String msg = String.format("Missing expected header: %s.", field);
            System.out.println(msg);
            return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
          }
        }
    
        if (headers.get("ce-subject") == null) {
          String msg = "Missing expected header: ce-subject.";
          System.out.println(msg);
          return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
        }
    
        String ceSubject = headers.get("ce-subject");
        String msg = "Detected change in Cloud Storage bucket: " + ceSubject;
        System.out.println(msg);
        return new ResponseEntity<String>(msg, HttpStatus.OK);
      }
    }

    .NET

    
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
    
            logger.LogInformation("Service is starting...");
    
            app.UseRouting();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapPost("/", async context =>
                {
                    logger.LogInformation("Handling HTTP POST");
    
                    var ceSubject = context.Request.Headers["ce-subject"];
                    logger.LogInformation($"ce-subject: {ceSubject}");
    
                    if (string.IsNullOrEmpty(ceSubject))
                    {
                        context.Response.StatusCode = 400;
                        await context.Response.WriteAsync("Bad Request: expected header Ce-Subject");
                        return;
                    }
    
                    await context.Response.WriteAsync($"GCS CloudEvent type: {ceSubject}");
                });
            });
        }
    }
    

    Node.js

    const express = require('express');
    const app = express();
    
    app.use(express.json());
    app.post('/', (req, res) => {
      if (!req.header('ce-subject')) {
        return res
          .status(400)
          .send('Bad Request: missing required header: ce-subject');
      }
    
      console.log(
        `Detected change in Cloud Storage bucket: ${req.header('ce-subject')}`
      );
      return res
        .status(200)
        .send(
          `Detected change in Cloud Storage bucket: ${req.header('ce-subject')}`
        );
    });
    
    module.exports = app;

    Python

    import os
    
    from flask import Flask, request
    
    app = Flask(__name__)
    if __name__ == "__main__":
        app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
  • 서비스의 작동 환경을 정의하는 Dockerfile입니다. Dockerfile의 콘텐츠는 언어별로 다릅니다.

    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.17-buster 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:buster-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"]
    

    자바

    
    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.8-jdk-11 as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml .
    COPY src ./src
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk11:alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/audit-storage-*.jar /audit-storage.jar
    
    # Run the web service on container startup.
    CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/audit-storage.jar"]
    

    .NET

    
    # Use Microsoft's official build .NET image.
    # https://hub.docker.com/_/microsoft-dotnet-core-sdk/
    FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    WORKDIR /app
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Use Microsoft's official runtime .NET image.
    # https://hub.docker.com/_/microsoft-dotnet-core-aspnet/
    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine AS runtime
    WORKDIR /app
    COPY --from=build /app/out ./
    
    # Run the web service on container startup.
    ENTRYPOINT ["dotnet", "AuditStorage.dll"]

    Node.js

    
    # Use the official lightweight Node.js 10 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.10-slim
    
    # 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.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

코드 제공

코드를 제공하려면 다음 안내를 따르세요.

  1. Cloud Build로 컨테이너 이미지를 빌드하고 Container Registry에 업로드합니다.

    Go

     gcloud builds submit --tag gcr.io/PROJECT_ID/audit-storage

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    성공하면 ID, 생성 시간, 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다. 이미지는 Container Registry에 저장되며 원하는 경우 다시 사용할 수 있습니다.

    자바

    1. gcloud 사용자 인증 정보 도우미를 사용하여 Docker가 Container Registry로 컨테이너를 푸시하도록 승인합니다.
      gcloud auth configure-docker
    2. Jib Maven 플러그인을 사용하여 컨테이너를 빌드하고 Container Registry로 내보냅니다.

      mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/audit-storage

      PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

      audit-storage는 컨테이너 이름입니다. 성공하면 SUCCESS 메시지가 표시됩니다. 이미지는 Container Registry에 저장되며 원하는 경우 다시 사용할 수 있습니다.

    .NET

     gcloud builds submit --tag gcr.io/PROJECT_ID/audit-storage

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    성공하면 ID, 생성 시간, 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다. 이미지는 Container Registry에 저장되며 원하는 경우 다시 사용할 수 있습니다.

    Node.js

     gcloud builds submit --tag gcr.io/PROJECT_ID/audit-storage

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    성공하면 ID, 생성 시간, 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다. 이미지는 Container Registry에 저장되며 원하는 경우 다시 사용할 수 있습니다.

    Python

     gcloud builds submit --tag gcr.io/PROJECT_ID/audit-storage

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    성공하면 ID, 생성 시간, 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다. 이미지는 Container Registry에 저장되며 원하는 경우 다시 사용할 수 있습니다.

  2. 컨테이너 이미지를 Cloud Run에 배포합니다.

    gcloud run deploy troubleshoot-service --image gcr.io/PROJECT_ID/audit-storage \
    --allow-unauthenticated
    

    PROJECT_ID를 GCP 프로젝트 ID로 바꿉니다.
    audit-storage는 컨테이너 이름이고 troubleshoot-service는 Cloud Run 서비스의 이름입니다.

    컨테이너 이미지는 이전에 gcloud 설정에서 구성한 서비스 및 리전에 배포됩니다.

  3. Cloud Run에 배포할 때 인증되지 않은 호출 허용 프롬프트에 y, '예'라고 응답합니다. IAM 기반 인증에 대한 자세한 내용은 Eventarc 역할 및 권한을 참조하세요.

    배포가 성공하면 명령줄에 서비스 URL이 표시됩니다.

트리거 만들기

이제 Cloud Run 서비스를 배포했으므로 감사 로그를 통해 Cloud Storage의 이벤트를 리슨하도록 트리거를 설정합니다.

  1. Cloud Storage 이벤트를 리슨하는 감사 로그 트리거를 만듭니다.

    gcloud eventarc triggers create troubleshoot-trigger \
     --destination-run-service=troubleshoot-service \
     --event-filters="type=google.cloud.audit.log.v1.written" \
     --event-filters="serviceName=storage.googleapis.com" \
     --event-filters="methodName=storage.objects.create" \
     --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    그러면 troubleshoot-trigger라는 트리거가 생성됩니다.

  2. troubleshoot-trigger가 생성되었는지 확인하려면 다음을 실행합니다.

    gcloud eventarc triggers list
    

    troubleshoot-triggertroubleshoot-service의 대상과 함께 나열되어 표시됩니다.

이벤트 생성 및 확인

서비스가 성공적으로 배포되었고 Cloud Storage에서 이벤트를 수신할 수 있는지 확인하려면 다음 안내를 따르세요.

  1. 파일을 만들고 첫 번째 스토리지 버킷에 업로드합니다.

     echo "Hello World" > random.txt
     gsutil cp random.txt gs://${BUCKET1}/random.txt
    
  2. 로그를 모니터링하여 서비스에서 이벤트가 수신되었는지 확인합니다. 서비스 로그는 서비스가 설정에 문제가 있음을 나타내는 이벤트를 리슨하고 있음을 보여줍니다.

    Now listening on: http://0.0.0.0:8080

문제 조사

이제 서비스가 이벤트를 수신하지 않는 이유를 조사하는 프로세스를 진행할 수 있습니다.

감사 로그

이 튜토리얼에서는 Cloud Storage 이벤트가 감사 로그를 통해 내보내지고 Cloud Run으로 전송됩니다. Cloud Storage에 감사 로그가 사용 설정되어 있는지 확인합니다.

  1. IAM 및 관리자 > 감사 로그로 이동하고 Google Cloud Storage 체크박스를 선택합니다. Cloud 감사 로그 콘솔로 이동
  2. Cloud 감사 로그의 관리자 읽기, 데이터 읽기, 데이터 쓰기 로그 유형이 선택되어 있는지 확인합니다.

Cloud 감사 로그가 사용 설정되면 파일을 다시 업로드하고 로그를 확인합니다. 서비스가 여전히 이벤트를 수신하지 않으면 이는 트리거 위치와 관련이 있을 수 있습니다.

트리거 위치

서로 다른 위치에 여러 리소스가 있을 수 있으며, Cloud Run 대상과 동일한 리전에 있는 소스의 이벤트를 필터링해야 합니다. 자세한 내용은 Eventarc에서 지원되는 위치를 참조하세요.

이 튜토리얼에서는 Cloud Run 서비스를 us-central1에 배포했습니다. 또한 eventarc/locationus-central1로 설정되어 있으므로 동일한 위치에 트리거를 만들었습니다.

트리거의 위치를 나열하려면 트리거를 설명합니다.

gcloud eventarc triggers describe troubleshoot-trigger

그러나 us-east1us-west1 위치에 두 개의 버킷을 만들었습니다. 이러한 위치에서 이벤트를 수신하려면 해당 위치에서 트리거를 만들어야 합니다. us-east1에서 트리거를 만들어 보겠습니다.

  1. us-central1 위치에서 기존 트리거를 삭제합니다.

       gcloud eventarc triggers delete troubleshoot-trigger
    
  2. 위치 및 리전을 us-east1로 설정합니다.

      gcloud config set eventarc/location us-east1
      gcloud config set run/region us-east1
    
  3. 코드를 다시 발송합니다.

  4. us-east1 위치에 새 트리거를 만듭니다.

     gcloud eventarc triggers create troubleshoot-trigger \
       --destination-run-service=troubleshoot-service \
       --event-filters="type=google.cloud.audit.log.v1.written" \
       --event-filters="serviceName=storage.googleapis.com" \
       --event-filters="methodName=storage.objects.create" \
       --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com
    
  5. 트리거가 생성되었는지 확인합니다.

       gcloud eventarc triggers list
    

트리거가 이벤트를 전송하기 시작하기 전에 초기화하는 데 최대 10분이 걸릴 수 있습니다.

초기화 시간

트리거가 생성되면 이벤트가 진행되기 전에 최대 10분의 초기화 시간이 발생합니다. 다음 명령어를 실행하여 트리거가 활성 상태인지 확인합니다.

   gcloud eventarc triggers list

트리거의 상태를 나타내는 유사한 결과가 표시됩니다.

    NAME                   TYPE                               DESTINATION_RUN_SERVICE  DESTINATION_RUN_PATH  ACTIVE
    troubleshoot-trigger3  google.cloud.audit.log.v1.written  troubleshoot-service2                          By 14:16:56
    troubleshoot-trigger   google.cloud.audit.log.v1.written  troubleshoot-service                           Yes

10분 후 각 버킷에 파일을 다시 업로드합니다. 각 파일의 이벤트는 Cloud Run 서비스 로그에 기록됩니다. 서비스가 이벤트를 수신하지 않는 경우 이벤트 크기와 관련이 있을 수 있습니다.

이벤트 크기

전송하는 이벤트가 이벤트 크기(512KB)의 한도를 초과해서는 안 됩니다.

이전에 이벤트를 전달한 트리거의 작동이 중지되었습니다.

  1. 소스가 이벤트를 생성하는지 확인합니다. Cloud 감사 로그를 확인하고 모니터링되는 서비스가 로그를 내보내는지 확인합니다. 로그가 기록되지만 이벤트가 전송되지 않으면 지원팀에 문의합니다.

  2. 트리거 이름이 동일한 Pub/Sub 주제가 있는지 확인합니다.

    1. 트리거를 나열하려면 gcloud eventarc 트리거 목록을 참조하세요.
    2. Pub/Sub 주제를 나열하려면 다음을 실행합니다.

        gcloud pubsub topics list
      

    Pub/Sub 주제 이름에 생성된 트리거의 이름이 포함되어 있는지 확인합니다. Pub/Sub 주제가 누락된 경우 트리거를 만들 때 주제를 만듭니다.

  3. Pub/Sub 주제의 상태를 확인합니다.

    1. 트리거 탭에 체크표시 이 있는지 확인합니다. Cloud Console에서 Cloud Run으로 이동하여 생성한 서비스를 선택하고 트리거 탭으로 이동합니다.

    2. Pub/Sub > 주제로 이동하고 Pub/Sub 주제를 클릭합니다.

      Pub/Sub 주제로 이동

    3. 메시지가 topic/send_message_operation_count 측정항목과 함께 주제에 게시되었는지 모니터링합니다. 메시지가 주제에 게시되지 않으면 Cloud 감사 로그를 확인하고 모니터링되는 서비스가 로그를 내보내는지 확인합니다. 로그가 기록되지만 이벤트가 전송되지 않으면 지원팀에 문의합니다.

      주제 측정항목

    4. response_codesubscription/push_request_count 측정항목을 사용하여 Cloud Run에 메시지가 성공적으로 푸시되는지 모니터링합니다.

      1. Cloud Console에서 Cloud Monitoring으로 이동합니다.

        모니터링으로 이동

      2. 새 작업공간에 프로젝트를 추가합니다.

      3. 대시보드를 클릭하고 Cloud Pub/Sub 대시보드를 선택합니다.

      4. Cloud Pub/Sub 대시보드에서 사용자가 만든 Pub/Sub 주제를 클릭합니다.

      5. 이슈 섹션에서 정책 만들기를 클릭합니다.

      6. 알림 정책 만들기 페이지에서 조건 추가를 클릭합니다.

      7. 측정항목 탭에서 다음 조건을 지정합니다.

        • 리소스 유형Cloud Pub/Sub 구독
        • 측정항목푸시 요청
        • Group by응답 코드
        • 0구성 임곗값으로 선택합니다. 구독 측정항목 Pub/Sub의 사용량 측정항목에 대한 자세한 내용은 푸시 구독 모니터링을 참조하세요.
      8. 추가를 클릭하여 알림 정책 만들기 페이지로 이동합니다.

      9. 문제 해결 단계 선택 섹션에서 알림 이름(예: samplealert)을 입력하고 저장을 클릭합니다.

      10. 알림을 보려면 Monitoring > 대시보드 > Cloud Pub/Sub로 이동합니다. Pub/Sub 주제를 클릭하고 구독 탭을 클릭합니다.

      푸시 오류가 보고되면 Cloud Run 서비스 로그를 확인합니다. 수신 엔드포인트가 OK가 아닌 상태 코드를 반환하면 Cloud Run 코드가 예상대로 작동하지 않는다는 의미이며 지원팀에 문의해야 합니다.

삭제

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

프로젝트 삭제

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

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

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

    리소스 관리로 이동

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

튜토리얼 리소스 삭제

  1. 이 튜토리얼에서 배포한 Cloud Run 서비스를 삭제합니다.

    gcloud run services delete SERVICE_NAME

    여기서 SERVICE_NAME은 선택한 서비스 이름입니다.

    Google Cloud Console에서 Cloud Run 서비스를 삭제할 수도 있습니다.

  2. 튜토리얼 설정 중에 추가한 gcloud CLI 기본 구성을 삭제합니다.

    예를 들면 다음과 같습니다.

    gcloud config unset run/region

    또는

    gcloud config unset project

  3. 이 가이드에서 만든 다른 Google Cloud 리소스를 삭제합니다.

    • Eventarc 트리거를 삭제합니다.
      gcloud eventarc triggers delete TRIGGER_NAME
      
      TRIGGER_NAME을 트리거의 이름으로 바꿉니다.

    • Container Registry에서 가져온 gcr.io/PROJECT_ID/audit-storage라는 컨테이너 이미지 삭제 PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

다음 단계

  • Eventarc를 사용할 때 발생할 수 있는 다른 문제를 해결하려면 문제 해결을 참조하세요.