Google Cloud Functions en C#

1. Introducción

Funciones de Google Cloud Run es una plataforma de procesamiento sin servidores controlada por eventos. Las funciones de Cloud Run te permiten escribir tu código sin preocuparte por aprovisionar recursos o escalar para controlar los requisitos cambiantes.

Existen dos tipos de funciones de Cloud Run:

  • Las funciones de HTTP responden a las solicitudes HTTP.
  • Las funciones de eventos se activan mediante eventos, como la publicación de un mensaje en Cloud Pub/Sub o la carga de un archivo en Cloud Storage.

efb3268e3b74ed4f.png

En este codelab, aprenderás a crear tus propias funciones de Cloud Run en C#. Más específicamente, implementarás funciones de C# que respondan a HTTP y CloudEvents desde varias fuentes de Google Cloud.

Qué aprenderás

  • Functions Framework para .NET
  • Cómo escribir una función de HTTP
  • Cómo escribir una función activada por eventos que responda a eventos de Cloud Storage
  • Cómo escribir una función activada por eventos que responda a eventos de Cloud Pub/Sub
  • Cómo escribir una función activada por eventos que responda a cualquier tipo de evento

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla en cualquier momento.
  • El ID del proyecto debe ser único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID del proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se mantendrá durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no debería costar mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar todo el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de USD 300.

Inicia Cloud Shell

Si bien Google Cloud y Spanner se pueden operar de manera remota desde tu laptop, en este codelab usarás Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.

En Google Cloud Console, haz clic en el ícono de Cloud Shell en la barra de herramientas en la parte superior derecha:

55efc1aaa7a4d3ad.png

El aprovisionamiento y la conexión al entorno deberían tomar solo unos minutos. Cuando termine el proceso, debería ver algo como lo siguiente:

7ffe5cbb04455448.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Todo tu trabajo en este codelab se puede hacer en un navegador. No es necesario que instales nada.

3. Antes de comenzar

En Cloud Shell, ejecuta el siguiente comando para habilitar los servicios necesarios:

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

A continuación, configura tu región.

REGION=<YOUR_REGION>

En este codelab, crearás una cuenta de servicio con los permisos de Eventarc necesarios y el rol de invocador de Cloud Run para recibir un evento de Cloud Storage y, luego, invocar la función de Cloud Run.

Primero, crea la cuenta de servicio.

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"

A continuación, otorga el rol de receptor de eventos de Eventarc (roles/eventarc.eventReceiver) en el proyecto a la cuenta de servicio asociada con tu activador de Eventarc para que el activador pueda recibir eventos de los proveedores de eventos.

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

Luego, otorga a la cuenta de servicio el rol de invocador de Cloud Run para que pueda invocar la función.

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

4. Functions Framework para .NET

Functions Framework para .NET es un framework de FaaS (función como servicio) de código abierto para escribir funciones de .NET portátiles, creado por el equipo de Google Cloud Functions.

Functions Framework te permite escribir funciones ligeras que se ejecutan en muchos entornos diferentes, incluidos los siguientes:

  • Funciones de Google Cloud Run
  • Tu máquina de desarrollo local
  • Cloud Run y Cloud Run en GKE
  • Entornos basados en Knative

En este codelab, usarás Functions Framework para .NET y sus plantillas para crear e implementar Cloud Functions en C#.

En Cloud Shell, ejecuta el siguiente comando para instalar plantillas de Cloud Functions para dotnet:

dotnet new install Google.Cloud.Functions.Templates

Esto instala 3 plantillas para dotnet. Cada plantilla está disponible en C#, F# y VB (pero solo usarás C# en este lab). Para verificar que las plantillas estén instaladas, ejecuta lo siguiente:

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. Función HTTP

Crearás e implementarás una función de HTTP que responda a las solicitudes HTTP.

Crea una función de HTTP con la plantilla gcf-http:

mkdir HelloHttp
cd HelloHttp
dotnet new gcf-http

Esto crea un proyecto y un archivo Function.cs que responde a las solicitudes HTTP.

Cambia el framework de destino a net8.0 en el archivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implementar una función de Cloud Run directamente en Cloud Run, ejecuta el siguiente comando:

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

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., usa el siguiente comando:

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

Una vez que se implemente la función, puedes invocarla con el siguiente comando curl:

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

