C# 中的 Google Cloud Functions

1. 簡介

Google Cloud Run 函式是事件導向的無伺服器運算平台,您可以使用 Cloud Run 函式編寫程式碼,不必擔心佈建資源或調整資源調度,以因應變更的需求。

Cloud Run 函式分為兩種類型:

  • HTTP 函式會回應 HTTP 要求。
  • 事件函式會在事件觸發時執行,例如訊息發布至 Cloud Pub/Sub 或檔案上傳至 Cloud Storage

efb3268e3b74ed4f.png

本程式碼研究室將逐步引導您使用 C# 建立自己的 Cloud Run 函式。具體來說,您將部署 C# 函式,回應來自各種 Google Cloud 來源的 HTTP 和 CloudEvents。

課程內容

  • 適用於 .NET 的函式架構。
  • 如何編寫 HTTP 函式。
  • 如何編寫回應 Cloud Storage 事件的事件觸發函式。
  • 如何編寫回應 Cloud Pub/Sub 事件的事件觸發函式。
  • 如何編寫可回應任何類型事件的事件觸發函式。

2. 設定和需求

自助式環境設定

  1. 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請務必建立帳戶

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「Project name」是這個專案參與者的顯示名稱。這是 Google API 不會使用的字元字串。您隨時可以更新。
  • 專案 ID 在所有 Google Cloud 專案中不得重複,且無法變更 (設定後即無法變更)。Cloud 控制台會自動產生一個專屬字串,您通常不需要特別留意。在大多數程式碼研究室中,您都需要參照專案 ID (通常會標示為 PROJECT_ID)。如果您不喜歡系統產生的 ID,可以隨機產生另一組 ID。或者,您也可以自行嘗試,看看是否可用。這項設定在這個步驟後即無法變更,並會在專案期間維持不變。
  • 提醒您,有些 API 會使用第三個值,也就是「專案編號」。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用帳單功能,才能使用 Cloud 資源/API。執行本程式碼研究室時,費用應該不會太高,甚至可能不收費。如要關閉資源,避免產生教學課程以外的費用,您可以刪除建立的資源,或刪除整個專案。Google Cloud 新使用者可享有 $300 美元的免費試用期

啟動 Cloud Shell

雖然 Google Cloud 可透過筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是在雲端運作的指令列環境。

Google Cloud 控制台中,按一下右上方工具列的 Cloud Shell 圖示:

55efc1aaa7a4d3ad.png

佈建並連線至環境的作業需要一些時間才能完成。完成後,您應該會看到如下的畫面:

7ffe5cbb04455448.png

這個虛擬機器會載入您需要的所有開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提升網路效能和驗證功能。您可以在瀏覽器中完成本程式碼研究室的所有工作。您不需要安裝任何東西。

3. 事前準備

在 Cloud Shell 中執行下列指令,啟用必要服務:

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

接著,設定區域。

REGION=<YOUR_REGION>

在本程式碼研究室中,您將建立服務帳戶,並授予必要的 Eventarc 權限和 Cloud Run 叫用者角色,以便接收 Cloud Storage 事件並叫用 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 事件接收者角色 (roles/eventarc.eventReceiver) 授予與 Eventarc 觸發條件相關聯的服務帳戶,讓觸發條件能夠接收事件供應者的事件。

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 Framework for .NET 是 Google Cloud Functions 團隊推出的開放原始碼 FaaS (函式即服務) 架構,可用於編寫可移植的 .NET 函式。

Functions Framework 可讓您編寫簡易函式,並在許多不同環境中執行,包括:

  • Google Cloud Run 函式
  • 您的本機開發電腦
  • Cloud Run 和 Cloud Run on GKE
  • 以 Knative 為基礎的環境

在本程式碼研究室中,您將使用 .NET 專用 Functions Framework 和其範本,以 C# 語言建立及部署 Cloud Functions。

在 Cloud Shell 中執行下列指令,為 dotnet 安裝 Cloud 函式範本:

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

這會建立專案和 Function.cs 檔案,用於回應 HTTP 要求。

.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

您將建立及部署 CloudEvent 函式,以回應 Google Cloud Storage (GCS) 事件。

首先,請建立 Cloud Storage 值區。這是您稍後要監聽事件的 bucket:

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

這會建立專案和 Function.cs 檔案,以回應 CloudEvent 要求。並將 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 控制台應會顯示該函式:

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

這會建立專案和 Function.cs 檔案,以回應 CloudEvent 要求。預設也會將 CloudEvent 的資料剖析為 StorageObjectData

.csproj 檔案中將目標架構變更為 net8.0

<TargetFramework>net8.0</TargetFramework>

StorageObjectData 變更為 MessagePublishedData,即可剖析 Pub/Sub 訊息。將 Google.Events.Protobuf.Cloud.Storage.V1 變更為 Google.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 控制台應會顯示該函式:

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 函式 - 未指定類型

如果您正在測試 CloudEvent,但尚未有要提交的酬載資料模型,或是希望函式能夠處理任何 Cloud Event,可以使用未指定類型的 CloudEvent 函式。

使用 gcf-untyped-event 範本建立 CloudEvent 函式:

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

這會建立專案和 Function.cs 檔案,以回應 CloudEvent 要求,但不會嘗試剖析 CloudEvent 的資料。

.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 控制台應會顯示該函式:

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. 恭喜!

恭喜您完成程式碼研究室!

涵蓋內容

  • 適用於 .NET 的函式架構。
  • 如何編寫 HTTP Cloud 函式。
  • 如何編寫可回應 Cloud Storage 事件的 CloudEvent 函式。
  • 如何編寫回應 Cloud Pub/Sub 事件的 CloudEvent 函式。
  • 如何編寫可回應任何類型事件的 CloudEvent 函式。