Foto diaria: Lab 6: Orquestación con flujos de trabajo

1. Descripción general

En los labs anteriores, compilaste una versión basada en eventos de la app de Pic-a-daily que usaba una Cloud Function activada por Google Cloud Storage para el servicio de Image Analysis, un contenedor de Cloud Run activado por GCS a través de Pub/Sub para el servicio de Thumbnail y Eventarc para activar el servicio de Image Garbage Collector en Cloud Run. También había un servicio de Collage activado por Cloud Scheduler:

d93345bfc235f81e.png

En este lab, crearás una versión organizada de la app. En lugar de que diferentes tipos de eventos fluyan por el sistema, usarás Workflows para organizar y llamar a los servicios de la siguiente manera:

b763efcbf5589747.png

Qué aprenderás

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • Workflows

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a la consola de Cloud 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.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

Recuerde el ID de proyecto, un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID.

  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar los recursos de Google Cloud recursos.

Ejecutar este codelab no debería costar mucho, tal vez nada. Asegúrate de seguir las instrucciones de la sección “Realiza una limpieza”, en la que se aconseja cómo cerrar recursos para que no se te facture más allá de este instructivo. 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 GCP Console, haga clic en el ícono de Cloud Shell en la barra de herramientas superior derecha:

bce75f34b2c53987.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:

f6ef2b5f13479f3a.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. Puedes realizar todo tu trabajo en este lab usando simplemente un navegador.

3. Introducción a Workflows

90fcd42d556e310e.jpeg

Puedes usar Workflows para crear flujos de trabajo sin servidores que vinculen una serie de tareas sin servidores en el orden que definas. Puedes combinar la potencia de las APIs de Google Cloud, los productos sin servidores, como Cloud Functions y Cloud Run, y las llamadas a las APIs externas para crear aplicaciones flexibles sin servidores.

Como es de esperar de un orquestador, Workflows te permite definir el flujo de tu lógica empresarial en un lenguaje de definición de flujos de trabajo basado en YAML/JSON y proporciona una API de ejecución de Workflows y una IU de Workflows para activar esos flujos.

Es más que un simple organizador con estas funciones integradas y configurables:

  • Manejo de errores y reintentos flexibles entre los pasos para una ejecución confiable de los pasos.
  • Análisis de JSON y paso de variables entre pasos para evitar código de pegamento.
  • Las fórmulas de expresión para las decisiones permiten ejecuciones de pasos condicionales.
  • Son flujos de trabajo secundarios para flujos de trabajo modulares y reutilizables.
  • La compatibilidad con servicios externos permite la organización de servicios más allá de Google Cloud.
  • Compatibilidad con la autenticación para Google Cloud y servicios externos para ejecuciones de pasos seguros.
  • Conectores a servicios de Google Cloud, como Pub/Sub, Firestore, Tasks y Secret Manager, para facilitar la integración

Sin mencionar que Workflows es un producto sin servidores completamente administrado. No hay servidores para configurar ni escalar, y solo pagas por lo que usas.

4. Habilita las APIs

En este lab, conectarás servicios de Cloud Functions y Cloud Run con Workflows. También usarás App Engine, Cloud Build, la API de Vision y otros servicios.

En Cloud Shell, asegúrate de que todos los servicios necesarios estén habilitados:

gcloud services enable \
  appengine.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  compute.googleapis.com \
  firestore.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \

Después de un tiempo, deberías ver que la operación finaliza correctamente:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

5. Obtén el código

Obtén el código, si aún no lo hiciste en los codelabs anteriores:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

Tendrás la siguiente estructura de carpetas, que es relevante para este lab:

frontend
 |
workflows
 |
 ├── functions
 ├── |── trigger-workflow
 ├── |── vision-data-transform
 ├── services
 ├── |── collage
 ├── |── thumbnails
 ├── workflows.yaml

Estas son las carpetas pertinentes:

  • frontend contiene el frontend de App Engine que reutilizaremos del lab 4.
  • functions contiene las funciones de Cloud Functions creadas para el flujo de trabajo.
  • services contiene los servicios de Cloud Run modificados para el flujo de trabajo.
  • workflows.yaml es el archivo de definición de Workflow.

6. Explora el archivo YAML de Workflows

