Executar um job em lote usando o Workflows

O Batch é um serviço totalmente gerenciado que permite programar, enfileirar e executar cargas de trabalho de processamento em lote em instâncias de máquina virtual (VM) do Compute Engine. O Batch provisiona recursos e gerencia a capacidade em seu nome, permitindo que suas cargas de trabalho em lote sejam executadas em escala.

Com o Workflows, é possível executar os serviços necessários em uma ordem definida por você, descrita usando a sintaxe do Workflows.

Neste tutorial, você vai usar o conector do Workflows para o Batch a fim de programar e executar um job do Batch que executa seis tarefas em paralelo em duas VMs do Compute Engine. Usar o Batch e Workflows permite combinar as vantagens que eles oferecem e provisionar e orquestrar todo o processo de maneira eficiente.

Crie um repositório do Artifact Registry

Crie um repositório para armazenar a imagem do contêiner do Docker.

Console

  1. No console do Google Cloud , acesse a página Repositórios.

    Acessar repositórios

  2. Clique em Criar repositório.

  3. Insira containers como o nome do repositório.

  4. Em Formato, escolha Docker.

  5. Em Tipo de local, escolha Região.

  6. Na lista Região, selecione us-central1.

  7. Clique em Criar.

gcloud

Execute este comando:

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

Você criou um repositório do Artifact Registry chamado containers na região us-central1. Para mais informações sobre regiões compatíveis, consulte Locais do Artifact Registry.

Acessar os exemplos de código

OGoogle Cloud armazena o código-fonte do aplicativo deste tutorial no GitHub. Você pode clonar esse repositório ou fazer o download das amostras.

  1. Clone o repositório do app de amostra na máquina local:

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

    Outra opção é fazer o download das amostras no arquivo main.zip e extraí-las.

  2. Acesse o diretório que contém o exemplo de código:

    cd batch-samples/primegen
    

Agora você tem o código-fonte do aplicativo no ambiente de desenvolvimento.

Criar a imagem do Docker usando o Cloud Build

O Dockerfile contém as informações necessárias para criar uma imagem do Docker usando o Cloud Build. Execute o comando a seguir para criar o binário:

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

Substitua PROJECT_ID pelo ID do projeto do Google Cloud.

Quando a build for concluída, você verá uma resposta semelhante a esta:

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

Usando um Dockerfile, você criou uma imagem do Docker chamada primegen-service e a enviou para um repositório do Artifact Registry chamado containers.

Implantar um fluxo de trabalho que programa e executa um job do Batch

O fluxo de trabalho a seguir programa e executa um job do Batch que executa um contêiner do Docker como seis tarefas em paralelo em duas VMs do Compute Engine. O resultado é a geração de seis lotes de números primos, armazenados em um bucket do Cloud Storage.

Console

  1. No console Google Cloud , acesse a página Fluxos de trabalho.

    Acessar fluxos de trabalho

  2. Clique em Criar.

  3. Insira um nome para o novo fluxo de trabalho, como batch-workflow.

  4. Na lista Região, selecione us-central1.

  5. Selecione a conta de serviço que você criou.

  6. Clique em Próxima.

  7. No editor de fluxo de trabalho, insira a seguinte definição:

    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. Clique em Implantar.

gcloud

  1. Crie um arquivo de código-fonte para seu fluxo de trabalho:

    touch batch-workflow.JSON_OR_YAML

    Substitua JSON_OR_YAML por yaml ou json, dependendo do formato do fluxo de trabalho.

  2. Em um editor de texto, copie o seguinte fluxo de trabalho para o arquivo de código-fonte:

    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. Implante o fluxo de trabalho digitando o seguinte comando:

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

    Substitua SERVICE_ACCOUNT_NAME pelo nome da conta de serviço que você criou anteriormente.

Executar o fluxo de trabalho

Quando um fluxo de trabalho é executado, a definição atual associada a ele também é.

Console

  1. No console Google Cloud , acesse a página Fluxos de trabalho.

    Acessar fluxos de trabalho

  2. Na página Fluxos de trabalho, clique no fluxo de trabalho batch-workflow para acessar a página de detalhes dele.

  3. Na página Detalhes do fluxo de trabalho, clique em Executar.

  4. Clique em Executar novamente.

    A execução do fluxo de trabalho leva alguns minutos.

  5. Veja os resultados do fluxo de trabalho no painel Saída.

    A resposta deve ficar assim:

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

gcloud

  1. Execute o fluxo de trabalho:

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

    A execução do fluxo de trabalho leva alguns minutos.

  2. É possível verificar o status de uma execução de longa duração.

  3. Para ver o status da última execução concluída, execute o seguinte comando:

    gcloud workflows executions describe-last

    Os resultados serão semelhantes a estes:

    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
    

Listar os objetos no bucket de saída

É possível confirmar se os resultados estão conforme o esperado listando os objetos no bucket de saída do Cloud Storage.

Console

  1. No console do Google Cloud , acesse a página Buckets do Cloud Storage.

    Acessar buckets

  2. Na lista de buckets, clique no nome do bucket cujo conteúdo você quer visualizar.

    Os resultados serão semelhantes a este, com seis arquivos no total e cada um listando um 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. Recupere o nome do bucket de saída:

    gcloud storage ls

    A saída será assim:

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

  2. Liste os objetos no bucket de saída.

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

    Substitua TIMESTAMP pelo carimbo de data/hora retornado pelo comando anterior.

    A saída será semelhante a esta, com seis arquivos no total, e cada um listando um lote 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