Ejecuta un trabajo por lotes con Workflows

Batch es un servicio completamente administrado que te permite programar, poner en cola y ejecutar cargas de trabajo de procesamiento por lotes en instancias de máquina virtual (VM) de Compute Engine. Batch aprovisiona recursos y administra la capacidad en tu nombre, lo que permite que tus cargas de trabajo por lotes se ejecuten a gran escala.

Workflows te permite ejecutar los servicios que necesitas en el orden que definas, descrito con la sintaxis de Workflows.

En este instructivo, usarás el conector de Workflows para Batch para programar y ejecutar un trabajo de Batch que ejecute seis tareas en paralelo en dos VMs de Compute Engine. El uso de Batch y Workflows te permite combinar las ventajas que ofrecen y aprovisionar y coordinar de manera eficiente todo el proceso.

Crea un repositorio de Artifact Registry

Crea un repositorio para almacenar tu imagen de contenedor de Docker.

Console

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

    Ir a Repositorios

  2. Haz clic en Crear repositorio.

  3. Ingresa containers como el nombre del repositorio.

  4. En Formato, elige Docker.

  5. En Tipo de ubicación, elige Región.

  6. En la lista Región, selecciona us-central1.

  7. Haz clic en Crear.

gcloud

Ejecuta el siguiente comando:

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

Creaste un repositorio de Artifact Registry llamado containers en la región us-central1. Para obtener más información sobre las regiones admitidas, consulta Ubicaciones de Artifact Registry.

Obtén las muestras de código

Google Cloud almacena el código fuente de la aplicación para este instructivo en GitHub. Puedes clonar ese repositorio o descargar las muestras.

  1. Clona el repositorio de la app de muestra en tu máquina local:

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

    De manera opcional, puedes descargar las muestras en el archivo main.zip y extraerlas.

  2. Dirígete al directorio que contiene el código de muestra:

    cd batch-samples/primegen
    

Ahora tienes el código fuente para la aplicación en tu entorno de desarrollo.

Compila la imagen de Docker con Cloud Build

El Dockerfile contiene la información necesaria para compilar una imagen de Docker con Cloud Build. Ejecuta el siguiente comando para compilarlo:

gcloud builds submit \
  -t us-central1-docker.pkg.dev/PROJECT_ID/containers/primegen-service:v1 PrimeGenService/

Reemplaza PROJECT_ID por el ID del proyecto Google Cloud.

Cuando se complete la compilación, deberías ver un resultado similar al siguiente:

DONE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ID: a54818cc-5d14-467b-bfda-5fc9590af68c
CREATE_TIME: 2022-07-29T01:48:50+00:00
DURATION: 48S
SOURCE: gs://project-name_cloudbuild/source/1659059329.705219-17aee3a424a94679937a7200fab15bcf.tgz
IMAGES: us-central1-docker.pkg.dev/project-name/containers/primegen-service:v1
STATUS: SUCCESS

Con un Dockerfile, compilaste una imagen de Docker llamada primegen-service y enviaste la imagen a un repositorio de Artifact Registry llamado containers.

Implementa un flujo de trabajo que programa y ejecuta un trabajo de Batch

El siguiente flujo de trabajo programa y ejecuta un trabajo por lotes que ejecuta un contenedor de Docker como seis tareas en paralelo en dos VMs de Compute Engine. El resultado es la generación de seis lotes de números primos, almacenados en un bucket de Cloud Storage.

