Google Cloud Functions w C#

1. Wprowadzenie

Funkcje Google Cloud Run to bezserwerowa platforma obliczeniowa oparta na zdarzeniach. Funkcje Cloud Run umożliwiają pisanie kodu bez konieczności zajmowania się alokacją zasobów czy skalowaniem w celu sprostania zmieniającym się wymaganiom.

Istnieją 2 rodzaje funkcji Cloud Run:

  • Funkcje HTTP odpowiadają na żądania HTTP.
  • Funkcje zdarzeń są wywoływane przez zdarzenia, takie jak opublikowanie wiadomości w Cloud Pub/Sub lub przesłanie pliku do Cloud Storage.

efb3268e3b74ed4f.png

W tym laboratorium programistycznym dowiesz się, jak tworzyć własne funkcje Cloud Run w C#. Dokładniej rzecz ujmując, wdrożysz funkcje C# reagujące na HTTP i CloudEvents z różnych źródeł w Google Cloud.

Czego się nauczysz

  • Platforma funkcji dla .NET.
  • Jak napisać funkcję HTTP.
  • Jak napisać funkcję sterowaną zdarzeniami, która reaguje na zdarzenia Cloud Storage.
  • Jak napisać funkcję wywoływaną przez zdarzenia odpowiadającą na zdarzenia Cloud Pub/Sub.
  • Jak napisać funkcję uruchamianą przez zdarzenie, która reaguje na dowolny typ zdarzenia.

2. Konfiguracja i wymagania

Konfiguracja środowiska w samodzielnym tempie

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, którego nie używają interfejsy API Google. Możesz ją zaktualizować w dowolnym momencie.
  • Identyfikator projektu musi być niepowtarzalny we wszystkich projektach Google Cloud i jest niezmienny (nie można go zmienić po jego ustawieniu). Cloud Console automatycznie generuje unikalny ciąg znaków. Zwykle nie ma znaczenia, jaki to ciąg. W większości laboratoriów z kodem musisz odwoływać się do identyfikatora projektu (zazwyczaj jest to PROJECT_ID). Jeśli nie podoba Ci się wygenerowany identyfikator, możesz wygenerować inny losowy. Możesz też spróbować użyć własnego konta i sprawdzić, czy jest ono dostępne. Po tym kroku nie można go zmienić. Pozostanie ona niezmieniona przez cały czas trwania projektu.
  • Informacyjnie: istnieje jeszcze 3 wartość, numer projektu, którego używają niektóre interfejsy API. Więcej informacji o wszystkich 3 wartościach znajdziesz w dokumentacji.
  1. Następnie musisz włączyć rozliczenia w konsoli Cloud, aby korzystać z zasobów i interfejsów API Cloud. Przejście przez ten moduł Codelab nie powinno wiązać się z wielkimi kosztami, jeśli w ogóle z nimi będzie. Aby wyłączyć zasoby, aby nie generować opłat po zakończeniu samouczka, możesz usunąć utworzone zasoby lub cały projekt. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

Uruchomienie Cloud Shell

Google Cloud można obsługiwać zdalnie z laptopa, ale w tym ćwiczeniu będziesz używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.

W konsoli Google Cloud kliknij ikonę Cloud Shell na pasku narzędzi w prawym górnym rogu:

55efc1aaa7a4d3ad.png

Uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil. Po jego zakończeniu powinno wyświetlić się coś takiego:

7ffe5cbb04455448.png

Ta maszyna wirtualna zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie poprawia wydajność sieci i uwierzytelnianie. Wszystkie zadania w tym CodeLab możesz wykonać w przeglądarce. Nie musisz niczego instalować.

3. Zanim zaczniesz

Aby włączyć wymagane usługi, w Cloud Shell uruchom to polecenie:

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

Następnie wybierz region.

REGION=<YOUR_REGION>

W tym ćwiczeniu utworzysz konto usługi z wymaganymi uprawnieniami EventArc i rolą wywołującego Cloud Run, aby odbierać zdarzenia z Cloud Storage i wywoływać funkcję Cloud Run.

