C#으로 Google Cloud Functions

1. 소개

Google Cloud Run 함수는 이벤트 기반 서버리스 컴퓨팅 플랫폼입니다. Cloud Run 함수를 사용하면 리소스 프로비저닝이나 요구사항 변경에 맞춰 확장하는 데 대한 걱정 없이 코드를 작성할 수 있습니다.

Cloud Run Functions에는 다음과 같은 두 가지 유형이 있습니다.

  • HTTP 함수는 HTTP 요청에 응답합니다.
  • 이벤트 함수는 Cloud Pub/Sub에 메시지가 게시되거나 Cloud Storage에 파일이 업로드되는 등의 이벤트에 의해 트리거됩니다.

efb3268e3b74ed4f.png

이 Codelab에서는 C#로 자체 Cloud Run 함수를 만드는 방법을 안내합니다. 구체적으로 다양한 Google Cloud 소스의 HTTP 및 CloudEvents에 응답하는 C# 함수를 배포합니다.

학습할 내용

  • .NET용 Functions 프레임워크
  • HTTP 함수를 작성하는 방법
  • Cloud Storage 이벤트에 응답하는 이벤트 트리거 함수를 작성하는 방법
  • Cloud Pub/Sub 이벤트에 응답하는 이벤트 트리거 함수를 작성하는 방법
  • 모든 유형의 이벤트에 응답하는 이벤트 트리거 함수를 작성하는 방법

2. 설정 및 요구사항

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유해야 하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔은 고유한 문자열을 자동으로 생성합니다. 일반적으로는 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 다른 임의 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스 또는 전체 프로젝트를 삭제하면 됩니다. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

Cloud Shell 시작

Google Cloud를 노트북에서 원격으로 실행할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.

Google Cloud Console의 오른쪽 상단 툴바에 있는 Cloud Shell 아이콘을 클릭합니다.

55efc1aaa7a4d3ad.png

환경을 프로비저닝하고 연결하는 데 몇 분 정도 소요됩니다. 완료되면 다음과 같이 표시됩니다.

7ffe5cbb04455448.png

가상 머신에는 필요한 개발 도구가 모두 들어있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab의 모든 작업은 브라우저 내에서 수행할 수 있습니다. 아무것도 설치할 필요가 없습니다.

3. 시작하기 전에

Cloud Shell에서 다음 명령어를 실행하여 필요한 서비스를 사용 설정합니다.

gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  eventarc.googleapis.com \
  run.googleapis.com

그런 다음 리전을 설정합니다.

REGION=<YOUR_REGION>

이 Codelab에서는 Cloud Storage에서 이벤트를 수신하고 Cloud Run 함수를 호출하는 데 필요한 Eventarc 권한과 Cloud Run 호출자 역할이 있는 서비스 계정을 만듭니다.

먼저 서비스 계정을 만듭니다.