Console

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

    Ir a Workflows

  2. Haz clic en  Crear.

  3. Ingresa un nombre para el flujo de trabajo nuevo, como batch-workflow.

  4. En la lista Región, selecciona us-central1.

  5. Selecciona la cuenta de servicio que creaste anteriormente.

  6. Haz clic en Siguiente.

  7. En el editor de flujos de trabajo, ingresa la siguiente definición para el flujo de trabajo:

    YAML

    main:
      params: [args]
      steps:
        - init:
            assign:
              - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
              - region: "us-central1"
              - imageUri: ${region + "-docker.pkg.dev/" + projectId + "/containers/primegen-service:v1"}
              - jobId: ${"job-primegen-" + string(int(sys.now()))}
              - bucket: ${projectId + "-" + jobId}
        - createBucket:
            call: googleapis.storage.v1.buckets.insert
            args:
              query:
                project: ${projectId}
              body:
                name: ${bucket}
        - logCreateBucket:
            call: sys.log
            args:
              data: ${"Created bucket " + bucket}
        - logCreateBatchJob:
            call: sys.log
            args:
              data: ${"Creating and running the batch job " + jobId}
        - createAndRunBatchJob:
            call: googleapis.batch.v1.projects.locations.jobs.create
            args:
                parent: ${"projects/" + projectId + "/locations/" + region}
                jobId: ${jobId}
                body:
                  taskGroups:
                    taskSpec:
                      runnables:
                        - container:
                            imageUri: ${imageUri}
                          environment:
                            variables:
                              BUCKET: ${bucket}
                    # Run 6 tasks on 2 VMs
                    taskCount: 6
                    parallelism: 2
                  logsPolicy:
                    destination: CLOUD_LOGGING
            result: createAndRunBatchJobResponse
        # You can delete the batch job or keep it for debugging
        - logDeleteBatchJob:
            call: sys.log
            args:
              data: ${"Deleting the batch job " + jobId}
        - deleteBatchJob:
            call: googleapis.batch.v1.projects.locations.jobs.delete
            args:
                name: ${"projects/" + projectId + "/locations/" + region + "/jobs/" + jobId}
            result: deleteResult
        - returnResult:
            return:
              jobId: ${jobId}
              bucket: ${bucket}

    JSON

    {
      "main": {
        "params": [
          "args"
        ],
        "steps": [
          {
            "init": {
              "assign": [
                {
                  "projectId": "${sys.get_env(\"GOOGLE_CLOUD_PROJECT_ID\")}"
                },
                {
                  "region": "us-central1"
                },
                {
                  "imageUri": "${region + \"-docker.pkg.dev/\" + projectId + \"/containers/primegen-service:v1\"}"
                },
                {
                  "jobId": "${\"job-primegen-\" + string(int(sys.now()))}"
                },
                {
                  "bucket": "${projectId + \"-\" + jobId}"
                }
              ]
            }
          },
          {
            "createBucket": {
              "call": "googleapis.storage.v1.buckets.insert",
              "args": {
                "query": {
                  "project": "${projectId}"
                },
                "body": {
                  "name": "${bucket}"
                }
              }
            }
          },
          {
            "logCreateBucket": {
              "call": "sys.log",
              "args": {
                "data": "${\"Created bucket \" + bucket}"
              }
            }
          },
          {
            "logCreateBatchJob": {
              "call": "sys.log",
              "args": {
                "data": "${\"Creating and running the batch job \" + jobId}"
              }
            }
          },
          {
            "createAndRunBatchJob": {
              "call": "googleapis.batch.v1.projects.locations.jobs.create",
              "args": {
                "parent": "${\"projects/\" + projectId + \"/locations/\" + region}",
                "jobId": "${jobId}",
                "body": {
                  "taskGroups": {
                    "taskSpec": {
                      "runnables": [
                        {
                          "container": {
                            "imageUri": "${imageUri}"
                          },
                          "environment": {
                            "variables": {
                              "BUCKET": "${bucket}"
                            }
                          }
                        }
                      ]
                    },
                    "taskCount": 6,
                    "parallelism": 2
                  },
                  "logsPolicy": {
                    "destination": "CLOUD_LOGGING"
                  }
                }
              },
              "result": "createAndRunBatchJobResponse"
            }
          },
          {
            "logDeleteBatchJob": {
              "call": "sys.log",
              "args": {
                "data": "${\"Deleting the batch job \" + jobId}"
              }
            }
          },
          {
            "deleteBatchJob": {
              "call": "googleapis.batch.v1.projects.locations.jobs.delete",
              "args": {
                "name": "${\"projects/\" + projectId + \"/locations/\" + region + \"/jobs/\" + jobId}"
              },
              "result": "deleteResult"
            }
          },
          {
            "returnResult": {
              "return": {
                "jobId": "${jobId}",
                "bucket": "${bucket}"
              }
            }
          }
        ]
      }
    }
    
  8. Haz clic en Implementar.

