Google Cloud Functions ב-C#

1. מבוא

פונקציות של Google Cloud Run הן פלטפורמת מחשוב ללא שרת (serverless) מבוססת-אירועים. הפונקציות של Cloud Run מאפשרות לכתוב את הקוד בלי לדאוג לגבי הקצאת משאבים או התאמה לעומס (scaling) כדי להתמודד עם הדרישות המשתנות.

יש שני סוגים של פונקציות Cloud Run:

  • פונקציות HTTP מגיבות לבקשות HTTP.
  • פונקציות של אירועים מופעלות על ידי אירועים, כמו הודעה שמתפרסמת ב-Cloud Pub/Sub או קובץ שמעלים ל-Cloud Storage.

efb3268e3b74ed4f.png

ה-Codelab הזה ידריך אותך איך ליצור פונקציות משלכם ב-Cloud Run ב-C#. באופן ספציפי יותר, תפרסו פונקציות C# שמגיבות ל-HTTP ול-CloudEvents ממקורות שונים ב-Google Cloud.

מה תלמדו

  • Functions Framework for ‎.NET.
  • איך כותבים פונקציית HTTP.
  • איך לכתוב פונקציה שמופעלת על ידי אירוע בתגובה לאירועים ב-Cloud Storage.
  • איך לכתוב פונקציה שמופעלת על ידי אירוע בתגובה לאירועי Cloud Pub/Sub.
  • איך לכתוב פונקציה שמופעלת על ידי אירוע בתגובה לכל סוג של אירוע.

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים למסוף Google Cloud ויוצרים פרויקט חדש או עושים שימוש חוזר בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או חשבון Google Workspace, עליכם ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Project name הוא השם המוצג של המשתתפים בפרויקט. זו מחרוזת תווים שלא משמשת את Google APIs. אפשר לעדכן את המיקום הזה בכל שלב.
  • Project ID חייב להיות ייחודי בכל הפרויקטים ב-Google Cloud ואי אפשר לשנות אותו (אי אפשר לשנות אותו אחרי שמגדירים אותו). מסוף Cloud יוצר מחרוזת ייחודית באופן אוטומטי; בדרך כלל לא מעניין אותך מה זה. ברוב ה-Codelabs תצטרכו להפנות אל מזהה הפרויקט (בדרך כלל הוא מזוהה כ-PROJECT_ID). אם המזהה שנוצר לא מוצא חן בעיניך, יש לך אפשרות ליצור מזהה אקראי אחר. לחלופין, אפשר לנסות תבנית משלך ולבדוק אם היא זמינה. לא ניתן לשנות את השם אחרי השלב הזה, והוא יישאר למשך כל תקופת הפרויקט.
  • לידיעתך, יש ערך שלישי, מספר פרויקט, שמשתמשים בו בחלק מממשקי ה-API. מידע נוסף על כל שלושת הערכים האלה זמין במסמכי התיעוד.
  1. בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים או בממשקי API של Cloud. מעבר ב-Codelab הזה לא אמור לעלות הרבה, אם בכלל. כדי להשבית את המשאבים ולמנוע חיובים אחרי סיום המדריך, אפשר למחוק את המשאבים שיצרתם או למחוק את הפרויקט כולו. משתמשים חדשים ב-Google Cloud זכאים להצטרף לתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.

הפעלת Cloud Shell

אומנם אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-Codelab הזה משתמשים ב-Google Cloud Shell, סביבת שורת הפקודה שפועלת ב-Cloud.

במסוף Google Cloud, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:

55efc1aaa7a4d3ad.png

נדרשים רק כמה דקות כדי להקצות את הסביבה ולהתחבר אליה. בסיום, אמור להופיע משהו כזה:

7ffe5cbb04455448.png

למכונה הווירטואלית הזו נטען כל כלי הפיתוח הדרושים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. כל העבודה ב-Codelab הזה יכולה להתבצע בתוך דפדפן. אתה לא צריך להתקין שום דבר.

3. לפני שמתחילים

Inside 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 את התפקיד 'מקבל אירועים' ב-Eventarc (roles/eventarc.eventReceiver) בפרויקט, כדי שהטריגר יוכל לקבל אירועים מספקי אירועים.

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

לאחר מכן מקצים לחשבון השירות את התפקיד Cloud Run Invoker כדי שיוכל להפעיל את הפונקציה.

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

4. Functions Framework ל- .NET

Functions Framework for ‎.NET היא מסגרת FaaS (Function as a Service) בקוד פתוח לכתיבה של פונקציות ‎.NET ניידות – שפותחה על ידי צוות Google Cloud Functions.

