Build an event-driven orchestration with Eventarc and Workflows

1. Introducción

cb762f29e9183a3f.png 1c05e3d0c2bd2b45.png a03f943ca09ac4c.png

Eventarc facilita la conexión de los servicios de Cloud Run con eventos de una variedad de fuentes. Te permite crear arquitecturas controladas por eventos en las que los microservicios están vinculados y distribuidos de manera flexible. Se encarga de la transferencia de eventos, la entrega, la seguridad, la autorización y el manejo de errores por ti.

Workflows es una plataforma de organización completamente administrada que ejecuta servicios en el orden que tú defines: un flujo de trabajo. Estos flujos de trabajo pueden combinar servicios alojados en Cloud Run o Cloud Functions, servicios de Google Cloud como Cloud Vision AI y BigQuery, y cualquier API basada en HTTP.

En este codelab, compilarás una organización de microservicios basada en eventos para procesar imágenes. Usarás Workflows para organizar el orden, las entradas y las salidas de 4 funciones de procesamiento de imágenes de Cloud Functions. Luego, permitirás que la organización responda a los eventos de Cloud Storage con acoplamiento bajo con Eventarc.

Al final, terminarás con una arquitectura sin servidores flexible pero estructurada para procesar imágenes.

e372ceed8c26c5fb.png

Qué aprenderás

  • Descripción general de Eventarc y Workflows
  • Cómo implementar servicios de Cloud Functions
  • Cómo organizar servicios con Workflows
  • Cómo hacer que los flujos de trabajo respondan a los eventos de Cloud Storage con Eventarc

2. Configuración y requisitos

Cómo configurar el entorno a tu propio ritmo

  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 es ú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 te importa qué es. En la mayoría de los codelabs, deberás hacer referencia al ID del proyecto (por lo general, se identifica como PROJECT_ID). Si no te gusta el ID generado, puedes generar otro aleatorio. También puedes probar el tuyo propio y ver si está disponible. No se puede cambiar después de este paso y se mantendrá mientras dure el proyecto.
  • Para tu información, 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 te facture 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.

Configura gcloud

En Cloud Shell, configura el ID del proyecto y la región en la que quieres implementar la aplicación. Guárdalos como variables PROJECT_ID y REGION. Consulta las ubicaciones de Cloud Functions para conocer las regiones disponibles.

PROJECT_ID=your-project-id
gcloud config set project $PROJECT_ID

Obtén el código fuente

El código fuente de la aplicación se encuentra en la carpeta processing-pipelines del repositorio de eventarc-samples.

Clone el repositorio:

git clone https://github.com/GoogleCloudPlatform/eventarc-samples.git

Navega a la carpeta eventarc-samples/processing-pipelines:

cd eventarc-samples/processing-pipelines

3. Descripción general de la arquitectura

La arquitectura de la aplicación es la siguiente:

6aa6fbc7721dd6b6.png

  1. Una imagen se guarda en un bucket de entrada que genera un evento de creación de Cloud Storage.
  2. Eventarc lee el evento de creación de Cloud Storage a través de un activador de Cloud Storage y lo pasa a Workflows como un CloudEvent.
  3. En el primer paso del flujo de trabajo, Filtrar, un servicio de Cloud Functions, usa la API de Vision para determinar si la imagen es segura. Si la imagen es segura, Workflows continúa con los próximos pasos.
  4. En el segundo paso del flujo de trabajo, Labeler, un servicio de Cloud Function, extrae etiquetas de la imagen con la API de Vision y las guarda en el bucket de salida.
  5. En el tercer paso, Renamer, otro servicio de Cloud Function, cambia el tamaño de la imagen con ImageSharp y la guarda en el bucket de salida.
  6. En el último paso, Watermarker, otro servicio de Cloud Function, agrega una marca de agua de etiquetas del Labeler a la imagen redimensionada usando ImageSharp y la guarda en el bucket de salida.

La aplicación se activa por un evento de Cloud Storage, por lo que está controlada por eventos. El procesamiento de imágenes ocurre en un flujo de trabajo, por lo que se trata de una organización. En definitiva, es una organización basada en eventos para una arquitectura sin servidores flexible y estructurada para procesar imágenes.

4. Crear depósitos

Crear un bucket de entrada para que los usuarios suban las imágenes y un bucket de salida para que la canalización de procesamiento de imágenes guarde las imágenes procesadas

En Cloud Shell, ejecute lo siguiente:

REGION=us-central1
BUCKET1=$PROJECT_ID-images-input
BUCKET2=$PROJECT_ID-images-output

gsutil mb -l $REGION gs://$BUCKET1
gsutil mb -l $REGION gs://$BUCKET2