El archivo workflows.yaml define el flujo de trabajo en una serie de pasos. Analicemos el proceso para comprenderlo mejor.

Al comienzo del flujo de trabajo, se pasan algunos parámetros. Se pasarán a través de dos Cloud Functions que activarán los flujos de trabajo. Veremos estas funciones más adelante, pero así es como se inician los flujos de trabajo:

d44a5e18aa9d4660.png

En YAML, puedes ver que estos parámetros se asignan a variables en el paso init, como los nombres de archivo y bucket que activan el evento, y las URLs de algunos servicios de Cloud Functions y Cloud Run a los que llamará Workflows:

main:
  params: [args]
  steps:
    - init:
        assign:
          - file: ${args.file}
          - bucket: ${args.bucket}
          - gsUri: ${"gs://" + bucket + "/" + file}
          - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - urls: ${args.urls}

A continuación, los flujos de trabajo verifican el tipo de evento. Se admiten 2 tipos de eventos: object.finalize (se emite cuando se guarda un archivo en el bucket de Cloud Storage) y object.delete (se emite cuando se borra un archivo). Cualquier otra acción generará una excepción de evento no admitido.

dd1f450983655619.png

Aquí se muestra el paso, en la definición del flujo de trabajo de YAML, en el que verificamos el tipo de evento de almacenamiento de archivos:

    - eventTypeSwitch:
        switch:
            - condition: ${args.eventType == "google.storage.object.finalize"}
              next: imageAnalysisCall
            - condition: ${args.eventType == "google.storage.object.delete"}
              next: pictureGarbageCollectionGCS
    - eventTypeNotSupported:
        raise: ${"eventType " + args.eventType + " is not supported"}
        next: end

Observa cómo Workflows admite instrucciones switch y el control de excepciones, con la instrucción switch y sus diversas condiciones, y la instrucción raise para generar un error cuando no se reconoce el evento.

A continuación, veamos el imageAnalysisCall. Se trata de una serie de llamadas de Workflows a la API de Vision para analizar la imagen, transformar los datos de respuesta de la API de Vision para ordenar las etiquetas de los elementos reconocidos en la imagen, elegir los colores dominantes, verificar si la imagen es segura para mostrarla y, luego, guardar los metadatos en Cloud Firestore.

Ten en cuenta que todo se hace en Workflows, excepto las funciones de Cloud Functions de Vision Transform (que implementaremos más adelante):

ca2ad16b9cbb436.png

Así se ven los pasos en YAML:

    - imageAnalysisCall:
        call: http.post
        args:
          url: https://vision.googleapis.com/v1/images:annotate
          headers:
            Content-Type: application/json
          auth:
            type: OAuth2
          body:
            requests:
            - image:
                source:
                  gcsImageUri: ${gsUri}
              features:
              - type: LABEL_DETECTION
              - type: SAFE_SEARCH_DETECTION
              - type: IMAGE_PROPERTIES
        result: imageAnalysisResponse
    - transformImageAnalysisData:
        call: http.post
        args:
          url: ${urls.VISION_DATA_TRANSFORM_URL}
          auth:
            type: OIDC
          body: ${imageAnalysisResponse.body}
        result: imageMetadata
    - checkSafety:
        switch:
          - condition: ${imageMetadata.body.safe == true}
            next: storeMetadata
        next: end
    - storeMetadata:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
          auth:
            type: OAuth2
          method: PATCH
          body:
            name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
            fields:
              color:
                stringValue: ${imageMetadata.body.color}
              created:
                timestampValue: ${imageMetadata.body.created}
              labels:
                arrayValue:
                  values: ${imageMetadata.body.labels}
        result: storeMetadataResponse

Una vez que se analiza la imagen, los dos pasos siguientes son crear la miniatura de la imagen y un collage de las imágenes más recientes. Para ello, se implementan 2 servicios de Cloud Run y se realizan llamadas a ellos desde los pasos thumbnailCall y collageCall:

76f9179323c3144.png

Pasos en YAML:

   - thumbnailCall:
        call: http.post
        args:
          url: ${urls.THUMBNAILS_URL}
          auth:
            type: OIDC
          body:
              gcsImageUri: ${gsUri}
        result: thumbnailResponse
    - collageCall:
        call: http.get
        args:
          url: ${urls.COLLAGE_URL}
          auth:
            type: OIDC
        result: collageResponse

