Google Cloud Functions em C#

1. Introdução

O Google Cloud Run Functions é uma plataforma de computação sem servidor com base em eventos. Com o Cloud Run functions, você pode escrever seu código sem se preocupar com o provisionamento de recursos ou escalonamento para lidar com requisitos em mudança.

Há dois tipos de funções do Cloud Run:

  • As funções HTTP respondem a solicitações HTTP.
  • As funções de evento são acionadas por eventos, como uma mensagem publicada no Cloud Pub/Sub ou um arquivo enviado para o Cloud Storage.

efb3268e3b74ed4f.png

Neste codelab, você vai aprender a criar suas próprias funções do Cloud Run em C#. Mais especificamente, você vai implantar funções C# que respondem a HTTP e CloudEvents de várias origens do Google Cloud.

O que você vai aprender

  • Functions Framework para .NET.
  • Como escrever uma função HTTP.
  • Como escrever uma função acionada por evento que responde a eventos do Cloud Storage.
  • Como escrever uma função acionada por evento que responde a eventos do Cloud Pub/Sub.
  • Como escrever uma função acionada por evento que responde a qualquer tipo de evento.

2. Configuração e requisitos

Configuração de ambiente autoguiada

  1. Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • O Nome do projeto é o nome de exibição para os participantes do projeto. É uma string de caracteres não usada pelas APIs do Google É possível atualizar o local a qualquer momento.
  • O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser alterado após a definição. O console do Cloud gera automaticamente uma string exclusiva. Em geral, não importa o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, normalmente identificado como PROJECT_ID. Se você não gostar do ID gerado, crie outro aleatório. Se preferir, teste o seu e confira se ele está disponível. Ele não pode ser mudado após essa etapa e permanece durante o projeto.
  • Para sua informação, há um terceiro valor, um Número do projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
  1. Em seguida, ative o faturamento no console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não será muito cara, se tiver algum custo. Para encerrar os recursos e evitar cobranças além deste tutorial, exclua os recursos criados ou exclua o projeto inteiro. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

Inicie o Cloud Shell

Embora o Google Cloud e o Spanner possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.

No Console do Google Cloud, clique no ícone do Cloud Shell na barra de ferramentas superior à direita:

55efc1aaa7a4d3ad.png

O provisionamento e a conexão com o ambiente levarão apenas alguns instantes para serem concluídos: Quando o processamento for concluído, você verá algo como:

7ffe5cbb04455448.png

Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Neste codelab, todo o trabalho pode ser feito com um navegador. Você não precisa instalar nada.

3. Antes de começar

No Cloud Shell, execute o comando a seguir para ativar os serviços necessários:

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

Em seguida, defina sua região.

REGION=<YOUR_REGION>

Neste codelab, você vai criar uma conta de serviço com as permissões necessárias do Eventarc e o papel de invocador do Cloud Run para receber um evento do Cloud Storage e invocar a função do Cloud Run.

Primeiro, crie a conta de serviço.

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"

Em seguida, conceda o papel Receptor de eventos do Eventarc (roles/eventarc.eventReceiver) no projeto à conta de serviço associada ao gatilho do Eventarc para que ele possa receber eventos de provedores de eventos.

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

Em seguida, conceda à conta de serviço o papel de invocação do Cloud Run para que ela possa invocar a função.

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

4. Functions Framework para .NET

O Functions Framework para .NET é um framework de FaaS (função como serviço) de código aberto para escrever funções .NET portáteis. Ele foi criado pela equipe do Google Cloud Functions.

O Functions Framework permite gravar funções leves executadas em diferentes ambientes, inclusive:

  • Funções do Google Cloud Run
  • Sua máquina de desenvolvimento local
  • Cloud Run e Cloud Run no GKE
  • Ambientes baseados no Knative

Neste codelab, você vai usar o Functions Framework para .NET e os modelos dele para criar e implantar o Cloud Functions em C#.

No Cloud Shell, execute o seguinte comando para instalar modelos do Cloud Functions para dotnet:

dotnet new install Google.Cloud.Functions.Templates

Isso instala três modelos para dotnet. Cada modelo está disponível em C#, F# e VB, mas você só vai usar C# neste laboratório. Para verificar se os modelos foram instalados, execute:

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. Função HTTP

Você vai criar e implantar uma função HTTP que responde a solicitações HTTP.

Crie uma função HTTP usando o modelo gcf-http:

mkdir HelloHttp
cd HelloHttp
dotnet new gcf-http

Isso cria um projeto e um arquivo Function.cs que responde a solicitações HTTP.

