Ejecutar una tarea de Cloud Run con Workflows

Workflows te permite ejecutar tareas de Cloud Run como parte de un flujo de trabajo para llevar a cabo un procesamiento de datos más complejo u orquestar un sistema de tareas.

En este tutorial se muestra cómo usar Workflows para ejecutar una tarea de Cloud Run que procesa los datos transferidos como variables de entorno a la tarea en respuesta a un evento de Cloud Storage.

Ten en cuenta que también puedes almacenar los datos de eventos en un segmento de Cloud Storage, lo que te permite cifrar los datos con claves de cifrado gestionadas por el cliente. Para obtener más información, consulta Ejecutar una tarea de Cloud Run que procese datos de eventos guardados en Cloud Storage.

Crear un trabajo de Cloud Run

En este tutorial se usa un trabajo de Cloud Run de ejemplo de GitHub. El trabajo lee datos de un archivo de entrada en Cloud Storage y realiza algún procesamiento arbitrario para cada línea del archivo.

  1. Para obtener el código de ejemplo, clona el repositorio de la aplicación de ejemplo en tu máquina local:

    git clone https://github.com/GoogleCloudPlatform/jobs-demos.git

    También puedes descargar el ejemplo como un archivo ZIP y extraerlo.

  2. Accede al directorio que contiene el código de muestra:

    cd jobs-demos/parallel-processing
  3. Crea un segmento de Cloud Storage para almacenar un archivo de entrada en el que se pueda escribir y que active un evento:

    Consola

    1. En la Google Cloud consola, ve a la página Segmentos de Cloud Storage.

      Ir a Contenedores

    2. Haz clic en Añadir Crear.
    3. En la página Crear un contenedor, introduce un nombre para el contenedor:
      input-PROJECT_ID
      Sustituye PROJECT_ID por el ID de tu Google Cloud proyecto.
    4. Mantén los demás valores predeterminados.
    5. Haz clic en Crear.

    gcloud

    Ejecuta el comando gcloud storage buckets create:

    gcloud storage buckets create gs://input-PROJECT_ID

    Si la solicitud se realiza correctamente, el comando devuelve el siguiente mensaje:

    Creating gs://input-PROJECT_ID/...

    Terraform

    Para crear un segmento de Cloud Storage, usa el recurso google_storage_bucket y modifica el archivo main.tf como se muestra en el siguiente ejemplo.

    Para saber cómo aplicar o quitar una configuración de Terraform, consulta Comandos básicos de Terraform.

    Ten en cuenta que, en un flujo de trabajo típico de Terraform, aplicas todo el plan a la vez. Sin embargo, en este tutorial, puedes orientar los anuncios a un recurso específico. Por ejemplo:

    terraform apply -target="random_id.bucket_name_suffix"
    y
    terraform apply -target="google_storage_bucket.default"

    # Cloud Storage bucket names must be globally unique
    resource "random_id" "bucket_name_suffix" {
      byte_length = 4
    }
    
    # Create a Cloud Storage bucket
    resource "google_storage_bucket" "default" {
      name                        = "input-${data.google_project.project.name}-${random_id.bucket_name_suffix.hex}"
      location                    = "us-central1"
      storage_class               = "STANDARD"
      force_destroy               = false
      uniform_bucket_level_access = true
    }
  4. Crea un repositorio estándar de Artifact Registry donde puedas almacenar tu imagen de contenedor:

    Consola

    1. En la Google Cloud consola, ve a la página Repositorios de Artifact Registry:

      Ir a Repositorios

    2. Haz clic en Crear repositorio.

    3. Asigna un nombre al repositorio (por ejemplo, my-repo). Los nombres de los repositorios deben ser únicos en cada ubicación de repositorio de un proyecto.

    4. Mantén el formato predeterminado, que debe ser Docker.

    5. Mantén el modo predeterminado, que debe ser Estándar.

    6. En la región, selecciona us-central1 (Iowa).

    7. Conserva el resto de los valores predeterminados.

    8. Haz clic en Crear.

    gcloud

    Ejecuta el comando:

    gcloud artifacts repositories create REPOSITORY \
        --repository-format=docker \
        --location=us-central1

    Sustituye REPOSITORY por un nombre único para el repositorio (por ejemplo, my-repo). Los nombres de los repositorios deben ser únicos en cada ubicación de repositorio de un proyecto.

    Terraform

    Para crear un repositorio de Artifact Registry, usa el recurso google_artifact_registry_repository y modifica el archivo main.tf como se muestra en el siguiente ejemplo.

    Ten en cuenta que, en un flujo de trabajo típico de Terraform, aplicas todo el plan a la vez. Sin embargo, para este tutorial, puedes orientar la publicidad a un recurso específico. Por ejemplo:

    terraform apply -target="google_artifact_registry_repository.default"

    # Create an Artifact Registry repository
    resource "google_artifact_registry_repository" "default" {
      location      = "us-central1"
      repository_id = "my-repo"
      format        = "docker"
    }
  5. Crea la imagen de contenedor con un Google Cloud paquete de compilación predeterminado:

    export SERVICE_NAME=parallel-job
    gcloud builds submit \
        --pack image=us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}

    Sustituye REPOSITORY por el nombre de tu repositorio de Artifact Registry.

    La compilación puede tardar un par de minutos en completarse.

  6. Crea un trabajo de Cloud Run que despliegue la imagen de contenedor:

    Consola

    1. En la Google Cloud consola, ve a la página Cloud Run:

      Ir a Cloud Run

    2. Haz clic en Crear tarea para que se muestre el formulario Crear tarea.

      1. En el formulario, seleccione us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/parallel-job:latest como URL de la imagen de contenedor de Artifact Registry.
      2. Opcional: En el nombre del trabajo, introduce parallel-job.
      3. Opcional: En la región, selecciona us-central1 (Iowa).
      4. Para indicar el número de tareas que quieres ejecutar en el trabajo, introduce 10. Todas las tareas deben completarse correctamente para que el trabajo se realice correctamente. De forma predeterminada, las tareas se ejecutan en paralelo.
    3. Despliega la sección Contenedor, variables y secretos, conexiones y seguridad y conserva todos los valores predeterminados, excepto los siguientes:

      1. Haz clic en la pestaña General.

        1. En el comando del contenedor, introduce python.
        2. En el argumento del contenedor, introduce process.py.
      2. Haz clic en la pestaña Variables y secretos.

        1. Haga clic en Añadir variable e introduzca INPUT_BUCKET en el nombre y input-PROJECT_ID en el valor.
        2. Haz clic en Añadir variable e introduce INPUT_FILE en el nombre y input_file.txt en el valor.
    4. Para crear el trabajo, haz clic en Crear.

    gcloud

    1. Define la región predeterminada de Cloud Run:

      gcloud config set run/region us-central1
    2. Crea el trabajo de Cloud Run:

      gcloud run jobs create parallel-job \
          --image us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/parallel-job:latest \
          --command python \
          --args process.py \
          --tasks 10 \
          --set-env-vars=INPUT_BUCKET=input-PROJECT_ID,INPUT_FILE=input_file.txt

      Tenga en cuenta que, si no especifica una etiqueta de imagen, Artifact Registry buscará la imagen con la etiqueta latest predeterminada.

      Para ver una lista completa de las opciones disponibles al crear un trabajo, consulta la documentación de la línea de comandos gcloud run jobs create.

      Una vez que se haya creado el trabajo, debería aparecer un mensaje que indique que se ha realizado correctamente.

    Terraform

    Para crear un trabajo de Cloud Run, usa el recurso google_cloud_run_v2_job y modifica el archivo main.tf como se muestra en el siguiente ejemplo.

    Ten en cuenta que, en un flujo de trabajo típico de Terraform, aplicas todo el plan a la vez. Sin embargo, para este tutorial, puedes orientar la publicidad a un recurso específico. Por ejemplo:

    terraform apply -target="google_cloud_run_v2_job.default"

    # Create a Cloud Run job
    resource "google_cloud_run_v2_job" "default" {
      name     = "parallel-job"
      location = "us-central1"
    
      template {
        task_count = 10
        template {
          containers {
            image   = "us-central1-docker.pkg.dev/${data.google_project.project.name}/${google_artifact_registry_repository.default.repository_id}/parallel-job:latest"
            command = ["python"]
            args    = ["process.py"]
            env {
              name  = "INPUT_BUCKET"
              value = google_storage_bucket.default.name
            }
            env {
              name  = "INPUT_FILE"
              value = "input_file.txt"
            }
          }
        }
      }
    }