gcloud

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

    touch batch-workflow.JSON_OR_YAML

    Reemplaza JSON_OR_YAML por yaml o json, según el formato de tu flujo de trabajo.

  2. En un editor de texto, copia el siguiente flujo de trabajo en tu archivo de código fuente:

    YAML

    main:
      params: [args]
      steps:
        - init:
            assign:
              - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
              - region: "us-central1"
              - imageUri: ${region + "-docker.pkg.dev/" + projectId + "/containers/primegen-service:v1"}
              - jobId: ${"job-primegen-" + string(int(sys.now()))}
              - bucket: ${projectId + "-" + jobId}
        - createBucket:
            call: googleapis.storage.v1.buckets.insert
            args:
              query:
                project: ${projectId}
              body:
                name: ${bucket}
        - logCreateBucket:
            call: sys.log
            args:
              data: ${"Created bucket " + bucket}
        - logCreateBatchJob:
            call: sys.log
            args:
              data: ${"Creating and running the batch job " + jobId}
        - createAndRunBatchJob:
            call: googleapis.batch.v1.projects.locations.jobs.create
            args:
                parent: ${"projects/" + projectId + "/locations/" + region}
                jobId: ${jobId}
                body:
                  taskGroups:
                    taskSpec:
                      runnables:
                        - container:
                            imageUri: ${imageUri}
                          environment:
                            variables:
                              BUCKET: ${bucket}
                    # Run 6 tasks on 2 VMs
                    taskCount: 6
                    parallelism: 2
                  logsPolicy:
                    destination: CLOUD_LOGGING
            result: createAndRunBatchJobResponse
        # You can delete the batch job or keep it for debugging
        - logDeleteBatchJob:
            call: sys.log
            args:
              data: ${"Deleting the batch job " + jobId}
        - deleteBatchJob:
            call: googleapis.batch.v1.projects.locations.jobs.delete
            args:
                name: ${"projects/" + projectId + "/locations/" + region + "/jobs/" + jobId}
            result: deleteResult
        - returnResult:
            return:
              jobId: ${jobId}
              bucket: ${bucket}

    JSON

    {
      "main": {
        "params": [
          "args"
        ],
        "steps": [
          {
            "init": {
              "assign": [
                {
                  "projectId": "${sys.get_env(\"GOOGLE_CLOUD_PROJECT_ID\")}"
                },
                {
                  "region": "us-central1"
                },
                {
                  "imageUri": "${region + \"-docker.pkg.dev/\" + projectId + \"/containers/primegen-service:v1\"}"
                },
                {
                  "jobId": "${\"job-primegen-\" + string(int(sys.now()))}"
                },
                {
                  "bucket": "${projectId + \"-\" + jobId}"
                }
              ]
            }
          },
          {
            "createBucket": {
              "call": "googleapis.storage.v1.buckets.insert",
              "args": {
                "query": {
                  "project": "${projectId}"
                },
                "body": {
                  "name": "${bucket}"
                }
              }
            }
          },
          {
            "logCreateBucket": {
              "call": "sys.log",
              "args": {
                "data": "${\"Created bucket \" + bucket}"
              }
            }
          },
          {
            "logCreateBatchJob": {
              "call": "sys.log",
              "args": {
                "data": "${\"Creating and running the batch job \" + jobId}"
              }
            }
          },
          {
            "createAndRunBatchJob": {
              "call": "googleapis.batch.v1.projects.locations.jobs.create",
              "args": {
                "parent": "${\"projects/\" + projectId + \"/locations/\" + region}",
                "jobId": "${jobId}",
                "body": {
                  "taskGroups": {
                    "taskSpec": {
                      "runnables": [
                        {
                          "container": {
                            "imageUri": "${imageUri}"
                          },
                          "environment": {
                            "variables": {
                              "BUCKET": "${bucket}"
                            }
                          }
                        }
                      ]
                    },
                    "taskCount": 6,
                    "parallelism": 2
                  },
                  "logsPolicy": {
                    "destination": "CLOUD_LOGGING"
                  }
                }
              },
              "result": "createAndRunBatchJobResponse"
            }
          },
          {
            "logDeleteBatchJob": {
              "call": "sys.log",
              "args": {
                "data": "${\"Deleting the batch job \" + jobId}"
              }
            }
          },
          {
            "deleteBatchJob": {
              "call": "googleapis.batch.v1.projects.locations.jobs.delete",
              "args": {
                "name": "${\"projects/\" + projectId + \"/locations/\" + region + \"/jobs/\" + jobId}"
              },
              "result": "deleteResult"
            }
          },
          {
            "returnResult": {
              "return": {
                "jobId": "${jobId}",
                "bucket": "${bucket}"
              }
            }
          }
        ]
      }
    }
    
  3. Para implementar el flujo de trabajo, ingresa el siguiente comando:

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

    Reemplaza SERVICE_ACCOUNT_NAME por el nombre de la cuenta de servicio que creaste anteriormente.