Esta rama de la ejecución finaliza con la devolución de códigos de estado de cada servicio en el paso finalizeCompleted:

    - finalizeCompleted:
        return:
          imageAnalysis: ${imageAnalysisResponse.code}
          storeMetadata: ${storeMetadataResponse.code}
          thumbnail: ${thumbnailResponse.code}
          collage: ${collageResponse.code}

La otra rama de la ejecución se da cuando se borra un archivo del bucket de almacenamiento principal, que contiene las versiones de alta resolución de las imágenes. En esta rama, queremos borrar la miniatura de la imagen en el bucket que contiene miniaturas y borrar sus metadatos de Firestore. Ambas acciones se realizan con llamadas HTTP desde Workflows:

f172379274dcb3c2.png

Pasos en YAML:

    - pictureGarbageCollectionGCS:
        try:
          call: http.request
          args:
            url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
            auth:
              type: OAuth2
            method: DELETE
          result: gcsDeletionResult
        except:
          as: e
          steps:
              - dummyResultInOutVar:
                  assign:
                      - gcsDeletionResult:
                          code: 200
                          body: "Workaround for empty body response"
    - pictureGarbageCollectionFirestore:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
          auth:
            type: OAuth2
          method: DELETE
        result: firestoreDeletionResult

La rama de eliminación finaliza con la devolución de resultados o códigos de cada paso:

    - deleteCompleted:
        return:
          gcsDeletion: ${gcsDeletionResult}
          firestoreDeletion: ${firestoreDeletionResult.code}

En los siguientes pasos, crearemos todas las dependencias externas de los flujos de trabajo: buckets, Cloud Functions, servicios de Cloud Run y la base de datos de Firestore.

7. Crea los buckets

Necesitas 2 buckets para las imágenes: 1 para guardar las imágenes originales de alta resolución y 1 para guardar las miniaturas de las imágenes.

Crea un bucket regional público (en este caso, en Europa) con acceso uniforme para que los usuarios suban fotos con la herramienta gsutil:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

Crea otro bucket regional público para las miniaturas:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}

Para verificar que los buckets se crearon y son públicos, visita la sección Cloud Storage de Cloud Console:

15063936edd72f06.png

8. Transformación de datos de Vision (función de Cloud)

Workflows.yaml comienza con los pasos init, eventTypeSwitch y eventTypeNotSupported. Estos garantizan que los eventos provenientes de los segmentos se enruten a los pasos correctos.

En el caso del evento object.finalize, el paso imageAnalysisCall realiza una llamada a la API de Vision para extraer los metadatos de la imagen creada. Todos estos pasos se realizan en Workflows:

daaed43a22d2b0d3.png

A continuación, debemos transformar los datos que devuelve la API de Vision antes de guardarlos en Firestore. Específicamente, debemos hacer lo siguiente:

  • Enumera las etiquetas que se devolvieron para la imagen.
  • Recupera el color predominante de la imagen.
  • Determina si la imagen es segura.

Esto se hace en el código de una función de Cloud Functions, y Workflows simplemente llama a esta función:

5e120e70c67779cd.png

Explora el código

La Cloud Function se llama vision-data-transform. Puedes consultar su código completo en index.js. Como puedes ver, el único propósito de esta función es realizar una transformación de JSON a JSON para almacenar los metadatos de la imagen de forma conveniente en Firestore.

Implementar en Cloud Functions

Navega a la carpeta:

cd workflows/functions/vision-data-transform/nodejs

Establece la región que elijas:

export REGION=europe-west1
gcloud config set functions/region ${REGION}

Implementa la función con el siguiente comando:

export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=vision_data_transform \
  --trigger-http \
  --allow-unauthenticated

Una vez que se implemente la función, el paso transformImageAnalysisData de Workflows podrá llamar a esta función para realizar la transformación de datos de la API de Vision.

9. Prepara la base de datos

A continuación, en el flujo de trabajo, se verifica la seguridad de la imagen a partir de los datos de la imagen y, luego, se almacena la información sobre la imagen que devolvió la API de Vision en la base de datos de Cloud Firestore, una base de datos de documentos NoSQL nativa de la nube, rápida, completamente administrada y sin servidores:

6624c616bc7cd97f.png