5. Implementa el servicio de filtros

Comencemos con la implementación del primer servicio. Este servicio de Cloud Functions recibe la información del bucket y del archivo, determina si la imagen es segura con la API de Vision y muestra el resultado.

Primero, habilita los servicios necesarios para Cloud Functions (gen2) y la API de Vision:

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

Dentro de la carpeta processing-pipelines de nivel superior, implementa el servicio:

SERVICE_NAME=filter

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --entry-point Filter.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v3/filter/csharp

Una vez implementada la función, configura la URL de servicio en una variable; la necesitaremos más adelante:

FILTER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

6. Implementa el servicio de etiquetador

El segundo servicio de Cloud Functions recibe la información del bucket y el archivo, extrae las etiquetas de la imagen con la API de Vision y las guarda en el bucket de salida.

Dentro de la carpeta processing-pipelines de nivel superior, implementa el servicio:

SERVICE_NAME=labeler

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Labeler.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/labeler/csharp

Una vez implementada la función, configura la URL de servicio en una variable; la necesitaremos más adelante:

LABELER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

7. Implementa el servicio de cambio de tamaño

Este servicio de Cloud Functions recibe la información del bucket y el archivo, cambia el tamaño de la imagen con ImageSharp y la guarda en el bucket de salida.

Dentro de la carpeta processing-pipelines de nivel superior, implementa el servicio:

SERVICE_NAME=resizer

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Resizer.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/resizer/csharp \
  --timeout=120s

Ten en cuenta el valor timeout de 2 minutos para permitir que la función de cambio de tamaño tenga tiempo adicional para su procesamiento.

Una vez implementada la función, configura la URL de servicio en una variable; la necesitaremos más adelante:

RESIZER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

8. Implementa el servicio de marcas de agua

Este servicio de Cloud Functions recibe la información del bucket, el archivo y las etiquetas, lee el archivo, agrega las etiquetas como marca de agua a la imagen con ImageSharp y la guarda en el bucket de salida.

Dentro de la carpeta processing-pipelines de nivel superior, implementa el servicio:

SERVICE_NAME=watermarker

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Watermarker.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/watermarker/csharp

Una vez implementada la función, configura la URL de servicio en una variable; la necesitaremos más adelante:

WATERMARKER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

En este punto, las cuatro Cloud Functions deberían estar implementadas y en ejecución:

76a218568982c90c.png

9. Define e implementa el flujo de trabajo

Usa Workflows para reunir servicios de filtros, etiquetadores, redimensionadores y marcas de agua en un flujo de trabajo. Los flujos de trabajo organizarán la llamada a estos servicios en el orden y con los parámetros que definamos.

Primero, habilita los servicios necesarios para Workflows:

gcloud services enable \
  workflows.googleapis.com \
  workflowexecutions.googleapis.com

Definir

Workflows recibe un CloudEvent como parámetro. Proviene de Eventarc una vez que creemos el activador. En los primeros dos pasos, Workflows registra el evento y extrae la información del bucket y el archivo del evento:

main:
  params: [event]
  steps:
  - log_event:
      call: sys.log
      args:
          text: ${event}
          severity: INFO
  - extract_bucket_and_file:
      assign:
      - bucket: ${event.data.bucket}
      - file: ${event.data.name}

En el paso filter, Workflows realiza una llamada al servicio de filtro que implementamos antes. Luego, registra y verifica la seguridad de los archivos:

  - filter:
      call: http.post
      args:
        url: FILTER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: filterResponse
  - log_safety:
      call: sys.log
      args:
          text: ${filterResponse.body.safe}
          severity: INFO
  - check_safety:
      switch:
        - condition: ${filterResponse.body.safe == true}
          next: label
      next: end

En el paso label, Workflows realiza una llamada al servicio de etiquetador y captura la respuesta (las 3 etiquetas principales):

  - label:
      call: http.post
      args:
        url: LABELER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: labelResponse

En el paso resize, Workflows realiza una llamada al servicio de cambio de tamaño y captura la respuesta (el bucket y el archivo de la imagen a la que se le cambió el tamaño):

  - resize:
      call: http.post
      args:
        url: RESIZER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: resizeResponse

En el paso watermark, Workflows llama al servicio de marcas de agua con las etiquetas y la imagen con el tamaño cambiado, y captura el resultado (la imagen redimensionada y con una marca de agua):

  - watermark:
      call: http.post
      args:
        url: WATERMARKER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${resizeResponse.body.bucket}
            file: ${resizeResponse.body.file}
            labels: ${labelResponse.body.labels}
      result: watermarkResponse

