使用 Workflows 執行批次工作


Batch 是一項全代管服務,可讓您在 Compute Engine 虛擬機器 (VM) 執行個體中排定時間、排入佇列和執行批次處理工作負載。Batch 會代您佈建資源並管理容量,讓批次工作負載大規模執行。

Workflows 可讓您按照您使用 Workflows 語法定義的順序,執行所需的服務。

在本教學課程中,您將使用 Workflows for Batch 連接器來排程及執行 Batch 工作,在兩個 Compute Engine VM 上並行執行六項工作。同時使用 Batch 和 Workflows,您就能同時享有兩者帶來的優勢,並有效地佈建及調度整個程序。

目標

教學課程內容:

  1. 為 Docker 容器映像檔建立 Artifact Registry 存放區。
  2. 從 GitHub 取得批次處理工作負載的程式碼:這個範例程式會以 10,000 的批次產生質數。
  3. 建構工作負載的 Docker 映像檔。
  4. 部署並執行可執行下列操作的工作流程:
    1. 建立 Cloud Storage 值區,用於儲存素數產生器的結果。
    2. 排定並執行批次工作,以便在兩個 Compute Engine VM 上以六個工作並行執行 Docker 容器。
    3. 可在批次工作完成後刪除。
  5. 確認結果是否符合預期,並且產生的質數批次已儲存在 Cloud Storage 中。

您可以在 Google Cloud 主控台中執行下列大部分指令,也可以在終端機或 Cloud Shell 中使用 Google Cloud CLI 執行所有指令。

費用

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use the pricing calculator. New Google Cloud users might be eligible for a free trial.

事前準備

貴機構定義的安全性限制,可能會導致您無法完成下列步驟。如需疑難排解資訊,請參閱「在受限的 Google Cloud 環境中開發應用程式」。

主控台

  1. 在 Google Cloud 主控台的專案選擇器頁面中,選取或建立 Google Cloud 專案

    前往專案選取器

  2. 請確認您已為 Google Cloud 專案啟用計費功能。瞭解如何檢查專案是否已啟用計費功能

  3. 啟用 Artifact Registry、Batch、Cloud Build、Compute Engine、Workflow Executions 和 Workflows API。

    啟用 API

  4. 建立服務帳戶,讓工作流程用於與其他 Google Cloud 服務進行驗證,並授予適當的角色:

    1. 前往 Google Cloud 控制台的「Create service account」(建立服務帳戶) 頁面。

      前往「Create service account」(建立服務帳戶)

    2. 選取專案。

    3. 在「Service account name」(服務帳戶名稱) 欄位中輸入名稱。 Google Cloud 控制台會根據這個名稱填入「Service account ID」欄位。

      在「服務帳戶說明」欄位中輸入說明。例如:Service account for tutorial

    4. 按一下「建立並繼續」

    5. 在「Select a role」(請選擇角色) 清單中,篩選下列角色,將這些角色授予您在先前步驟中建立的使用者管理服務帳戶:

      • 批次工作編輯器:用於編輯批次工作。
      • 記錄寫入者:用於寫入記錄。
      • Storage 管理員:控管 Cloud Storage 資源。

      如要新增其他角色,請按一下 「Add another role」(新增其他角色),然後新增其他角色。

    6. 按一下「繼續」

    7. 按一下「完成」,即可完成帳戶建立程序。

  5. 將預設服務帳戶的 IAM 服務帳戶使用者角色,授予先前步驟中建立的使用者管理服務帳戶。啟用 Compute Engine API 後,預設服務帳戶即為 Compute Engine 預設服務帳戶 (PROJECT_NUMBER-compute@developer.gserviceaccount.com),而權限通常會透過 roles/iam.serviceAccountUser 角色指派。

    1. 在「Service Accounts」(服務帳戶) 頁面中,按一下預設服務帳戶 (PROJECT_NUMBER-compute@developer.gserviceaccount.com) 的電子郵件地址。

    2. 按一下「Permissions」(權限) 分頁標籤。

    3. 按一下 「授予存取權」按鈕。

    4. 如要新增主體,請輸入服務帳戶 (SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com) 的電子郵件地址。

    5. 在「Select a role」清單中,依序選取「Service Accounts」>「Service Account User」角色。

    6. 按一下 [儲存]