Desplegar un flujo de trabajo que ejecute el trabajo de Cloud Run

Define y despliega un flujo de trabajo que ejecute el trabajo de Cloud Run que acabas de crear. Una definición de flujo de trabajo se compone de una serie de pasos descritos mediante la sintaxis de Workflows.

Consola

  1. En la Google Cloud consola, ve a la página Flujos de trabajo:

    Ir a Workflows

  2. Haz clic en Crear.

  3. Escribe un nombre para el nuevo flujo de trabajo, como cloud-run-job-workflow.

  4. En la región, selecciona us-central1 (Iowa).

  5. En el campo Cuenta de servicio, selecciona la cuenta que has creado anteriormente.

    La cuenta de servicio actúa como identidad del flujo de trabajo. Ya deberías haber concedido el rol Administrador de Cloud Run a la cuenta de servicio para que el flujo de trabajo pueda ejecutar el trabajo de Cloud Run.

  6. Haz clic en Siguiente.

  7. En el editor del flujo de trabajo, introduce la siguiente definición para tu flujo de trabajo:

    main:
        params: [event]
        steps:
            - init:
                assign:
                    - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                    - event_bucket: ${event.data.bucket}
                    - event_file: ${event.data.name}
                    - target_bucket: ${"input-" + project_id}
                    - job_name: parallel-job
                    - job_location: us-central1
            - check_input_file:
                switch:
                    - condition: ${event_bucket == target_bucket}
                      next: run_job
                    - condition: true
                      next: end
            - run_job:
                call: googleapis.run.v1.namespaces.jobs.run
                args:
                    name: ${"namespaces/" + project_id + "/jobs/" + job_name}
                    location: ${job_location}
                    body:
                        overrides:
                            containerOverrides:
                                env:
                                    - name: INPUT_BUCKET
                                      value: ${event_bucket}
                                    - name: INPUT_FILE
                                      value: ${event_file}
                result: job_execution
            - finish:
                return: ${job_execution}
  8. Haz clic en Desplegar.