En el paso final, los flujos de trabajo muestran el código de estado HTTP de los servicios de etiquetador, cambio de tamaño y marca de agua:

  - final:
      return:
        label: ${labelResponse.code}
        resize: ${resizeResponse.code}
        watermark: ${watermarkResponse.code}

Implementar

Antes de implementar el flujo de trabajo, asegúrate de reemplazar las URLs de servicio por las URLs de las funciones implementadas de forma manual o mediante sed:

Dentro de la carpeta processing-pipelines de nivel superior, navega a la carpeta image-v3 en la que se encuentra el archivo workflows.yaml:

cd image-v3/

Ejecuta sed para reemplazar las URLs de marcador de posición por las URLs reales de los servicios implementados:

sed -i -e "s|FILTER_URL|${FILTER_URL}|" workflow.yaml
sed -i -e "s|LABELER_URL|${LABELER_URL}|" workflow.yaml
sed -i -e "s|RESIZER_URL|${RESIZER_URL}|" workflow.yaml
sed -i -e "s|WATERMARKER_URL|${WATERMARKER_URL}|" workflow.yaml

Implementa el flujo de trabajo:

WORKFLOW_NAME=image-processing

gcloud workflows deploy $WORKFLOW_NAME \
    --source=workflow.yaml \
    --location=$REGION

Luego de unos segundos, deberías ver el flujo de trabajo implementado en la consola:

92cf4e758bdc3dde.png

10. Crear activador

Ahora que se implementó el flujo de trabajo, el último paso es conectarlo a eventos de Cloud Storage con un activador de Eventarc.

Configuración única

Primero, habilita los servicios necesarios para Eventarc:

gcloud services enable \
 eventarc.googleapis.com

Crea una cuenta de servicio que usarás en el activador de Eventarc.

SERVICE_ACCOUNT=eventarc-trigger-imageproc-sa

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Eventarc trigger image processing service account"

Otorga el rol workflows.invoker, de modo que la cuenta de servicio se pueda usar para invocar Workflows desde Eventarc:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role roles/workflows.invoker \
  --member serviceAccount:$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

Otorga el rol eventarc.eventReceiver; la cuenta de servicio se puede usar en un

Activador de Cloud Storage:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role roles/eventarc.eventReceiver \
  --member serviceAccount:$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

Otorga el rol pubsub.publisher a la cuenta de servicio de Cloud Storage. Esto es necesario para el activador de Cloud Storage de Eventarc:

STORAGE_SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p $PROJECT_ID)"

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:$STORAGE_SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

Crear

Ejecuta el siguiente comando para crear un activador. Este activador filtra los eventos de creación de archivos nuevos desde el bucket de Cloud Storage de entrada y los pasa al flujo de trabajo que definimos anteriormente:

TRIGGER_NAME=trigger-image-processing

gcloud eventarc triggers create $TRIGGER_NAME \
  --location=$REGION \
  --destination-workflow=$WORKFLOW_NAME \
  --destination-workflow-location=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=$BUCKET1" \
  --service-account=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

Puedes ver que el activador se creó y está listo en la sección de Eventarc de la consola de Cloud:

14330c4fa2451bc0.png

11. Prueba la canalización

La canalización de procesamiento de imágenes está lista para recibir eventos de Cloud Storage. Para probar la canalización, sube una imagen al bucket de entrada:

gsutil cp beach.jpg gs://$BUCKET1

Apenas subas la imagen, deberías ver una ejecución de Workflows en estado activo:

36d07cb63c39e7d9.png

Después de aproximadamente un minuto, deberías ver que la ejecución se realizó correctamente. También puedes ver la entrada y el resultado del flujo de trabajo:

229200c79d989c25.png

Si muestras el contenido del bucket de salida, deberías ver la imagen redimensionada, la imagen redimensionada y con una marca de agua, y las etiquetas de la imagen:

gsutil ls gs://$BUCKET2

gs://$PROJECT_ID-images-output/beach-400x400-watermark.jpeg
gs://$PROJECT_ID-images-output/beach-400x400.png
gs://$PROJECT_ID-images-output/beach-labels.txt

Para comprobarlo, puedes abrir la imagen con una marca de agua y con nuevo tamaño para ver el resultado:

75f3c0019ca842ce.jpeg

12. Felicitaciones

¡Felicitaciones! Completaste el codelab.

Temas abordados

  • Descripción general de Eventarc y Workflows
  • Cómo implementar servicios de Cloud Functions
  • Cómo organizar servicios con Workflows
  • Cómo hacer que los flujos de trabajo respondan a los eventos de Cloud Storage con Eventarc