Ejecuta el flujo de trabajo

Ejecuta la definición actual del flujo de trabajo asociada con el flujo de trabajo.

Console

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

    Ir a Workflows

  2. En la página Flujos de trabajo, haz clic en el flujo de trabajo batch-workflow para ir a su página de detalles.

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

  4. Haz clic de nuevo en Ejecutar.

    La ejecución del flujo de trabajo debería tardar unos minutos.

  5. Consulta los resultados del flujo de trabajo en el panel Output.

    Los resultados debería ser similar al siguiente:

    {
      "bucket": "project-name-job-primegen-TIMESTAMP",
      "jobId": "job-primegen-TIMESTAMP"
    }
    

gcloud

  1. Ejecuta el flujo de trabajo:

    gcloud workflows run batch-workflow \
      --location=us-central1

    La ejecución del flujo de trabajo debería tardar unos minutos.

  2. Puedes verificar el estado de una ejecución de larga duración.

  3. Para obtener el estado de la última ejecución completada, ejecuta el siguiente comando:

    gcloud workflows executions describe-last

    Los resultados deberían ser similares a los siguientes:

    name: projects/PROJECT_NUMBER/locations/us-central1/workflows/batch-workflow/executions/EXECUTION_ID
    result: '{"bucket":"project-name-job-primegen-TIMESTAMP","jobId":"job-primegen-TIMESTAMP"}'
    startTime: '2022-07-29T16:08:39.725306421Z'
    state: SUCCEEDED
    status:
      currentSteps:
      - routine: main
        step: returnResult
    workflowRevisionId: 000001-9ba
    

Enumera los objetos del bucket de salida

Para confirmar que los resultados son los esperados, enumera los objetos en tu bucket de salida de Cloud Storage.

Console

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

    Ir a Buckets

  2. En la lista de bucket s, haz clic en el nombre del bucket que posee el contenido que deseas ver.

    Los resultados deberían ser similares a los siguientes, con seis archivos en total y cada uno con un lote de 10,000 números primos:

    primes-1-10000.txt
    primes-10001-20000.txt
    primes-20001-30000.txt
    primes-30001-40000.txt
    primes-40001-50000.txt
    primes-50001-60000.txt
    

gcloud

  1. Recupera el nombre de tu bucket de salida:

    gcloud storage ls

    El resultado es similar a este:

    gs://PROJECT_ID-job-primegen-TIMESTAMP/

  2. Enumera los objetos en tu bucket de salida:

    gcloud storage ls gs://PROJECT_ID-job-primegen-TIMESTAMP/** --recursive

    Reemplaza TIMESTAMP por la marca de tiempo que devolvió el comando anterior.

    El resultado debería ser similar al siguiente, con seis archivos en total y cada uno con una lista de 10,000 números primos:

    gs://project-name-job-primegen-TIMESTAMP/primes-1-10000.txt
    gs://project-name-job-primegen-TIMESTAMP/primes-10001-20000.txt
    gs://project-name-job-primegen-TIMESTAMP/primes-20001-30000.txt
    gs://project-name-job-primegen-TIMESTAMP/primes-30001-40000.txt
    gs://project-name-job-primegen-TIMESTAMP/primes-40001-50000.txt
    gs://project-name-job-primegen-TIMESTAMP/primes-50001-60000.txt