Najpierw utwórz konto usługi.

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"

Następnie przypisz do konta usługi powiązanego z aktywatorem Eventarc rolę Odbiorca zdarzenia Eventarc (roles/eventarc.eventReceiver) w projekcie, aby aktywator mógł odbierać zdarzenia od dostawców zdarzeń.

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

Następnie przypisz do konta usługi rolę wywołującego Cloud Run, aby mogło wywołać funkcję.

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

4. Functions Framework for .NET

Platforma funkcji dla .NET to platforma typu open source FaaS (funkcje jako usługa) do pisania przenośnych funkcji .NET, którą udostępnia zespół Google Cloud Functions.

Framework funkcji umożliwia tworzenie lekkich funkcji, które działają w wielu różnych środowiskach, m.in.:

  • Funkcje Google Cloud Run
  • Twój lokalny komputer do programowania
  • Cloud Run i Cloud Run w GKE
  • Środowiska oparte na Knative

W tym laboratorium kodu użyjesz funkcji Functions Framework for .NET i jej szablonów do tworzenia i wdrażania funkcji Cloud Functions w C#.

Aby zainstalować szablony Cloud Functions dla dotnet, uruchom w Cloud Shell to polecenie:

dotnet new install Google.Cloud.Functions.Templates

Spowoduje to zainstalowanie 3 szablonów dla dotnet. Każdy szablon jest dostępny w językach C#, F# i VB (w tym module użyjesz tylko języka C#). Aby sprawdzić, czy szablony zostały zainstalowane, uruchom:

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. Funkcja HTTP

Utworzysz i wdrożysz funkcję HTTP, która będzie odpowiadać na żądania HTTP.

Utwórz funkcję HTTP za pomocą szablonu gcf-http:

mkdir HelloHttp
cd HelloHttp
dotnet new gcf-http

Spowoduje to utworzenie projektu i pliku Function.cs, który będzie odpowiadać na żądania HTTP.

W pliku .csproj zmień docelową wersję na net8.0:

<TargetFramework>net8.0</TargetFramework>

Aby wdrożyć funkcję Cloud Run bezpośrednio w Cloud Run, uruchom to polecenie:

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

Jeśli wolisz wdrożyć funkcję jako funkcję Cloud Functions 2 generacji, użyj tego polecenia:

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

Po wdrożeniu funkcji możesz ją wywołać za pomocą tego polecenia curl:

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

curl $SERVICE_URL

6. CloudEvent Function – GCS

Utworzysz i wdrożesz funkcję CloudEvent, która będzie reagować na zdarzenia Google Cloud Storage (GCS).

Najpierw utwórz zasobnik Cloud Storage. To jest zasobnik, z którego później będziesz nasłuchiwać zdarzeń:

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

Utwórz funkcję CloudEvent za pomocą szablonu gcf-event:

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

Spowoduje to utworzenie projektu i pliku Function.cs, który będzie odpowiadał na żądania CloudEvent. Rozkłada też dane z elementu CloudEvent na elementy StorageObjectData.

W pliku .csproj zmień docelową wersję na net8.0:

<TargetFramework>net8.0</TargetFramework>

Aby wdrożyć funkcję Cloud Run bezpośrednio w Cloud Run, najpierw wdróż funkcję, a następnie utwórz dla niej odpowiedni uchwyt.

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

Teraz utwórz regułę dla funkcji 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

Jeśli wolisz wdrażać funkcję jako funkcję 2 generacji, możesz użyć tego polecenia do wdrożenia funkcji za pomocą flag trigger-event i 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

Po kilku minutach funkcja powinna być widoczna w Cloud Console:

c28654d74bb31420.png

Aktywuj funkcję, przesyłając plik do zasobnika na dane:

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

Sprawdź, czy funkcja została wywołana, czytając dzienniki:

W przypadku funkcji Cloud Run możesz uruchomić to polecenie:

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

W przypadku funkcji 2 generacji możesz uruchomić to polecenie:

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

7. CloudEvent Function – Pub/Sub