Mude o framework de destino para net8.0 no arquivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implantar uma função do Cloud Run diretamente no Cloud Run, execute o seguinte comando:

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

Se você preferir implantar como um Cloud Functions de 2ª geração, use o seguinte comando:

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

Depois que a função for implantada, você poderá invocá-la usando o seguinte comando curl:

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

curl $SERVICE_URL

6. Função CloudEvent: GCS

Você vai criar e implantar uma função do CloudEvent que responde a eventos do Google Cloud Storage (GCS).

Primeiro, crie um bucket do Cloud Storage. Este é o bucket em que você vai detectar eventos mais tarde:

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

Crie uma função do CloudEvent usando o modelo gcf-event:

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

Isso cria um projeto e um arquivo Function.cs que responde a solicitações CloudEvent. Ele também analisa os dados de CloudEvent em StorageObjectData.

Mude o framework de destino para net8.0 no arquivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implantar uma função do Cloud Run diretamente no Cloud Run, primeiro implante a função e, em seguida, crie um acionador para ela.

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

Agora crie o acionador para a função do 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

Se você preferir implantar como um Cloud Functions de 2ª geração, use o comando a seguir para implantar a função usando as flags trigger-event e 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

Após alguns minutos, a função vai aparecer no Cloud Console:

c28654d74bb31420.png

Acione a função fazendo upload de um arquivo para o bucket de armazenamento:

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

Verifique se a função foi acionada lendo os registros:

Para uma função do Cloud Run, execute este comando:

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

Para uma função de 2ª geração, execute este comando:

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

7. Função CloudEvent: Pub/Sub

Você vai criar e implantar uma função do CloudEvent que responde a eventos do Cloud Pub/Sub.

Primeiro, crie um tópico do Cloud Pub/Sub que emitirá eventos:

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

Crie uma função do CloudEvent usando o modelo gcf-event:

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

Isso cria um projeto e um arquivo Function.cs que responde a solicitações CloudEvent. Ele também analisa os dados de CloudEvent em StorageObjectData por padrão.

Mude o framework de destino para net8.0 no arquivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Mude StorageObjectData para MessagePublishedData para analisar as mensagens do Pub/Sub. Mude Google.Events.Protobuf.Cloud.Storage.V1 para Google.Events.Protobuf.Cloud.PubSub.V1.

No final, a função vai ficar assim:

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

Para implantar uma função do Cloud Run diretamente no Cloud Run, primeiro implante a função e, em seguida, crie um acionador para ela.

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

Agora crie o acionador para a função do 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

Se você preferir implantar como um Cloud Functions de 2ª geração, use o comando a seguir para implantar a função usando a flag trigger-topic:

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

Após alguns minutos, a função vai aparecer no Cloud Console:

3443808da7caf3bc.png

Acione a função publicando uma mensagem no tópico:

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

Verifique se a função foi acionada lendo os registros.

Para uma função do Cloud Run, execute este comando:

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

Para uma função de 2ª geração, execute este comando:

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

8. Função do CloudEvent: sem tipo

Se você estiver testando o CloudEvents e ainda não tiver um modelo de dados de payload para o qual deseja se comprometer ou quiser que sua função processe qualquer evento do Cloud, use uma função do CloudEvent não tipada.

Crie uma função do CloudEvent usando o modelo gcf-untyped-event:

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

Isso cria um projeto e um arquivo Function.cs que responde a solicitações CloudEvent sem nenhuma tentativa de analisar os dados do CloudEvent.

Mude o framework de destino para net8.0 no arquivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implantar uma função do Cloud Run diretamente no Cloud Run, primeiro implante a função e, em seguida, crie um acionador para ela.

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

Agora crie o acionador para a função do 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

Se você preferir implantar como um Cloud Functions de 2ª geração, use o comando a seguir para implantar a função usando as flags trigger-event e 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}

A função será acionada quando um arquivo for enviado para um bucket de armazenamento.

Após alguns minutos, a função vai aparecer no Cloud Console:

afe56530826787c6.png

Acione a função fazendo upload de um arquivo para o bucket de armazenamento:

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

Verifique se a função foi acionada lendo os registros.

Para uma função do Cloud Run, execute este comando:

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

Para uma função de 2ª geração, execute este comando:

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

9. Parabéns!

Parabéns por concluir o codelab.

O que vimos

  • Functions Framework para .NET.
  • Como escrever uma função HTTP do Cloud.
  • Como escrever uma função do CloudEvent que responde a eventos do Cloud Storage.
  • Como escrever uma função do CloudEvent que responde a eventos do Cloud Pub/Sub.
  • Como escrever uma função do CloudEvent que responde a qualquer tipo de evento.