AWS Batch でジョブを実行する前処理としてLambda の実行結果(出力した値)を使って AWS Batch でジョブを実行したいです。
このような制御する場合は何かしらのワークフローが必要になるため、Step Functions を利用するのが一般的かと思います。
AWS Batch のジョブ実行をキックする Lambda を書くつもりでいたのですが、Workflow Studio で Batch と検索するとSubmitJob という「顧客(私)が本当に必要だったもの」と思われるものが用意されていました。
SubmitJobの使用感確認のために Step Fuctions のワークフローでSubmitJobを利用して、AWS Batch のジョブを実行できるのかをやってみました。
各種設定
Lambda の実行結果(出力した値)を AWS Batch のジョブ実行時に渡す検証として以下のワークフローを作成します。Lambda と AWS Batch、そして、Step Functions で必要になった主要な設定を記載します。
Lambda の設定
Lambda 関数はreturn
に固定値を返すだけの関数を用意しました。
def lambda_handler(event, context):
return {
'statusCode': 200,
'target': '/path/sample.txt'
}
テスト実行した結果は以下になります。target
キーの値を AWS Batch に引き渡します。
実行結果
{
"statusCode": 200,
"target": "/path/sample.txt"
}
AWW Batch の設定
パラメーターMessage
を用意し、Step Functions からMessage
の値を書き換えます。ジョブを実行するとecho Ref::Message
でMessage
の内容を標準出力に返します。デフォルト値としてhi
を入力しています。
AWS BatchでRef::
はパラメーターの値を使うプレースホルダーの記述です。
ジョブ定義全文
{
"jobDefinitions": [
{
"jobDefinitionName": "fagate-sfn",
"jobDefinitionArn": "arn:aws:batch:ap-northeast-1:123456789012:job-definition/fagate-sfn:1",
"revision": 1,
"status": "ACTIVE",
"type": "container",
"parameters": {
"Message": "hi"
},
"containerProperties": {
"image": "public.ecr.aws/amazonlinux/amazonlinux:latest",
"command": [
"echo",
"Ref::Message"
],
"jobRoleArn": "arn:aws:iam::123456789012:role/batch-test-BatchTaskExecutionRole",
"executionRoleArn": "arn:aws:iam::123456789012:role/batch-test-BatchTaskExecutionRole",
"volumes": [],
"environment": [],
"mountPoints": [],
"ulimits": [],
"resourceRequirements": [
{
"value": "1.0",
"type": "VCPU"
},
{
"value": "2048",
"type": "MEMORY"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {},
"secretOptions": []
},
"secrets": [],
"networkConfiguration": {
"assignPublicIp": "ENABLED"
},
"fargatePlatformConfiguration": {
"platformVersion": "LATEST"
}
},
"tags": {},
"platformCapabilities": [
"FARGATE"
],
"containerOrchestrationType": "ECS"
}
]
}
ジョブ定義の JSON 出力方法
aws batch describe-job-definitions
コマンドで出力できます。
`aws batch describe-job-definitions --job-definition-name [INPUT_NAME]`
Step Functions の設定
ワークフローは Lambda を実行した後に、AWS Batch でジョブを実行する直列なフローを作成しました。
今回の検証ポイント
Lambda の実行結果を$
とし、SubmitJob 実行のパラメーターで$.target
としています。Lambda の実行結果target
の値がMessage
パラメーターの値になっています。
AWS Batch のジョブ定義ではMessage
の値を echo コマンドで標準出力に返すだけですので、Lambda の実行結果であるtarget
の値が AWS Batch で実行したコンテナの標準出力に表示される寸法です。
InputPath、パラメータ、ResultSelector - AWS Step Functions
ここが今回の検証したかった SubmitJob へ必要なパラメーターの渡し方と、AWS Batch のジョブ定義で Step Functions のワークフローから受け取った値を利用する方法です。
ワークフロー定義全文
{
"Comment": "A description of my state machine",
"StartAt": "Pass the result",
"States": {
"Pass the result": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"OutputPath": "$.Payload",
"Parameters": {
"Payload.$": "$",
"FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:test-sfn-in-out-value:$LATEST"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"Next": "Batch SubmitJob"
},
"Batch SubmitJob": {
"Type": "Task",
"Resource": "arn:aws:states:::batch:submitJob.sync",
"Parameters": {
"JobName": "fargate-test",
"JobDefinition": "arn:aws:batch:ap-northeast-1:123456789012:job-definition/fagate-sfn:1",
"JobQueue": "arn:aws:batch:ap-northeast-1:123456789012:job-queue/fargate-queue",
"Parameters": {
"Message.$": "$.target"
}
},
"End": true
}
}
}
以上が主要な設定内容でした。
ワークフローを実行してみる
ワークフローを実行し正常に終了しました。結果を確認します。
Lambda の実行結果
Lambda の出力タブにはtarget
の値を固定値(/path/sample.txt
)で返した内容を確認できます。
AWS Batch の実行結果
AWS Batch の入力タブには Lambda の出力内容がそのまま渡されています。
出力タブの内容は画像で収まらないので出力結果(JSON形式)を書き出します。
ジョブ定義のパラメーターでプレースホルダーとしていた$.target
の箇所が/path/sample.txt
に置き換わっており期待した結果になっています。
{
"Attempts": [
{
"Container": {
"ExitCode": 0,
"LogStreamName": "fagate-sfn/default/a07ea7aef82e4a04ba5237ce4f320c09",
"NetworkInterfaces": [
{
"AttachmentId": "679f1438-636b-4fd7-a540-410057a2779f",
"PrivateIpv4Address": "10.0.1.87"
}
],
"TaskArn": "arn:aws:ecs:ap-northeast-1:123456789012:task/AWSBatch-fargate-1a-846f808b-7caf-35a9-9192-292884f9bd46/a07ea7aef82e4a04ba5237ce4f320c09"
},
"StartedAt": 1689557537640,
"StatusReason": "Essential container in task exited",
"StoppedAt": 1689557560856
}
],
"Container": {
"Command": [
"echo",
"/path/sample.txt"
],
"Environment": [
{
"Name": "MANAGED_BY_AWS",
"Value": "STARTED_BY_STEP_FUNCTIONS"
}
],
"ExecutionRoleArn": "arn:aws:iam::123456789012:role/batch-test-BatchTaskExecutionRole",
"ExitCode": 0,
"FargatePlatformConfiguration": {
"PlatformVersion": "LATEST"
},
"Image": "public.ecr.aws/amazonlinux/amazonlinux:latest",
"JobRoleArn": "arn:aws:iam::123456789012:role/batch-test-BatchTaskExecutionRole",
"LogConfiguration": {
"LogDriver": "awslogs",
"Options": {},
"SecretOptions": []
},
"LogStreamName": "fagate-sfn/default/a07ea7aef82e4a04ba5237ce4f320c09",
"MountPoints": [],
"NetworkConfiguration": {
"AssignPublicIp": "ENABLED"
},
"NetworkInterfaces": [
{
"AttachmentId": "679f1438-636b-4fd7-a540-410057a2779f",
"PrivateIpv4Address": "10.0.1.87"
}
],
"ResourceRequirements": [
{
"Type": "VCPU",
"Value": "1.0"
},
{
"Type": "MEMORY",
"Value": "2048"
}
],
"Secrets": [],
"TaskArn": "arn:aws:ecs:ap-northeast-1:123456789012:task/AWSBatch-fargate-1a-846f808b-7caf-35a9-9192-292884f9bd46/a07ea7aef82e4a04ba5237ce4f320c09",
"Ulimits": [],
"Volumes": []
},
"CreatedAt": 1689557509347,
"DependsOn": [],
"EksAttempts": [],
"JobArn": "arn:aws:batch:ap-northeast-1:123456789012:job/cb13b2a9-0bd2-490f-b3cb-a24948849bde",
"JobDefinition": "arn:aws:batch:ap-northeast-1:123456789012:job-definition/fagate-sfn:1",
"JobId": "cb13b2a9-0bd2-490f-b3cb-a24948849bde",
"JobName": "fargate-test",
"JobQueue": "arn:aws:batch:ap-northeast-1:123456789012:job-queue/fargate-queue",
"Parameters": {
"Message": "/path/sample.txt"
},
"PlatformCapabilities": [
"FARGATE"
],
"StartedAt": 1689557537640,
"Status": "SUCCEEDED",
"StatusReason": "Essential container in task exited",
"StoppedAt": 1689557560856,
"Tags": {
"resourceArn": "arn:aws:batch:ap-northeast-1:123456789012:job/cb13b2a9-0bd2-490f-b3cb-a24948849bde"
}
}
AWS Batch で実行したジョブの内容は echo コマンドで、パラメーターMessage
の値(ここで期待するのは/path/sample.txt
)を標準出力に返すといった内容でした。
実際の AWS Batch の実行ログを確認します。Step Functions の実行結果から AWS Batch のログを確認するリンクが貼られています。
AWS Batch で実行したジョブのログを確認すると/path/sample.txt
の文字列を確認できました。
これで Lambda の実行結果の値を Step Functions の SumitJob を利用して AWS Batch のジョブ実行時に利用する動作確認が取れました。
おわりに
AWS Batch のジョブを実行開始するだけのために Lambda を用意しなくても良い時代になっていました。込み入ったジョブの実行の仕方だと引き続き Lambda から AWS Batch の SDK を使って API を叩くことになりますが、まずは Step Fuctions の SubmitJob を利用して実行できないか検討してみると良いのでないでしょうか。Lambda を省略できるならより運用負荷を削減できますよ。
他にも Lambda なしで実行できるものないか探してみてください。