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 aplicación Pic-a-daily en la que se usaba una Cloud Function de Google Cloud Storage activada para el servicio de análisis de imágenes, un contenedor de GCS que activó Cloud Run a través de Pub/Sub para el servicio de miniaturas y Eventarc con el objetivo de activar el servicio de recolector de imágenes no utilizados 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 fluyan diferentes tipos de eventos a través del 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 no incurrir en facturación más allá de este instructivo. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de$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, productos sin servidores como Cloud Functions y Cloud Run, y llamadas a APIs externas para crear aplicaciones flexibles sin servidores.

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

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

  • Reintento flexible y manejo de errores entre pasos para una ejecución confiable de los pasos
  • Se analiza JSON y pasa variables entre pasos para evitar la unión del código.
  • Las fórmulas de expresión para tomar decisiones permiten ejecuciones de pasos condicionales.
  • Subflujos de trabajo para flujos de trabajo modulares y reutilizables.
  • La asistencia para servicios externos permite la organización de servicios más allá de Google Cloud.
  • Compatibilidad de autenticación con Google Cloud y servicios externos para ejecuciones de pasos seguras.
  • Conectores a servicios de Google Cloud como Pub/Sub, Firestore, Tasks y Secret Manager para una integración más fácil.

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

4. Habilita las APIs

En este lab, conectarás los 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 estén habilitados todos los servicios necesarios:

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

Para este lab, verás la siguiente estructura de carpetas:

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

Estas son las carpetas relevantes:

  • frontend contiene el frontend de App Engine que reutilizaremos en el 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 del flujo de trabajo.

6. Explora los flujos de trabajo de YAML

El archivo workflows.yaml define el flujo de trabajo en una serie de pasos. Analicémoslo para entenderlo mejor.

Al comienzo del flujo de trabajo, se pasan algunos parámetros. Se pasarán por dos Cloud Functions que activan los flujos de trabajo. Llegaremos a estas funciones más adelante, pero así es como comienza el flujo 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án 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, Workflows verifica 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

Este es el paso de la definición del flujo de trabajo 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 de interruptores y manejo de excepciones, con la instrucción de switch y sus diversas condiciones, y la instrucción de aumento para generar un error cuando no se reconoce el evento.

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

Ten en cuenta que todo se hace en Workflows, excepto Vision Transform, Cloud Functions (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 analizada la imagen, los siguientes dos pasos son crear la miniatura de la imagen y un collage con las imágenes más recientes. Para ello, se implementan 2 servicios de Cloud Run y se les llaman desde los pasos thumbnailCall y collageCall:

82f9179323c3144.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 es cuando se borra un archivo del bucket de almacenamiento principal, que contiene las versiones de alta resolución de las fotos. En esta rama, queremos borrar la miniatura de la imagen en el bucket que contiene las miniaturas y borrar sus metadatos de Firestore. Ambos se hacen 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 delete finaliza mostrando los resultados / 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 base de datos de Firestore.

7. Crea los buckets

Necesitas 2 categorías para las imágenes: 1 para guardar las imágenes originales en alta resolución y 1 para guardar las miniaturas.

Crea un bucket regional público (en este caso, en Europa) con acceso uniforme para que los usuarios suban fotos a través de 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 hayan creado y sean públicos, visita la sección Cloud Storage de la consola de Cloud:

15063936edd72f06.png

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

Workflows.yaml comienza con init, eventTypeSwitch, eventTypeNotSupported pasos. Esto garantiza que los eventos que provienen de buckets se enruten a los pasos correctos.

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

daaed43a22d2b0d3.png

A continuación, debemos transformar los datos que muestra la API de Vision para poder guardarlos en Firestore. Más específicamente, necesitamos hacer lo siguiente:

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

Esto se hace en código en una Cloud Function y Workflows simplemente llama a esta función:

5e120e70c67779cd.png

Explora el código

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

Implementa en Cloud Functions

Navega a la carpeta:

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

Configura la región que prefieras:

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 Workflows, debes verificar la seguridad de la imagen a partir de los datos de la imagen y, luego, almacenar la información sobre la imagen que muestra la API de Vision en la base de datos de Cloud Firestore, una base de datos NoSQL de documentos nativa de la nube, rápida, completamente administrada y sin servidores:

6624c616bc7cd97f.png

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

Primero, crea una aplicación de App Engine en la región en la que quieres que esté 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 manera programática en nuestra colección y contendrán 4 campos:

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

Debido a que buscaremos en Firestore para encontrar imágenes que tengan miniaturas disponibles y ordenaremos según la fecha de creación, necesitaremos 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 aproximadamente.

Una vez que se crea el índice, puedes verlo en la consola de Cloud:

43af1f5103bf423.png

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

10. Servicio de miniaturas (Cloud Run)

Lo siguiente en la cadena es crear la miniatura de una imagen. Esto se realiza en código en 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 verificar 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 contenedor y, luego, alojarse 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}