curl $SERVICE_URL

6. Función de CloudEvent: GCS

Crearás e implementarás una función de CloudEvent que responda a eventos de Google Cloud Storage (GCS).

Primero, crea un bucket de Cloud Storage. Este es el bucket del que escucharás los eventos más adelante:

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

Crea una función de CloudEvent con la plantilla gcf-event:

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

Esto crea un proyecto y un archivo Function.cs que responde a las solicitudes CloudEvent. También analiza los datos de CloudEvent en StorageObjectData.

Cambia el framework de destino a net8.0 en el archivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implementar una función de Cloud Run directamente en Cloud Run, primero debes implementarla y, luego, crear un activador para ella.

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

Ahora, crea el activador para la función de 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

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., puedes usar el siguiente comando para implementarla con las marcas trigger-event y 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

Después de unos minutos, la función debería aparecer en la consola de Cloud:

c28654d74bb31420.png

Sube un archivo al bucket de almacenamiento para activar la función:

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

Para verificar que se activó la función, lee los registros:

Para una función de Cloud Run, puedes ejecutar este comando:

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

Para una función de 2ª gen., puedes ejecutar este comando:

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

7. Función de CloudEvent: Pub/Sub

Crearás e implementarás una función de CloudEvent que responda a eventos de Cloud Pub/Sub.

Primero, crea un tema de Cloud Pub/Sub que emitirá eventos:

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

Crea una función de CloudEvent con la plantilla gcf-event:

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

Esto crea un proyecto y un archivo Function.cs que responde a las solicitudes CloudEvent. También analiza los datos de CloudEvent en StorageObjectData de forma predeterminada.

Cambia el framework de destino a net8.0 en el archivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Cambia StorageObjectData a MessagePublishedData para analizar los mensajes de Pub/Sub. Cambia Google.Events.Protobuf.Cloud.Storage.V1 a Google.Events.Protobuf.Cloud.PubSub.V1.

Al final, tu función debería verse de la siguiente manera:

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 implementar una función de Cloud Run directamente en Cloud Run, primero debes implementarla y, luego, crear un activador para ella.

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

Ahora, crea el activador para la función de 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

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., puedes usar el siguiente comando para implementarla con la marca trigger-topic:

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

Después de unos minutos, la función debería aparecer en la consola de Cloud:

3443808da7caf3bc.png

Publica un mensaje en el tema para activar la función:

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

Lee los registros para verificar que se haya activado la función.

Para una función de Cloud Run, puedes ejecutar este comando:

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

Para una función de 2ª gen., puedes ejecutar este comando:

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

8. Función de CloudEvent: sin tipo

Si estás experimentando con CloudEvents y aún no tienes un modelo de datos de carga útil con el que deseas confirmar o si deseas que tu función pueda controlar cualquier evento de Cloud, puedes usar una función de CloudEvent sin tipo.

Crea una función de CloudEvent con la plantilla gcf-untyped-event:

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

Esto crea un proyecto y un archivo Function.cs que responde a las solicitudes CloudEvent sin intentar analizar los datos de CloudEvent.

Cambia el framework de destino a net8.0 en el archivo .csproj:

<TargetFramework>net8.0</TargetFramework>

Para implementar una función de Cloud Run directamente en Cloud Run, primero debes implementarla y, luego, crear un activador para ella.

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

Ahora, crea el activador para la función de 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

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., puedes usar el siguiente comando para implementarla con las marcas trigger-event y 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}

La función se activará cuando se suba un archivo a un bucket de almacenamiento.

Después de un par de minutos, la función debería aparecer en la consola de Cloud:

afe56530826787c6.png

Sube un archivo al bucket de almacenamiento para activar la función:

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

Lee los registros para verificar que se haya activado la función.

Para una función de Cloud Run, puedes ejecutar este comando:

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

Para una función de 2ª gen., puedes ejecutar este comando:

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

9. ¡Felicitaciones!

Felicitaciones por completar el codelab.

Temas abordados

  • Functions Framework para .NET
  • Cómo escribir una función de HTTP de Cloud Functions
  • Cómo escribir una función de CloudEvent que responda a eventos de Cloud Storage
  • Cómo escribir una función de CloudEvent que responda a eventos de Cloud Pub/Sub
  • Cómo escribir una función de CloudEvent que responda a cualquier tipo de evento