Ambas acciones se realizan en Workflows, pero debes crear la base de datos de Firestore para que funcione el almacenamiento de metadatos.

Primero, crea una app de App Engine en la región en la que deseas la base de datos de Firestore (un requisito para Firestore):

export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}

A continuación, crea la base de datos de Firestore en la misma región:

gcloud firestore databases create --region=${REGION_FIRESTORE}

Los documentos se crearán de forma programática en nuestra colección y contendrán 4 campos:

  • name (cadena): Es el nombre de archivo de la imagen subida, que también es la clave del documento.
  • labels (array de cadenas): Son las etiquetas de los elementos reconocidos por la API de Vision.
  • color (cadena): Es el código de color hexadecimal del color predominante (p. ej., #ab12ef)
  • created (fecha): Marca de tiempo en la que se almacenaron los metadatos de esta imagen
  • thumbnail (booleano): Es un campo opcional que estará presente y será verdadero si se generó una imagen en miniatura para esta foto.

Como buscaremos en Firestore imágenes que tengan miniaturas disponibles y las ordenaremos según la fecha de creación, deberemos crear un índice de búsqueda. Puedes crear el índice con el siguiente comando:

gcloud firestore indexes composite create --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

Ten en cuenta que la creación del índice puede tardar hasta 10 minutos.

Una vez que se cree el índice, podrás verlo en Cloud Console:

43af1f5103bf423.png

El paso de Workflows storeMetadata ahora podrá almacenar los metadatos de la imagen en Firestore.

10. Servicio de miniaturas (Cloud Run)

El siguiente paso en la cadena es crear una miniatura de una imagen. Esto se hace en el código de un servicio de Cloud Run, y Workflows llama a este servicio en el paso thumbnailCall:

84d987647f082b53.png

Explora el código

El servicio de Cloud Run se llama thumbnails. Puedes consultar su código completo en index.js.

Compila y publica la imagen de contenedor

Cloud Run ejecuta contenedores, pero primero debes compilar la imagen del contenedor (definida en Dockerfile). Google Cloud Build se puede usar para compilar imágenes de contenedores y, luego, alojarlas en Google Container Registry.

Navega a la carpeta:

cd workflows/services/thumbnails/nodejs

Compilación:

export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

Después de un minuto o dos, la compilación debería completarse correctamente y el contenedor se implementará en Google Container Registry.

Implementa en Cloud Run

Establece algunas variables y configuraciones necesarias:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

Realiza la implementación con el siguiente comando:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

Una vez que se implemente el servicio, el paso thumbnailCall de Workflows podrá llamarlo.

11. Servicio de collage (Cloud Run)

El siguiente paso en la cadena es crear un collage a partir de las imágenes más recientes. Esto se hace en el código de un servicio de Cloud Run, y Workflows llama a este servicio en el paso collageCall:

591e36149066e1ba.png

Explora el código

El servicio de Cloud Run se llama collage. Puedes consultar su código completo en index.js.

Compila y publica la imagen de contenedor

Cloud Run ejecuta contenedores, pero primero debes compilar la imagen del contenedor (definida en Dockerfile). Google Cloud Build se puede usar para compilar imágenes de contenedores y, luego, alojarlas en Google Container Registry.

Navega a la carpeta:

cd services/collage/nodejs

Compilación:

export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

Después de un minuto o dos, la compilación debería completarse correctamente y el contenedor se implementará en Google Container Registry.

Implementa en Cloud Run

Establece algunas variables y configuraciones necesarias:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

Implementación:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

Una vez que se implemente el servicio, puedes verificar que ambos servicios se estén ejecutando en la sección Cloud Run de Cloud Console y que el paso de Workflows collageCall pueda llamar a este servicio:

3ae9873f4cbbf423.png

12. Implementación de flujos de trabajo

Implementamos todas las dependencias externas de Workflows. Workflows puede completar todos los pasos restantes (finalizeCompleted, pictureGarbageCollectionGCS, pictureGarbageCollectionFirestore, deleteCompleted).

Llegó el momento de implementar los flujos de trabajo.

Navega a la carpeta que contiene el archivo workflows.yaml y, luego, impleméntalo con el siguiente comando:

export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
  --source=workflows.yaml \
  --location=${WORKFLOW_REGION}

En unos segundos, se implementará el flujo de trabajo y podrás verlo en la sección Flujos de trabajo de la consola de Cloud:

94a720149e5df9c5.png

Si lo deseas, puedes hacer clic en el flujo de trabajo y editarlo. Durante la edición, obtienes una representación visual agradable del flujo de trabajo:

55441b158f6027f3.png

También puedes ejecutar el flujo de trabajo desde la consola de Cloud de forma manual con los parámetros correctos. En su lugar, lo ejecutaremos automáticamente en respuesta a los eventos de Cloud Storage en el siguiente paso.

13. Activadores de Workflows (Cloud Functions)

El flujo de trabajo se implementó y está listo. Ahora, debemos activar los flujos de trabajo cuando se cree o borre un archivo en un bucket de Cloud Storage. Estos son los eventos storage.object.finalize y storage.object.delete, respectivamente.

Workflows tiene APIs y bibliotecas cliente para crear, administrar y ejecutar flujos de trabajo que puedes usar. En este caso, usarás la API de Workflows Execution y, más específicamente, su biblioteca cliente de Node.js para activar el flujo de trabajo.

Activarás los flujos de trabajo desde Cloud Functions que detectan eventos de Cloud Storage. Dado que una Cloud Function solo puede detectar un tipo de evento, implementarás dos Cloud Functions para detectar los eventos de creación y eliminación:

c4d79646de729e4.png

Explora el código

La Cloud Function se llama trigger-workflow. Puedes consultar su código completo en index.js.

Implementar en Cloud Functions

Navega a la carpeta:

cd workflows/functions/trigger-workflow/nodejs

Establece algunas variables y configuraciones necesarias:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}