gcloud

  1. Crea un archivo de código fuente para tu flujo de trabajo:

    touch cloud-run-job-workflow.yaml
  2. Copia la siguiente definición de flujo de trabajo en tu archivo de código fuente:

    main:
        params: [event]
        steps:
            - init:
                assign:
                    - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                    - event_bucket: ${event.data.bucket}
                    - event_file: ${event.data.name}
                    - target_bucket: ${"input-" + project_id}
                    - job_name: parallel-job
                    - job_location: us-central1
            - check_input_file:
                switch:
                    - condition: ${event_bucket == target_bucket}
                      next: run_job
                    - condition: true
                      next: end
            - run_job:
                call: googleapis.run.v1.namespaces.jobs.run
                args:
                    name: ${"namespaces/" + project_id + "/jobs/" + job_name}
                    location: ${job_location}
                    body:
                        overrides:
                            containerOverrides:
                                env:
                                    - name: INPUT_BUCKET
                                      value: ${event_bucket}
                                    - name: INPUT_FILE
                                      value: ${event_file}
                result: job_execution
            - finish:
                return: ${job_execution}
  3. Para desplegar el flujo de trabajo, introduce el siguiente comando:

    gcloud workflows deploy cloud-run-job-workflow \
        --location=us-central1 \
        --source=cloud-run-job-workflow.yaml \
        --service-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com

    Haz los cambios siguientes:

    • SERVICE_ACCOUNT_NAME: el nombre de la cuenta de servicio que has creado antes
    • PROJECT_ID: el ID de tu Google Cloud proyecto

    La cuenta de servicio actúa como identidad del flujo de trabajo. Ya deberías haber concedido el rol roles/run.admin a la cuenta de servicio para que el flujo de trabajo pueda ejecutar el trabajo de Cloud Run.