Al cabo de uno o dos minutos, la compilación debería completarse correctamente y el contenedor se implementará en Google Container Registry.

Implementa en Cloud Run

Establece algunas variables y la configuración 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á llamar a este servicio.

11. Servicio de collages (Cloud Run)

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

591e36149066e1ba.png

Cómo explorar el código

El servicio de Cloud Run se llama collage. Puedes verificar 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 contenedor y, luego, alojarse 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}

Al cabo de uno o dos minutos, la compilación debería completarse correctamente y el contenedor se implementará en Google Container Registry.

Implementa en Cloud Run

Establece algunas variables y la configuración 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 la consola de Cloud. El paso collageCall de Workflows podrá 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 Workflows.

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}

Luego de unos segundos, el flujo de trabajo debería implementarse y puedes verlo en la sección Workflows de la consola de Cloud:

94a720149e5df9c5.png

Puedes hacer clic en el flujo de trabajo y editarlo si lo deseas. Durante la edición, obtienes una buena representación visual 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 adecuados. En cambio, lo ejecutaremos automáticamente en respuesta a los eventos de Cloud Storage en el siguiente paso.

13. Activadores de flujos de trabajo (Cloud Functions)

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

Los flujos de trabajo tienen 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 de la Cloud Function que escuchan eventos de Cloud Storage. Dado que una Cloud Function solo puede escuchar un tipo de evento, implementarás dos funciones de Cloud Functions para escuchar los eventos de creación y eliminación:

c4d79646de729e4.png

Explora el código

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

Implementa en Cloud Functions

Navega a la carpeta:

cd workflows/functions/trigger-workflow/nodejs

Establece algunas variables y la configuración 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 se complete la implementación, podrás ver ambas funciones en la consola de Cloud:

7d60c8b7851f39f5.png

14. Frontend (App Engine)

En este paso, crearás un frontend web en Google App Engine desde Pic-a-daily: Lab 4: Crea un frontend web 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: Crea un frontend web.

Explora el código

La aplicación de App Engine se llama frontend. Puedes verificar su código completo en index.js.

Implemente en App Engine

Navega a la carpeta:

cd frontend

Establece la región que prefieras y reemplaza GOOGLE_CLOUD_PROJECT en app.yaml por el ID del 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 uno o dos minutos, 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 App Engine de la consola de Cloud para ver si la app está implementada y explorar las 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 realizar la prueba, ve a la URL predeterminada de App Engine correspondiente a la app (https://<YOUR_PROJECT_ID>.appspot.com/). Deberías ver la IU de frontend en funcionamiento.

1649ac060441099.png

Sube una imagen. Esto debería activar los flujos de trabajo, y podrás ver su ejecución en el estado Active de la consola de Cloud:

b5a2a3d7a2bc094.png

Una vez finalizados los flujos de trabajo, puedes hacer clic en el ID de ejecución y ver el resultado de 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 pretendes 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