API Gateway + LambdaでAWS BatchのJobを実行する

こんにちは、菊池です。

API GatewayとLambdaで構成するAPIから、AWS Batchのジョブを実行する環境を作成してみました。Lambdaには向いていない長時間の処理などを、非同期にBatchで実行することで、スケーラブルなジョブ実行環境にできないかと思いました。

API Gateway + LambdaからBatch Jobを実行する

構成イメージは以下のようになります。

batch-with-api-001

APIに対しリクエストを行うと、Lambda関数はBatchに対しジョブの実行を要求し、すぐにレスポンスを返します。Batchはその後、APIのリクエストとは非同期でジョブを実行します。

ElasticBeanstalkのworker環境や、StepFunctionsに実装したActivity State Machineの呼び出しでも、非同期にEC2上のアプリケーションを実行することは可能です。しかし、Batchを使うことで、ジョブの要求数に応じて環境をスケールさせて実行することができます。

構築

以下の順で構築していきます。

  1. Batch環境の作成
  2. Lambda関数の作成
  3. API Gatewaの作成

AWS Batchの準備

今回は特に処理内容はなんでもよかったので、以下の記事の手順でBatchのジョブキュー/ジョブ定義を作成しました。

次のLambda関数の作成で、ジョブキューのARNを指定する必要がありますが、マネジメントコンソールからは確認できませんでした。AWS CLIのdescribe-job-queuesで取得することができます。

$ aws batch describe-job-queues
{
    "jobQueues": [
        {
            "status": "VALID",
            "jobQueueArn": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:job-queue/first-run-job-queue",
            "computeEnvironmentOrder": [
                {
                    "computeEnvironment": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:compute-environment/first-run-compute-environment",
                    "order": 1
                }
            ],
            "statusReason": "JobQueue Healthy",
            "priority": 1,
            "state": "ENABLED",
            "jobQueueName": "first-run-job-queue"
        }
    ]
}

Lambda関数の作成

Batchに対してJobをサブミットするLambda関数を用意します。Python 3.6のランタイムで以下のような関数を作成しました。

import boto3

def lambda_handler(event, context):

    client = boto3.client('batch')

    JOB_NAME = event['JobNeme']
    JOB_QUEUE = "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:job-queue/first-run-job-queue"
    JOB_DEFINITION = "first-run-job-definition:1"

    response = client.submit_job(
        jobName = JOB_NAME,
        jobQueue = JOB_QUEUE,
        jobDefinition = JOB_DEFINITION
        )
    print(response)
    return 0

Jobを実行するだけの関数です。JobNameのみリクエストから受け取るようにしています。

関数のロールには、AWS BatchのSubmitJobの実行権限を持つIAMポリシーをアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "batch:SubmitJob"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

API Gatewayの作成

続いて、API Gatewayの作成です。

API Gatewayのマネジメントコンソールで、[新しいAPIの作成]からAPIとリソースを作成します。以下の記事を合わせて参照ください。

作成したリソースに、[メソッドの作成]からPOSTメソッドを作成し、セットアップします。[統合タイプ]にLambda関数を選択し、先ほど作成した関数を指定します。

batch-with-api-002

メソッドが作成されました。次に、[アクション]から[APIのデプロイ]を選びます。ステージを選択すれば完了です。

batch-with-api-003

APIが呼び出し可能になりました。APIのURLが確認できます。

batch-with-api-004

実行してみる

それでは実行してみます。curlコマンドで作成したURLにPOSTします。

$ curl -X POST -d '{ "JobNeme" : "test" }' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/testbatch

実行されたJobはAWS Batchのコンソールから確認できます。APIからの呼び出し直後は、RUNABLEのステータスです。

batch-with-api-005

環境で定義したEC2の起動されると、ジョブが実行されます。しばらくすると、ステータスがSUCCEEDEDになりました。ジョブが完了したようです。

batch-with-api-006

これで、APIから呼び出し可能な、スケーラブルなジョブ環境が構築できました。

まとめ

以上です。あとは、Batchジョブにアプリケーションを乗せることで、処理の実行が可能です。処理が非同期化されますので、完了時にSNSのプッシュなどを組み合わせると良いでしょう。

参考リンク