Terraform

Para crear un flujo de trabajo, usa el recurso google_workflows_workflow y modifica el archivo main.tf como se muestra en el siguiente ejemplo.

Para saber cómo aplicar o quitar una configuración de Terraform, consulta Comandos básicos de Terraform.

Ten en cuenta que, en un flujo de trabajo típico de Terraform, aplicas todo el plan a la vez. Sin embargo, en este tutorial, puedes segmentar un recurso específico. Por ejemplo:

terraform apply -target="google_workflows_workflow.default"

# Create a workflow
resource "google_workflows_workflow" "default" {
  name        = "cloud-run-job-workflow"
  region      = "us-central1"
  description = "Workflow that routes a Cloud Storage event and executes a Cloud Run job"

  deletion_protection = false # set to "true" in production

  # Note that $$ is needed for Terraform
  source_contents = <<EOF
  main:
      params: [event]
      steps:
          - init:
              assign:
                  - project_id: $${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                  - event_bucket: $${event.data.bucket}
                  - event_file: $${event.data.name}
                  - target_bucket: "${google_storage_bucket.default.name}"
                  - job_name: parallel-job
                  - job_location: us-central1
          - check_input_file:
              switch:
                  - condition: $${event_bucket == target_bucket}
                    next: run_job
                  - condition: true
                    next: end
          - run_job:
              call: googleapis.run.v1.namespaces.jobs.run
              args:
                  name: $${"namespaces/" + project_id + "/jobs/" + job_name}
                  location: $${job_location}
                  body:
                      overrides:
                          containerOverrides:
                              env:
                                  - name: INPUT_BUCKET
                                    value: $${event_bucket}
                                  - name: INPUT_FILE
                                    value: $${event_file}
              result: job_execution
          - finish:
              return: $${job_execution}
  EOF
}

El flujo de trabajo hace lo siguiente:

  1. Paso init: acepta un evento de Cloud Storage como argumento y, a continuación, define las variables necesarias.

  2. Paso check_input_file: comprueba si el segmento de Cloud Storage especificado en el evento es el que usa el trabajo de Cloud Run.

    • Si es así, el flujo de trabajo pasa al paso run_job.
    • Si no es así, el flujo de trabajo finaliza y se detiene cualquier otro procesamiento.
  3. Paso run_job: usa el método googleapis.run.v1.namespaces.jobs.run del conector de la API Admin de Cloud Run para ejecutar el trabajo. Los nombres del segmento de Cloud Storage y del archivo de datos se transfieren a la tarea desde el flujo de trabajo como variables de anulación.

  4. Paso finish: devuelve información sobre la ejecución del trabajo como resultado del flujo de trabajo.

Crear un activador de Eventarc para el flujo de trabajo

Para ejecutar automáticamente el flujo de trabajo y, a su vez, la tarea de Cloud Run cada vez que se actualice el archivo de datos de entrada, crea un activador de Eventarc que responda a los eventos de Cloud Storage en el segmento que contenga el archivo de datos de entrada.

Consola

  1. En la Google Cloud consola, ve a la página Flujos de trabajo:

    Ir a Workflows

  2. Haz clic en el nombre del flujo de trabajo, como cloud-run-job-workflow.

  3. En la página Detalles del flujo de trabajo, haz clic en Editar.

  4. En la página Editar flujo de trabajo, en la sección Activadores, haz clic en Añadir nuevo activador > Eventarc.

    Se abrirá el panel Eventarc trigger (Activador de Eventarc).

  5. En el campo Nombre del activador, escribe un nombre para el activador, como cloud-run-job-workflow-trigger.

  6. En la lista Proveedor de eventos, selecciona Cloud Storage.

  7. En la lista Evento, selecciona google.cloud.storage.object.v1.finalized.

  8. En el campo Segmento, selecciona el segmento que contiene el archivo de datos de entrada. El nombre del segmento tiene el formato input-PROJECT_ID.

  9. En el campo Cuenta de servicio, selecciona la cuenta que has creado anteriormente.

    La cuenta de servicio actúa como identidad del activador. Ya deberías haber concedido los siguientes roles a la cuenta de servicio:

    • Receptor de evento Eventarc: para recibir eventos
    • Invocador de flujos de trabajo: para ejecutar flujos de trabajo
  10. Haz clic en Guardar activador.

    El activador de Eventarc ahora aparece en la sección Activadores de la página Editar flujo de trabajo.

  11. Haz clic en Siguiente.

  12. Haz clic en Desplegar.

gcloud

Para crear un activador de Eventarc, ejecuta el siguiente comando:

gcloud eventarc triggers create cloud-run-job-workflow-trigger \
    --location=us \
    --destination-workflow=cloud-run-job-workflow  \
    --destination-workflow-location=us-central1 \
    --event-filters="type=google.cloud.storage.object.v1.finalized" \
    --event-filters="bucket=input-PROJECT_ID" \
    --service-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com

Haz los cambios siguientes:

  • PROJECT_ID: el ID de tu Google Cloud proyecto
  • SERVICE_ACCOUNT_NAME: el nombre de la cuenta de servicio que has creado antes.

La cuenta de servicio actúa como identidad del activador. Ya deberías haber concedido los siguientes roles a la cuenta de servicio:

  • roles/eventarc.eventReceiver: para recibir eventos
  • roles/workflows.invoker: para ejecutar flujos de trabajo

Terraform

Para crear un activador, usa el recurso google_eventarc_trigger y modifica el archivo main.tf como se muestra en el siguiente ejemplo.

Para saber cómo aplicar o quitar una configuración de Terraform, consulta Comandos básicos de Terraform.

Ten en cuenta que, en un flujo de trabajo típico de Terraform, aplicas todo el plan a la vez. Sin embargo, en este tutorial, puedes segmentar un recurso específico. Por ejemplo:

terraform apply -target="google_eventarc_trigger.default"

# Create an Eventarc trigger that routes Cloud Storage events to Workflows
resource "google_eventarc_trigger" "default" {
  name     = "cloud-run-job-trigger"
  location = google_workflows_workflow.default.region

  # Capture objects changed in the bucket
  matching_criteria {
    attribute = "type"
    value     = "google.cloud.storage.object.v1.finalized"
  }
  matching_criteria {
    attribute = "bucket"
    value     = google_storage_bucket.default.name
  }

  # Send events to Workflows
  destination {
    workflow = google_workflows_workflow.default.id
  }

  service_account = google_service_account.workflows.email

}

Cada vez que se sube o se sobrescribe un archivo en el segmento de Cloud Storage que contiene el archivo de datos de entrada, el flujo de trabajo se ejecuta con el evento de Cloud Storage correspondiente como argumento.

Activar el flujo de trabajo

Prueba el sistema integral actualizando el archivo de datos de entrada en Cloud Storage.

  1. Genera datos nuevos para el archivo de entrada y súbelos a Cloud Storage en la ubicación que espera la tarea de Cloud Run:

    base64 /dev/urandom | head -c 100000 >input_file.txt
    gcloud storage cp input_file.txt gs://input-PROJECT_ID/input_file.txt

    Si has creado un segmento de Cloud Storage con Terraform, puedes obtener el nombre del segmento ejecutando el siguiente comando:

    gcloud storage buckets list gs://input*

    El trabajo de Cloud Run puede tardar unos minutos en ejecutarse.

  2. Para confirmar que la tarea de Cloud Run se ha ejecutado correctamente, consulta las ejecuciones de la tarea:

    gcloud config set run/region us-central1
    gcloud run jobs executions list --job=parallel-job

    En el resultado, debería aparecer que la tarea se ha ejecutado correctamente y que se han completado 10/10 tareas.

Consulta más información sobre cómo activar un flujo de trabajo con eventos o mensajes de Pub/Sub.