gcloud

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. 請確認您已為 Google Cloud 專案啟用計費功能。瞭解如何檢查專案是否已啟用計費功能

  3. 啟用 Artifact Registry、Batch、Cloud Build、Compute Engine 工作流程執行作業和 Workflows API。

    gcloud services enable artifactregistry.googleapis.com \
      batch.googleapis.com \
      cloudbuild.googleapis.com \
      compute.googleapis.com \
      workflowexecutions.googleapis.com \
      workflows.googleapis.com
  4. 為工作流程建立服務帳戶,用於與其他 Google Cloud 服務進行驗證,並授予適當的角色。

    1. 建立服務帳戶:

      gcloud iam service-accounts create SERVICE_ACCOUNT_NAME

      SERVICE_ACCOUNT_NAME 換成服務帳戶的名稱。

    2. 將角色授予您在先前步驟中建立的使用者自行管理的服務帳戶。針對下列每個 IAM 角色執行下列指令一次:

      • roles/batch.jobsEditor:編輯批次工作。
      • roles/logging.logWriter:寫入記錄。
      • roles/storage.admin:用於控制 Cloud Storage 資源。
      gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --role=ROLE

      更改下列內容:

      • PROJECT_ID:您建立服務帳戶的專案 ID
      • ROLE:要授予的角色
  5. 將預設服務帳戶的 IAM 服務帳戶使用者角色,授予您在前一個步驟中建立的使用者管理服務帳戶。啟用 Compute Engine API 後,預設服務帳戶即為 Compute Engine 預設服務帳戶 (PROJECT_NUMBER-compute@developer.gserviceaccount.com),而權限通常會透過 roles/iam.serviceAccountUser 角色指派。

    PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)')
    gcloud iam service-accounts add-iam-policy-binding \
      $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/iam.serviceAccountUser

建立 Artifact Registry 存放區

建立存放區來儲存 Docker 容器映像檔。

主控台

  1. 在 Google Cloud 控制台中,前往「Repositories」頁面。

    前往「存放區」

  2. 按一下 「Create Repository」(建立存放區)

  3. 輸入「containers」做為存放區名稱。

  4. 在「格式」部分,選擇「Docker」

  5. 在「位置類型」中,選擇「區域」

  6. 在「Region」(區域) 清單中選取「us-central1」

  7. 按一下 [建立]。

gcloud

執行下列指令:

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

您已在 us-central1 區域中建立名為 containers 的 Artifact Registry 存放區。如要進一步瞭解支援的地區,請參閱「Artifact Registry 位置」。

取得程式碼範例

Google Cloud 會將本教學課程的應用程式原始碼儲存在 GitHub 中。您可以複製該存放區或下載範例。

  1. 將應用程式存放區範例複製到本機電腦中:

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

    您也可以下載 main.zip 檔案中的範例,然後解壓縮該檔案。

  2. 變更為包含範例程式碼的目錄:

    cd batch-samples/primegen
    

您現在已在開發環境中取得應用程式的原始碼。

使用 Cloud Build 建構 Docker 映像檔

Dockerfile 包含使用 Cloud Build 建構 Docker 映像檔所需的資訊。執行下列指令來建構:

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

PROJECT_ID 替換為您的 Google Cloud專案 ID。

建構完成後,畫面會顯示類似以下的輸出:

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

您已使用 Dockerfile 建構名為 primegen-service 的 Docker 映像檔,並將該映像檔推送至名為 containers 的 Artifact Registry 存放區。

部署可排定及執行 Batch 工作的工作流程