Utworzysz i wdrożysz funkcję CloudEvent, która będzie reagować na zdarzenia Cloud Pub/Sub.

Najpierw utwórz temat Cloud Pub/Sub, który będzie emitować zdarzenia:

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

Utwórz funkcję CloudEvent za pomocą szablonu gcf-event:

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

Spowoduje to utworzenie projektu i pliku Function.cs, który będzie odpowiadał na żądania CloudEvent. Domyślnie parsuje on też dane z elementu CloudEvent do elementu StorageObjectData.

W pliku .csproj zmień docelową wersję na net8.0:

<TargetFramework>net8.0</TargetFramework>

Zmień StorageObjectData na MessagePublishedData, aby przeanalizować wiadomości Pub/Sub. Zmień Google.Events.Protobuf.Cloud.Storage.V1 na Google.Events.Protobuf.Cloud.PubSub.V1.

Ostatecznie funkcja powinna wyglądać tak:

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;
    }
}

Aby wdrożyć funkcję Cloud Run bezpośrednio w Cloud Run, najpierw wdróż funkcję, a następnie utwórz dla niej odpowiedni uchwyt.

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

Teraz utwórz element uruchamiający funkcję 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

Jeśli wolisz wdrożyć funkcję jako funkcję Cloud Functions 2 generacji, możesz użyć tego polecenia do wdrożenia funkcji za pomocą parametru trigger-topic:

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

Po kilku minutach funkcja powinna być widoczna w Cloud Console:

3443808da7caf3bc.png

Aby wywołać funkcję, opublikuj wiadomość w temacie:

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

Sprawdź, czy funkcja została wywołana, czytając dzienniki.

W przypadku funkcji Cloud Run możesz uruchomić to polecenie:

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

W przypadku funkcji 2 generacji możesz uruchomić to polecenie:

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

8. Funkcja CloudEvent – bez typu

Jeśli eksperymentujesz z CloudEvents i nie masz jeszcze modelu danych ładunku, którego chcesz użyć, lub chcesz, aby Twoja funkcja mogła obsługiwać dowolne zdarzenie CloudEvent, możesz użyć nietypowanej funkcji CloudEvent.

Utwórz funkcję CloudEvent za pomocą szablonu gcf-untyped-event:

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

Spowoduje to utworzenie projektu i pliku Function.cs, który będzie odpowiadać na żądania CloudEvent bez próby zanalizowania danych CloudEvent.

W pliku .csproj zmień docelową wersję na net8.0:

<TargetFramework>net8.0</TargetFramework>

Aby wdrożyć funkcję Cloud Run bezpośrednio w Cloud Run, najpierw wdróż funkcję, a następnie utwórz dla niej odpowiedni uchwyt.

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

Teraz utwórz regułę dla funkcji 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

Jeśli wolisz wdrażać funkcję jako funkcję Cloud Functions 2 generacji, możesz użyć tego polecenia, aby wdrożyć funkcję za pomocą flag trigger-event i 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}

Funkcja zostanie uruchomiona, gdy plik zostanie przesłany do zasobnika na dane.

Po kilku minutach funkcja powinna być widoczna w Cloud Console:

afe56530826787c6.png

Aktywuj funkcję, przesyłając plik do zasobnika na dane:

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

Sprawdź, czy funkcja została wywołana, czytając dzienniki.

W przypadku funkcji Cloud Run możesz uruchomić to polecenie:

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

W przypadku funkcji 2 generacji możesz uruchomić to polecenie:

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

9. Gratulacje!

Gratulujemy ukończenia ćwiczenia.

Omówione zagadnienia

  • Platforma funkcji dla .NET.
  • Jak napisać funkcję HTTP w Cloud Functions
  • Jak napisać funkcję CloudEvent, która będzie reagować na zdarzenia Cloud Storage.
  • Jak napisać funkcję CloudEvent odpowiadającą na zdarzenia Cloud Pub/Sub.
  • Jak napisać funkcję CloudEvent, która reaguje na dowolny typ zdarzenia.