Implementa la función que responde a los eventos de finalización:

export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.finalize \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

Implementa la segunda función que responde a los eventos de eliminación:

export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.delete \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

Cuando finalice la implementación, podrás ver ambas funciones en Cloud Console:

7d60c8b7851f39f5.png

14. Frontend (App Engine)

En este paso, crearás un frontend web en Google App Engine a partir de Pic-a-daily: Lab 4—Create a web frontend que permitirá a los usuarios subir imágenes desde la aplicación web, así como explorar las imágenes subidas y sus miniaturas.

223fb2281614d053.png

Puedes obtener más información sobre App Engine y leer la descripción del código en Pic-a-daily: Lab 4—Create a web frontend.

Explora el código

La app de App Engine se llama frontend. Puedes consultar su código completo en index.js.

Implemente en App Engine

Navega a la carpeta:

cd frontend

Establece la región que elijas y reemplaza GOOGLE_CLOUD_PROJECT en app.yaml por el ID de tu proyecto real:

export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml

Implementación:

gcloud app deploy app.yaml -q

Después de un minuto o dos, se te indicará que la aplicación está entregando tráfico:

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 8 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com]
You can stream logs from the command line by running:
  $ gcloud app logs tail -s default
To view your application in the web browser run:
  $ gcloud app browse

También puedes visitar la sección de App Engine en Cloud Console para ver que la app se implementó y explorar funciones de App Engine, como el control de versiones y la división del tráfico:

f4bd5f4de028bd83.png

15. Prueba los flujos de trabajo

Para probarla, ve a la URL predeterminada de App Engine para la app (https://<YOUR_PROJECT_ID>.appspot.com/) y deberías ver la IU de frontend en funcionamiento.

1649ac060441099.png

Sube una foto. Esto debería activar los flujos de trabajo, y podrás ver la ejecución del flujo de trabajo en estado Active en Cloud Console:

b5a2a3d7a2bc094.png

Una vez que se completen los flujos de trabajo, puedes hacer clic en el ID de ejecución y ver el resultado de los diferentes servicios:

8959df5098c21548.png

Sube 3 fotos más. También deberías ver la miniatura y el collage de las imágenes en los buckets de Cloud Storage y el frontend de App Engine actualizados:

d90c786ff664a5dc.png

16. Limpieza (opcional)

Si no tienes la intención de conservar la app, puedes borrar todo el proyecto para limpiar los recursos, ahorrar costos y ser un buen ciudadano de la nube en general:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

17. ¡Felicitaciones!

Creaste una versión organizada de la app con Workflows para organizar y llamar a los servicios.

Temas abordados

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • Workflows