PROJECT_ID=$(gcloud config get-value core/project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

SERVICE_ACCOUNT="cloud-run-functions"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Cloud Run functions Eventarc service account"

그런 다음 트리거가 이벤트 제공업체에서 이벤트를 수신할 수 있도록 프로젝트에 Eventarc 트리거와 연결된 서비스 계정에 Eventarc 이벤트 수신자 역할 (roles/eventarc.eventReceiver)을 부여합니다.

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role=roles/eventarc.eventReceiver

그런 다음 서비스 계정이 함수를 호출할 수 있도록 Cloud Run 호출자 역할을 부여합니다.

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role=roles/run.invoker

4. .NET용 Functions 프레임워크

.NET용 함수 프레임워크는 Google Cloud Functions팀에서 제공하는 포팅 가능한 .NET 함수를 작성할 수 있는 오픈소스 FaaS (서비스로서의 기능) 프레임워크입니다.

함수 프레임워크를 사용하면 다음을 포함한 여러 다양한 환경에서 실행되는 가벼운 함수를 만들 수 있습니다.

  • Google Cloud Run 함수
  • 로컬 개발 머신
  • Cloud Run 및 GKE의 Cloud Run
  • Knative 기반 환경

이 Codelab에서는 .NET용 Functions 프레임워크와 템플릿을 사용하여 C#로 Cloud Functions를 만들고 배포합니다.

Cloud Shell에서 다음 명령어를 실행하여 dotnet용 Cloud Functions 템플릿을 설치합니다.

dotnet new install Google.Cloud.Functions.Templates

이렇게 하면 dotnet용 템플릿 3개가 설치됩니다. 각 템플릿은 C#, F#, VB로 제공되지만 이 실습에서는 C#만 사용합니다. 다음을 실행하여 템플릿이 설치되었는지 확인할 수 있습니다.

dotnet new list

Templates                                                 Short Name            
-----------------------------------------------------------------------
Google Cloud Functions CloudEvent Function                gcf-event
Google Cloud Functions CloudEvent Function (Untyped)      gcf-untyped-event
Google Cloud Functions HttpFunction                       gcf-http

5. HTTP 함수

HTTP 요청에 응답하는 HTTP 함수를 만들고 배포합니다.

gcf-http 템플릿을 사용하여 HTTP 함수를 만듭니다.

mkdir HelloHttp
cd HelloHttp
dotnet new gcf-http

이렇게 하면 프로젝트와 HTTP 요청에 응답하는 Function.cs 파일이 생성됩니다.

.csproj 파일에서 대상 프레임워크를 net8.0로 변경합니다.

<TargetFramework>net8.0</TargetFramework>

Cloud Run 함수를 Cloud Run에 직접 배포하려면 다음 명령어를 실행합니다.

gcloud beta run deploy hello-http-function \
    --source . \
    --function HelloHttp.Function \
    --base-image dotnet8 \
    --region $REGION \
    --allow-unauthenticated

Cloud Functions 2세대로 배포하려면 다음 명령어를 사용하세요.

gcloud functions deploy hello-http-function \
    --allow-unauthenticated \
    --entry-point HelloHttp.Function \
    --gen2 \
    --region $REGION \
    --runtime dotnet8 \
    --trigger-http

함수가 배포되면 다음 curl 명령어를 사용하여 함수를 호출할 수 있습니다.

SERVICE_URL=$(gcloud run services describe hello-http-function --platform managed --region $REGION --format 'value(status.url)')

curl $SERVICE_URL

6. CloudEvent 함수 - GCS

Google Cloud Storage (GCS) 이벤트에 응답하는 CloudEvent 함수를 만들고 배포합니다.

먼저 Cloud Storage 버킷을 만듭니다. 나중에 이벤트를 수신할 버킷입니다.

BUCKET_NAME="cloud-functions-bucket-${PROJECT_ID}"
gsutil mb -l us-central1 gs://${BUCKET_NAME}

gcf-event 템플릿을 사용하여 CloudEvent 함수를 만듭니다.

cd ..
mkdir HelloGcs
cd HelloGcs
dotnet new gcf-event

이렇게 하면 프로젝트와 CloudEvent 요청에 응답하는 Function.cs 파일이 생성됩니다. 또한 CloudEvent의 데이터를 StorageObjectData로 파싱합니다.

.csproj 파일에서 대상 프레임워크를 net8.0로 변경합니다.

<TargetFramework>net8.0</TargetFramework>

Cloud Run 함수를 Cloud Run에 직접 배포하려면 먼저 함수를 배포한 다음 함수의 트리거를 만듭니다.

gcloud beta run deploy hello-gcs-function \
      --source . \
      --function HelloGcs.Function \
      --region $REGION \
      --base-image dotnet8 \
      --no-allow-unauthenticated

이제 Cloud Run 함수의 트리거를 만듭니다.

BUCKET_REGION=$REGION

gcloud eventarc triggers create hello-gcs-function-trigger \
     --location=$REGION \
     --destination-run-service=hello-gcs-function \
    --destination-run-region=$BUCKET_REGION \
     --event-filters="type=google.cloud.storage.object.v1.finalized" \
     --event-filters="bucket=$BUCKET_NAME" \
     --service-account=$SERVICE_ACCOUNT_ADDRESS

Cloud Functions 2세대로 배포하려면 다음 명령어를 사용하여 trigger-eventtrigger-resource 플래그를 사용하여 함수를 배포할 수 있습니다.

gcloud functions deploy hello-gcs-function \
    --allow-unauthenticated \
    --entry-point HelloGcs.Function \
    --gen2 \
    --region $REGION \
    --runtime dotnet8 \
    --trigger-event google.storage.object.finalize \
    --trigger-resource ${BUCKET_NAME} \
    --service-account=$SERVICE_ACCOUNT_ADDRESS

몇 분 후 Cloud Console에 함수가 표시됩니다.

c28654d74bb31420.png

스토리지 버킷에 파일을 업로드하여 함수를 트리거합니다.

echo "Hello from Storage" > random.txt
gsutil cp random.txt gs://${BUCKET_NAME}

로그를 읽어 함수가 트리거되었는지 확인합니다.

Cloud Run 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud logging read "resource.labels.service_name=hello-gcs-function AND textPayload: Name" --format=json

2세대 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud functions logs read hello-gcs-function \
    --gen2 \
    --region us-central1

7. CloudEvent 함수 - Pub/Sub

Cloud Pub/Sub 이벤트에 응답하는 CloudEvent 함수를 만들고 배포합니다.

먼저 이벤트를 내보낼 Cloud Pub/Sub 주제를 만듭니다.

TOPIC_NAME=cloud-functions-topic
gcloud pubsub topics create ${TOPIC_NAME}

gcf-event 템플릿을 사용하여 CloudEvent 함수를 만듭니다.

cd ..
mkdir HelloPubSub
cd HelloPubSub
dotnet new gcf-event

이렇게 하면 프로젝트와 CloudEvent 요청에 응답하는 Function.cs 파일이 생성됩니다. 또한 기본적으로 CloudEvent의 데이터를 StorageObjectData로 파싱합니다.

.csproj 파일에서 대상 프레임워크를 net8.0로 변경합니다.

<TargetFramework>net8.0</TargetFramework>

StorageObjectDataMessagePublishedData로 변경하여 Pub/Sub 메시지를 파싱합니다. Google.Events.Protobuf.Cloud.Storage.V1Google.Events.Protobuf.Cloud.PubSub.V1로 변경합니다.

최종적으로 함수는 다음과 같이 표시됩니다.

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.PubSub.V1;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace HelloPubSub;

public class Function : ICloudEventFunction<MessagePublishedData>
{
    public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
    {
        var nameFromMessage = data.Message?.TextData;
        var name = string.IsNullOrEmpty(nameFromMessage) ? "world" : nameFromMessage;
        Console.WriteLine($"Hello {name}");
        return Task.CompletedTask;
    }
}

Cloud Run 함수를 Cloud Run에 직접 배포하려면 먼저 함수를 배포한 다음 함수의 트리거를 만듭니다.

gcloud beta run deploy hello-pubsub-function \
      --source . \
      --function HelloPubSub.Function \
      --region $REGION \
      --base-image dotnet8 \
      --no-allow-unauthenticated \
      --service-account=$SERVICE_ACCOUNT_ADDRESS

이제 Cloud Run 함수의 트리거를 만듭니다.

gcloud eventarc triggers create my-pubsub-trigger \
    --location=$REGION \
    --service-account=$SERVICE_ACCOUNT_ADDRESS \
    --destination-run-service=hello-pubsub-function \
    --destination-run-region=$REGION \
    --destination-run-path="/" \
    --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \
    --transport-topic=projects/$PROJECT_ID/topics/$TOPIC_NAME

Cloud Functions 2세대로 배포하려면 다음 명령어를 사용하여 trigger-topic 플래그를 사용하여 함수를 배포하면 됩니다.

gcloud functions deploy hello-pubsub-function \
    --allow-unauthenticated \
    --entry-point HelloPubSub.Function \
    --gen2 \
    --region us-central1 \
    --runtime dotnet8 \
    --trigger-topic ${TOPIC_NAME}

몇 분 후 Cloud Console에 함수가 표시됩니다.

3443808da7caf3bc.png

주제에 메시지를 게시하여 함수를 트리거합니다.

gcloud pubsub topics publish ${TOPIC_NAME} --message="World"

로그를 읽어 함수가 트리거되었는지 확인합니다.

Cloud Run 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud logging read "resource.labels.service_name=hello-pubsub-function AND textPayload: World" --format=json

2세대 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud functions logs read hello-pubsub-function \
    --gen2 \
    --region us-central1

8. CloudEvent 함수 - 유형이 지정되지 않음

CloudEvents를 실험 중이며 아직 커밋할 페이로드 데이터 모델이 없거나 함수가 모든 Cloud 이벤트를 처리할 수 있도록 하려면 유형이 지정되지 않은 CloudEvent 함수를 사용하면 됩니다.

gcf-untyped-event 템플릿을 사용하여 CloudEvent 함수를 만듭니다.

cd ..
mkdir HelloUntyped
cd HelloUntyped
dotnet new gcf-untyped-event

이렇게 하면 CloudEvent의 데이터를 파싱하지 않고도 CloudEvent 요청에 응답하는 프로젝트와 Function.cs 파일이 생성됩니다.

.csproj 파일에서 대상 프레임워크를 net8.0로 변경합니다.

<TargetFramework>net8.0</TargetFramework>

Cloud Run 함수를 Cloud Run에 직접 배포하려면 먼저 함수를 배포한 다음 함수의 트리거를 만듭니다.

gcloud beta run deploy hello-untyped-function \
      --source . \
      --function HelloUntyped.Function \
      --region $REGION \
      --base-image dotnet8 \
      --no-allow-unauthenticated

이제 Cloud Run 함수의 트리거를 만듭니다.

BUCKET_REGION=$REGION

gcloud eventarc triggers create hello-untyped-function-trigger \
     --location=$REGION \
     --destination-run-service=hello-untyped-function \
    --destination-run-region=$BUCKET_REGION \
     --event-filters="type=google.cloud.storage.object.v1.finalized" \
     --event-filters="bucket=$BUCKET_NAME" \
     --service-account=$SERVICE_ACCOUNT_ADDRESS

Cloud Functions 2세대로 배포하려면 다음 명령어를 사용하여 trigger-eventtrigger-resource 플래그를 사용하여 함수를 배포할 수 있습니다.

gcloud functions deploy hello-untyped-function \
    --allow-unauthenticated \
    --entry-point HelloUntyped.Function \
    --gen2 \
    --region us-central1 \
    --runtime dotnet8 \
    --trigger-event google.storage.object.finalize \
    --trigger-resource ${BUCKET_NAME}

이 함수는 파일이 스토리지 버킷에 업로드될 때 트리거됩니다.

몇 분 후 Cloud Console에 함수가 표시됩니다.

afe56530826787c6.png

스토리지 버킷에 파일을 업로드하여 함수를 트리거합니다.

echo "Hello from Storage" > random.txt
gsutil cp random.txt gs://${BUCKET_NAME}

로그를 읽어 함수가 트리거되었는지 확인합니다.

Cloud Run 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud logging read "resource.labels.service_name=hello-gcs-function AND textPayload: Name" --format=json

2세대 함수의 경우 다음 명령어를 실행할 수 있습니다.

gcloud functions logs read hello-untyped-function \
    --gen2 \
    --region us-central1

9. 축하합니다.

축하합니다. Codelab을 완료했습니다.

학습한 내용

  • .NET용 Functions 프레임워크
  • HTTP Cloud Functions를 작성하는 방법
  • Cloud Storage 이벤트에 응답하는 CloudEvent 함수를 작성하는 방법
  • Cloud Pub/Sub 이벤트에 응답하는 CloudEvent 함수를 작성하는 방법
  • 모든 유형의 이벤트에 응답하는 CloudEvent 함수를 작성하는 방법