下列工作流程會排定並執行批次工作,以便在兩個 Compute Engine VM 上以六個工作並行執行 Docker 容器。結果是產生六批質數,並儲存在 Cloud Storage 值區中。

控制台

  1. 前往 Google Cloud 控制台的「Workflows」頁面。

    前往「Workflows」頁面

  2. 按一下「建立」

  3. 輸入新工作流程的名稱,例如 batch-workflow

  4. 在「Region」(區域) 清單中選取「us-central1」

  5. 選取先前建立的「Service account」(服務帳戶)

  6. 點按「Next」

  7. 在工作流程編輯器中,輸入工作流程的定義:

    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. 按一下 [Deploy] (部署)

gcloud

  1. 建立工作流程的原始碼檔案:

    touch batch-workflow.JSON_OR_YAML

    視工作流程的格式而定,將 JSON_OR_YAML 替換為 yamljson

  2. 在文字編輯器中,將下列工作流程複製到原始碼檔案:

    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. 輸入下列指令來部署工作流程:

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

    SERVICE_ACCOUNT_NAME 替換為您先前建立的服務帳戶名稱。

執行工作流程

執行工作流程會執行與工作流程相關聯的目前工作流程定義。

控制台

  1. 前往 Google Cloud 控制台的「Workflows」頁面。

    前往「Workflows」頁面

  2. 在「Workflows」頁面中,按一下「batch-workflow」工作流程,前往詳細資料頁面。

  3. 在「Workflow details」(工作流程詳細資料)頁面中,按一下 「Execute」(執行)

  4. 再次按一下「執行」

    工作流程執行作業應會在幾分鐘內完成。

  5. 在「Output」窗格中查看工作流程的結果。

    結果應如下所示:

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

gcloud

  1. 執行工作流程:

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

    工作流程執行作業應會在幾分鐘內完成。

  2. 您可以檢查長時間執行作業的狀態

  3. 如要取得上次完成執行作業的狀態,請執行下列指令:

    gcloud workflows executions describe-last

    結果應類似於以下內容:

    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
    

列出輸出值區中的物件

您可以列出 Cloud Storage 輸出值區中的物件,確認結果是否符合預期。

控制台

  1. 在 Google Cloud 控制台,前往 Cloud Storage「Buckets」頁面。

    前往「Buckets」(值區) 頁面

  2. 在值區清單中,按一下要查看內容的值區名稱。

    結果應類似於以下內容,總共六個檔案,每個檔案列出一批 10,000 個質數:

    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. 擷取輸出值區名稱:

    gcloud storage ls

    輸出結果會與下列內容相似:

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

  2. 列出輸出值區中的物件:

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

    TIMESTAMP 替換為上一個指令傳回的時間戳記。

    輸出內容應類似於以下內容,總共六個檔案,每個檔案列出 10,000 個質數:

    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
    

清除所用資源

如果您是為了這個教學課程建立新專案,請刪除專案。如果您使用現有的專案,且希望保留該專案而不採用本教學課程中新增的變更,請刪除為教學課程建立的資源

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

如要刪除專案:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

刪除本教學課程中建立的資源

  1. 刪除 Batch 工作:

    1. 首先擷取工作名稱:

      gcloud batch jobs list --location=us-central1

      畫面會顯示如下的輸出內容:

      NAME: projects/project-name/locations/us-central1/jobs/job-primegen-TIMESTAMP
      STATE: SUCCEEDED
      

      其中 job-primegen-TIMESTAMP 是批次作業的名稱。

    2. 刪除工作:

      gcloud batch jobs delete BATCH_JOB_NAME --location us-central1
  2. 刪除工作流程:

    gcloud workflows delete WORKFLOW_NAME
  3. 刪除容器存放區:

    gcloud artifacts repositories delete REPOSITORY_NAME --location=us-central1
  4. Cloud Build 會使用 Cloud Storage 儲存建構資源。如要刪除 Cloud Storage 值區,請參閱刪除值區

後續步驟