באמצעות Functions Framework אפשר לכתוב פונקציות קלילות שפועלות בסביבות רבות ושונות, כולל:

  • פונקציות של Google Cloud Run
  • המכונה המקומית לפיתוח
  • Cloud Run ו-Cloud Run ב-GKE
  • סביבות מבוססות-Knative

ב-Codelab הזה משתמשים ב-Functions Framework ל- .NET ובתבניות שלו כדי ליצור ולפרוס את Cloud Functions ב-C#.

ב-Cloud Shell, מריצים את הפקודה הבאה כדי להתקין תבניות של Cloud Functions עבור dotnet:

dotnet new install Google.Cloud.Functions.Templates

הפעולה הזו מתקינה 3 תבניות של dotnet. כל תבנית זמינה ב-C#, ב-F# וב-VB (אבל בשיעור ה-Lab הזה תשתמשו רק ב-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.

יוצרים פונקציית HTTP באמצעות התבנית gcf-http:

mkdir HelloHttp
cd HelloHttp
dotnet new gcf-http

ייווצר פרויקט וקובץ Function.cs שמגיבים לבקשות HTTP.

משנים את מסגרת היעד ל-net8.0 בקובץ .csproj:

<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 מדור שני, משתמשים בפקודה הבאה:

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_NAME="cloud-functions-bucket-${PROJECT_ID}"
gsutil mb -l us-central1 gs://${BUCKET_NAME}

יוצרים פונקציה של CloudEvent באמצעות התבנית gcf-event:

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

ייווצר פרויקט וקובץ Function.cs שמגיבים לבקשות של CloudEvent. הוא גם מנתח את הנתונים של CloudEvent ל-StorageObjectData.

שינוי של מסגרת היעד ל-net8.0 בקובץ .csproj:

<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 מדור שני, אתם יכולים להשתמש בפקודה הבאה כדי לפרוס את הפונקציה באמצעות הדגלים trigger-event ו-trigger-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

כדי להפעיל פונקציה מדור שני, אפשר להריץ את הפקודה הבאה:

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

7. פונקציית CloudEvent – Pub/Sub

תלמדו ליצור ולפרוס פונקציית CloudEvent שתגיב לאירועים ב-Cloud Pub/Sub.

קודם יוצרים נושא ב-Cloud Pub/Sub שיפיק אירועים:

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

יוצרים פונקציה של CloudEvent באמצעות התבנית gcf-event:

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

ייווצר פרויקט וקובץ Function.cs שמגיבים לבקשות של CloudEvent. הוא גם מנתח את הנתונים של CloudEvent ל-StorageObjectData כברירת מחדל.

שינוי של מסגרת היעד ל-net8.0 בקובץ .csproj:

<TargetFramework>net8.0</TargetFramework>

כדי לנתח הודעות Pub/Sub, משנים את הערך של StorageObjectData ל-MessagePublishedData. משנים את 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 מדור שני, אתם יכולים להשתמש בפקודה הבאה כדי לפרוס את הפונקציה באמצעות הדגל 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

בשביל פונקציה מדור שני, מריצים את הפקודה הבאה:

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

8. פונקציית CloudEvent – לא מועתקת

אם אתם מתנסים ב-CloudEvents ועדיין אין לכם מודל נתונים של מטען ייעודי (payload) שאתם רוצים להתחייב אליו, או שאתם רוצים שהפונקציה תוכל לטפל בכל אירוע ב-Cloud, תוכלו להשתמש בפונקציית CloudEvent לא שהוקלדה.

יוצרים פונקציית CloudEvent באמצעות התבנית gcf-untyped-event:

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

הפעולה הזו יוצרת פרויקט וקובץ Function.cs שמגיבים לבקשות של CloudEvent בלי לנסות לנתח את הנתונים של CloudEvent.

משנים את מסגרת היעד ל-net8.0 בקובץ .csproj:

<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 מדור שני, אתם יכולים להשתמש בפקודה הבאה כדי לפרוס את הפונקציה באמצעות הדגלים trigger-event ו-trigger-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

כדי להפעיל פונקציה מדור שני, אפשר להריץ את הפקודה הבאה:

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

9. מעולה!

כל הכבוד על השלמת ה-Codelab.

מה עסקנו בו

  • Functions Framework של NET.
  • איך כותבים פונקציית HTTP של Cloud Functions.
  • איך לכתוב פונקציה של CloudEvent שמגיבה לאירועים של Cloud Storage.
  • איך לכתוב פונקציה של CloudEvent שמגיבה לאירועי Cloud Pub/Sub.
  • איך כותבים פונקציית CloudEvent שמגיבה לכל סוג של אירוע.