AWS Batch の配列ジョブの挙動が確認できるチュートリアルをやってみた
コンバンハ、千葉(幸)です。
AWS Batch には配列ジョブという考え方があり、ひとつのジョブの中で 2 ~ 10,000 の子ジョブを生成できます。
それぞれの子ジョブには環境変数AWS_BATCH_JOB_ARRAY_INDEX
がセットされ自身の配列ジョブの番号が提供されます。その環境変数を利用して処理の振り分けを行う、という挙動を試せるチュートリアルがありましたのでやってみました。
配列ジョブチュートリアルでやること
以下を行います。
- コンテナイメージの作成
- Amazon ECR へのイメージのプッシュ
- AWS Batch ジョブ定義の登録
- AWS Bacth ジョブの送信
- 配列ジョブの確認
実行元の環境が必要となるのですが、今回は AWS Cloud9 環境を使いました。
AWS CLI と Docker が使用できればどこでも問題ありません。
配列ジョブチュートリアル事前準備
チュートリアルに入る前に事前に済ませておく必要があるタスクがいくつかあります。
実行環境の作成
先述の通り今回は AWS Clou9 を使用します。サクッと作れて AWS CLI も Docker も準備されているのが助かります。
以下の条件で作成しています。
項目 | 値 |
---|---|
環境タイプ | EC2(直接接続) |
インスタンスタイプ | t3.small |
プラットフォーム | Amazon Linux2 |
Cloud9 を使用するユーザー(IAMロール)には AdministratorAccess を割り当てています。
AWS CLI と Docker のバージョンは以下の通りでした。
$ aws --version aws-cli/1.19.112 Python/2.7.18 Linux/4.14.262-200.489.amzn2.x86_64 botocore/1.20.112 $ docker -v Docker version 20.10.7, build f0df350
コンピューティング環境の作成
チュートリアルの手順通りに進めたい時は、EC2 のプロビジョニングモデルを選択してください。
コンピューティング環境はジョブが実行される環境を定義するものです。ここで定義した内容に準じて ECS クラスターが作成されます。
わたしは既存の以下の環境を使用しました。プロビジョニングモデルとして Fargate を指定しているので、後続の手順でコマンドを少し変えてあげる必要がありました。
項目 | 値 |
---|---|
タイプ | マネージド型 |
プロビジョニングモデル | Fargate |
最大 vCPU | 16 |
サブネット | パブリックサブネット |
作成時の画面イメージは以下です。
ジョブキューの作成
ジョブキューはジョブがコンピューティング環境で実行されるまでキューイングされる場所です。ジョブキューには1つ以上のコンピューティング環境(最大3つ)を関連づけられます。
先ほどのコンピューティング環境を指定してTest-Job-Queue
という名称で作成しました。
1. コンテナイメージを構築する
環境変数AWS_BATCH_JOB_ARRAY_INDEX
で与えられた番号に応じて異なる結果を返すコンテナをビルドします。
Cloud9 環境で作業していきます。今回は作業用のディレクトリとしてwork
を作成します。
~/environment $ mkdir work ~/environment $ cd work ~/environment/work $
7つの色のリストを持つcolors.txt
作成します。
~/environment/work $ cat << _EOF_ >> colors.txt > red > orange > yellow > green > blue > indigo > violet > _EOF_ ~/environment/work $ cat colors.txt red orange yellow green blue indigo violet
コンテナが実行するスクリプトprint-color.sh
を作成します。ここではパーミッションの考慮は不要です。
~/environment/work $ touch print-color.sh ~/environment/work $ vi print-color.sh ~/environment/work $ cat print-color.sh #!/bin/sh LINE=$((AWS_BATCH_JOB_ARRAY_INDEX + 1)) COLOR=$(sed -n ${LINE}p /tmp/colors.txt) echo My favorite color of the rainbow is $COLOR.
↑AWS_BATCH_JOB_ARRAY_INDEX
(0から始まる)に 1 をプラスした行の色を取得し、メッセージを出力するという処理です。
Dockerfile
を作成します。colors.txt
とprint-color.sh
を/tmp
にコピーし、後者にはchmod +x
する内容が書かれています。
~/environment/work $ touch Dockerfile ~/environment/work $ vi Dockerfile ~/environment/work $ cat Dockerfile FROM busybox COPY print-color.sh /tmp/print-color.sh COPY colors.txt /tmp/colors.txt RUN chmod +x /tmp/print-color.sh ENTRYPOINT /tmp/print-color.sh
Docker イメージをビルドします。
~/environment/work $ docker build -t print-color . Sending build context to Docker daemon 4.096kB Step 1/5 : FROM busybox latest: Pulling from library/busybox 009932687766: Pull complete Digest: sha256:afcc7f1ac1b49db317a7196c902e61c6c3c4607d63599ee1a82d702d249a0ccb Status: Downloaded newer image for busybox:latest ---> ec3f0931a6e6 Step 2/5 : COPY print-color.sh /tmp/print-color.sh ---> 57e45044571f Step 3/5 : COPY colors.txt /tmp/colors.txt ---> bc308abb1d5d Step 4/5 : RUN chmod +x /tmp/print-color.sh ---> Running in a5acf9e57559 Removing intermediate container a5acf9e57559 ---> f3bbf5c902f6 Step 5/5 : ENTRYPOINT /tmp/print-color.sh ---> Running in 77726f28440d Removing intermediate container 77726f28440d ---> 9bc05a8cb26f Successfully built 9bc05a8cb26f Successfully tagged print-color:latest
コンテナのテストをします。
~/environment/work $ AWS_BATCH_JOB_ARRAY_INDEX=0 ~/environment/work $ while [ $AWS_BATCH_JOB_ARRAY_INDEX -le 6 ] > do > docker run -e AWS_BATCH_JOB_ARRAY_INDEX=$AWS_BATCH_JOB_ARRAY_INDEX print-color > AWS_BATCH_JOB_ARRAY_INDEX=$((AWS_BATCH_JOB_ARRAY_INDEX + 1)) > done My favorite color of the rainbow is red. My favorite color of the rainbow is orange. My favorite color of the rainbow is yellow. My favorite color of the rainbow is green. My favorite color of the rainbow is blue. My favorite color of the rainbow is indigo. My favorite color of the rainbow is violet.
環境変数AWS_BATCH_JOB_ARRAY_INDEX
を 0 ~ 6 まで与えてコンテナを起動し、それぞれで行の色が読み取られていることが確認できます。
2. イメージを Amazon ECR にプッシュする
コンテナイメージを作成できたので、それを ECR にプッシュします。ここにプッシュしたものを AWS Batch ジョブがプルすることになります。
まずは ECR のリポジトリを作成します。print-color
という名称を指定します。
~/environment/work $ aws ecr create-repository --repository-name print-color { "repository": { "repositoryUri": "012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color", "imageScanningConfiguration": { "scanOnPush": false }, "encryptionConfiguration": { "encryptionType": "AES256" }, "registryId": "012345678910", "imageTagMutability": "MUTABLE", "repositoryArn": "arn:aws:ecr:ap-northeast-1:012345678910:repository/print-color", "repositoryName": "print-color", "createdAt": 1646049568.0 } }
作成したリポジトリを指定してイメージにタグを付与します。
~/environment/work $ docker tag print-color 012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color
ECR レジストリにログインします。
~/environment/work $ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS \ > --password-stdin 012345678910.dkr.ecr.ap-northeast-1.amazonaws.com WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
イメージをプッシュします。
~/environment/work $ docker push 012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color Using default tag: latest The push refers to repository [012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color] 268a899ccec5: Pushed 49b2af34aff4: Pushed d31505fd5050: Pushed latest: digest: sha256:e143604aebee4f640a6451a2d2fae737e683b8f6bf8ec9217416e0ab42004862 size: 1148 ~/environment/work $
3. ジョブ定義を作成して登録する
AWS Batch ジョブ定義を作成します。ジョブ定義はジョブ実行時に指定されるものであり、必要に応じて設定をオーバーライドしてジョブが実行されます。ジョブ定義に応じた ECS のタスク定義が生成されます。
インプットの JSON ファイルを作成し、それをオブションで渡す方式でコマンド実行します。
JSON ファイルの作成を横着したかったので、環境変数にセットして実行します。ここではparamas
という変数に格納します。
params=$(cat <<EOM { "jobDefinitionName": "print-color", "type": "container", "containerProperties": { "image": "012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color", "executionRoleArn": "arn:aws:iam::012345678910:role/ecsTaskExecutionRole", "resourceRequirements": [ { "type": "MEMORY", "value": "3072" }, { "type": "VCPU", "value": "1" } ], "networkConfiguration": { "assignPublicIp": "ENABLED" } }, "platformCapabilities": [ "FARGATE" ] } EOM )
↑ 先述の通り、AWS ドキュメントに記載の内容と変えています。Fargate タイプのコンピューティング環境に対応した内容とするためです。
環境変数params
をオプションの引数として渡してコマンド実行します。
~/environment/work $ aws batch register-job-definition --cli-input-json "$params" { "jobDefinitionArn": "arn:aws:batch:ap-northeast-1:012345678910:job-definition/print-color:4", "jobDefinitionName": "print-color", "revision": 4 }
↑何回もやり直していたのでリビジョンが 4 になっていますが、初回であれば 1 が返ってきます。
4. AWS Batch 配列ジョブの実行
作成したジョブ定義を指定し、ジョブを実行します。
ここでも JSON ファイルをインプットとして渡します。作成済みのジョブキュー、ジョブ定義を指定し、配列サイズ 7 でジョブ実行する内容が定義されています。
params=$(cat <<EOM { "jobName": "print-color", "jobQueue": "Test-Job-Queue", "arrayProperties": { "size": 7 }, "jobDefinition": "print-color" } EOM )
ジョブを実行します。ここではジョブ ID などの出力が返ってくればOKです。
~/environment/work $ aws batch submit-job --cli-input-json "$params" { "jobName": "print-color", "jobArn": "arn:aws:batch:ap-northeast-1:012345678910:job/d4bea16c-8464-4cb9-8fce-336f0191e28b", "jobId": "d4bea16c-8464-4cb9-8fce-336f0191e28b" }
5, 配列ジョブの確認
ジョブの実行履歴を確認すると、インデックスとして 0 ~ 6 を持つ配列ジョブが実行されたことが確認できます。
ついでに ECS のサービス画面を覗くと、AWS Batch コンピューティング環境に紐づく ECS クラスター内でタスクが 7 個立ち上がっていたことが分かります。
ジョブの実行ログを確認すると、それぞれのジョブが自身のインデックスに基づいたログを出力していることが確認できます。
環境変数AWS_BATCH_JOB_ARRAY_INDEX
に応じて異なる処理をする配列ジョブの挙動が確認できました。
配列ジョブチュートリアル失敗集
せっかくなので躓いたところを供養します。ほぼジョブ定義の作成に関するところです。
ジョブ定義が EC2 用になっていることに気づかずジョブ実行
最初のトライの時はドキュメントの記載に則り以下パラメータでジョブ定義を作成していました。
{ "jobDefinitionName": "print-color", "type": "container", "containerProperties": { "image": "aws_account_id.dkr.ecr.region.amazonaws.com/print-color", "resourceRequirements": [ { "type": "MEMORY", "value": "250" }, { "type": "VCPU", "value": "1" } ] } }
ステップ4でそのジョブ定義を指定してジョブ実行した時に、怒られが発生しました。
$ aws batch submit-job --cli-input-json "$params" An error occurred (ClientException) when calling the SubmitJob operation: Job Queue is attached to Compute Environment that can not run Jobs with capability EC2
An error occurred (ClientException) when calling the SubmitJob operation: Job Queue is attached to Compute Environment that can not run Jobs with capability EC2
VCPU と MEMORY の組み合わせが正しくない
こちらはジョブ定義を作成する時点で発生したエラーです。
~/environment/work $ params=$(cat <<EOM > { > "jobDefinitionName": "print-color", > "type": "container", > "containerProperties": { > "image": "012345678910.dkr.ecr.ap-northeast-1.amazonaws.com/print-color", > "resourceRequirements": [ > { > "type": "MEMORY", > "value": "250" > }, > { > "type": "VCPU", > "value": "1" > } > ] > }, > "platformCapabilities": [ > "FARGATE" > ] > } > EOM > ) ~/environment/work $ aws batch register-job-definition --cli-input-json "$params" An error occurred (ClientException) when calling the RegisterJobDefinition operation: Error executing request, Exception : Fargate resource requirements (1.00 vCPU, 250 MiB) not valid., RequestId: 33fc96df-e4f0-46db-a366-97d8557befca
An error occurred (ClientException) when calling the RegisterJobDefinition operation: Error executing request, Exception : Fargate resource requirements (1.00 vCPU, 250 MiB) not valid.
AWS CLI リファレンスを見ると vCPU と メモリの組み合わせが載っていたので、それに準じる値に修正しました。
その他
ジョブ定義のパラメータでいろいろやりました。
"platformCapabilities": "FARGATE"
という誤った形で指定するInvalid type for parameter platformCapabilities, value: FARGATE, type: <type 'unicode'>, valid types: <type 'list'>, <type 'tuple'>
"executionRoleArn"
の定義漏れException : executionRoleArn must be provided for Fargate jobs.
"assignPublicIp": "ENABLED"
を指定しない- ジョブ定義の作成は成功するが、ジョブ実行が失敗する
- 今回の環境では NAT Gateway や VPC エンドポイントを用意していないのでパブリック IP を割り当てないとイメージがプルできない
- ジョブ定義の作成は成功するが、ジョブ実行が失敗する
勉強になりました。
終わりに
AWS Batch 配列ジョブのチュートリアルをやってみました。
単純に配列ジョブの挙動を見るだけであればもっと簡単な手段もありそうですが、コンテナイメージの作成から一連の流れで試せたのでお得な気分になれました。
Docker、ECR もついでに触れるので、興味がある方は試してみてはいかがでしょうか。
以上、 チバユキ (@batchicchi) がお送りしました。