Workflows を使用して Batch ジョブを実行する

Batch は、Compute Engine 仮想マシン(VM)インスタンスでバッチ処理ワークロードのスケジューリング、キューイング、実行を行えるフルマネージド サービスです。Batch がお客様に代わってリソースをプロビジョニングし、容量を管理することで、バッチ ワークロードを大規模に実行できます。

Workflows では、Workflows の構文を使用して定義した順序で必要なサービスを実行できます。

このチュートリアルでは、Batch 用 Workflows コネクタを使用して、2 つの Compute Engine VM で 6 つのタスクを同時に実行する Batch ジョブをスケジュール設定して実行します。Batch と Workflows の両方を使用すると、それぞれの利点を享受し、プロセス全体を効率的にプロビジョニングしてオーケストレートできます。

目標

このチュートリアルの内容は次のとおりです。

  1. Docker コンテナ イメージ用の Artifact Registry リポジトリを作成します。
  2. GitHub からバッチ処理ワークロードのコードを取得します。これは、10,000 個の素数をバッチで生成するサンプル プログラムです。
  3. ワークロードの Docker イメージをビルドします。
  4. 次の処理を行うワークフローをデプロイして実行します。
    1. 素数ジェネレータの結果を保存する Cloud Storage バケットを作成します。
    2. 2 つの Compute Engine VM で Docker コンテナを 6 つのタスクとして並列に実行する Batch ジョブをスケジュールして実行します。
    3. 必要に応じて、完了後に Batch ジョブを削除します。
  5. 結果が想定どおりであること、および生成されたプライム番号のバッチが Cloud Storage に保存されていることを確認します。

次のコマンドのほとんどは Google Cloud コンソールで実行できます。また、すべてのコマンドはターミナルまたは Cloud Shell で Google Cloud CLI を使用して実行できます。

費用

このドキュメントでは、課金対象である次の Google Cloudコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。

新規の Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

組織で定義されているセキュリティの制約により、次の手順を完了できない場合があります。トラブルシューティング情報については、制約のある Google Cloud 環境でアプリケーションを開発するをご覧ください。

コンソール

  1. Google Cloud コンソールのプロジェクト セレクタ ページで、 Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  2. Google Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。

  3. Artifact Registry API、Batch API、Cloud Build API、Compute Engine API、Workflow Execution API、Workflows API を有効にします。

    API を有効にする

  4. 他の Google Cloud サービスでの認証に使用するワークフローのサービス アカウントを作成し、適切なロールを付与します。

    1. Google Cloud コンソールで、[サービス アカウントの作成] ページに移動します。

      [サービス アカウントの作成] に移動

    2. プロジェクトを選択します。

    3. [サービス アカウント名] フィールドに名前を入力します。 Google Cloud コンソールでは、この名前に基づいて [サービス アカウント ID] フィールドの値が設定されます。

      [サービス アカウントの説明] フィールドに説明を入力します。例: Service account for tutorial

    4. [作成して続行] をクリックします。

    5. [ロールを選択] リストで、次のロールをフィルタして、前の手順で作成したユーザー管理のサービス アカウントに付与します。

      • バッチジョブ編集者: バッチジョブを編集します。
      • ログ書き込み: ログを書き込みます。
      • ストレージ管理者: Cloud Storage リソースを制御します。

      ロールを追加するには、[別のロールを追加] をクリックして各ロールを追加します。

    6. [続行] をクリックします。

    7. アカウントの作成を完了するには、[完了] をクリックします。

  5. デフォルトのサービス アカウントに対する IAM サービス アカウント ユーザーのロールを、前の手順で作成したユーザー管理のサービス アカウントに付与します。Compute Engine API を有効にすると、デフォルトのサービス アカウントは Compute Engine のデフォルトのサービス アカウント(PROJECT_NUMBER-compute@developer.gserviceaccount.com)になり、権限は通常、roles/iam.serviceAccountUser ロールによって割り当てられます。

    1. [サービス アカウント] ページで、デフォルトのサービス アカウント(PROJECT_NUMBER-compute@developer.gserviceaccount.com)のメールアドレスをクリックします。

    2. [権限] タブをクリックします。

    3. [アクセスを許可] ボタンをクリックします。

    4. 新しいプリンシパルを追加するには、サービス アカウントのメールアドレス(SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com)を入力します。

    5. [ロールを選択] リストで、[サービス アカウント] > [サービス アカウント ユーザー] ロールを選択します。

    6. [保存] をクリックします。

gcloud

  1. Google Cloud コンソールで Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

    Google Cloud コンソールの下部にある Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。Google Cloud CLI がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。

  2. Google Cloud プロジェクトで課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。

  3. Artifact Registry API、Batch API、Cloud Build API、Compute Engine API、Workflow Execution API、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 ロールごとに次のコマンドを 1 回実行します。

      • 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 コンソールで、[リポジトリ] ページに移動します。

    [リポジトリ] に移動

  2. [リポジトリを作成] をクリックします。

  3. リポジトリ名として「containers」と入力します。

  4. [形式] は [Docker] を選択します。

  5. [ロケーション タイプ] で、[リージョン] を選択します。

  6. [リージョン] リストで [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 リポジトリに push しました。

Batch ジョブをスケジュール設定して実行するワークフローをデプロイする

次のワークフローは、2 つの Compute Engine VM で 6 つのタスクとして Docker コンテナを並列に実行する Batch ジョブをスケジュールして実行します。結果として、6 個の素数のバッチが生成され Cloud Storage バケットに格納されます。

コンソール

  1. Google Cloud コンソールで [ワークフロー] ページに移動します。

    [ワークフロー] に移動

  2. [ 作成] をクリックします。

  3. 新しいワークフローの名前を入力します(例: batch-workflow)。

  4. [リージョン] リストで [us-central1] を選択します。

  5. 先ほど作成したサービス アカウントを選択します。

  6. [次へ] をクリックします。

  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": [