AWS Batchとは
AWS re:Invent 2016 で発表されたサービスで、2017/06より東京リージョンがリリースされました。
どんなサービスなのか簡潔に言うと、
ECSを利用して、処理が実行している間だけ自動でEC2インスタンスを起動し、終わったら自動でterminateしてくれるサービスです。
今回、試しに簡単な処理を実行するものを作ってみたので、その手順を書きたいと思います。
AWS Lambdaとの違い
処理を実行する時だけ起動するという点では、よく似ているサービスにAWS Lambdaがあります。
関連: Serverless FrameworkでAWS Lamda関数を作成する
しかし、似ているようで、全く別のサービスとなっています。
以下が、Lambdaとの相違点です。
- Lambdaは最長5分しか実行できないが、AWS Batchは実行時間に上限はない
- LambdaはFaaSなので開発言語が限定されているが、Batchは環境構築を自分で行うので自由
- Batch単体で定期実行はできないので、別途定期的にキックするトリガーを用意する必要がある
まず、サーバーの環境構築は自分で行う必要があります。
具体的には、あらかじめDockerイメージを作成しておいて、
処理起動時に、AWS Batchが指定されたDockerレポジトリからイメージを取得してコンテナを立ち上げるという流れになります。
自分で環境構築するため、Lambdaのように開発言語を限定されないので、自由度が高いです。
また、最長実行時間に上限がないため、時間のかかる処理に向いています。
AWS Batchのオートスケーリング
オートスケーリングは、AWSがよしなにやってくれます。
自分で制御することも可能です。
その他、以下のような特徴があります。
-
クラスタ数の上限を自分で設定することも可能
- インスタンス数ではなくvCPU数で指定する
-
使用されるEC2インスタンスタイプを指定することもAWSにおまかせすることもできる
- t2系などは選択できない
- m4 familyのような柔軟な設定も可能(その中からAWSが最適なものを選ぶ)
- optimal(おまかせ)を選択すると最新の C、M、および R インスタンスファミリーから最適なものが選択される
- 立ち上がったインスタンスは、実際にECSやEC2の画面で確認できる
構成図
今回構築した環境の構成図です。
今回は上図の構成で構築してみました。
処理のフローは以下になります。
-
jobをsubmitし、Batchのqueueに登録(FIFO)
- スケジューラがqueueのjobの優先順位を把握する
-
ECSがEC2インスタンスが起動させる
- 既に起動している場合は、起動しているインスタンスが使用される
- 既にEC2が起動している場合は、ほとんどタイムラグなくjobが実行されるが、起動していない場合は、job実行開始が、インスタンスが起動する時間分タイムラグとなる
- 立ち上がったインスタンスは、ECSやEC2の画面で確認できる
- AWS ECRに登録されているコンテナイメージを使って、EC2内にコンテナを立ち上げる
- コンテナ内で処理を実行する
- 処理が終わったら、EC2インスタンスを削除する
- 後続のjobがある場合は、削除されずにそのまま使用される
トリガーについて
まず、AWS Batchは単体で定期実行することができないので、別途トリガーを用意する必要があります。
方法は色々ありますが、AWSのサービスを利用するのであれば、トリガーを投げるLambdaをCloudwatchで定期実行させるのが簡単かと思います。
job
AWS Batchは、キックされるとjobにキューを溜めます。
基本的にFIFO(First In, First Out)ですが、他のjobとの依存関係や優先度を指定することも可能です。
ECSで処理実行
jobが実行されると、ECSが、EC2クラスタインスタンスを立ち上げます。
次に、ECSがDockerレポジトリ(今回はECR)からDockerイメージを取得して、
EC2クラスタインスタンス上にDockerコンテナを立ち上げます。
このコンテナ上で、処理が実行されます。
処理の重さに応じてオートスケーリングが行われます。
図の例では、データソースから取得したデータ加工して、HDFSに書き出すという処理が行われています。
処理が終了したら、EC2クラスタインスタンスが削除されます。
環境構築手順
AWS ECRにDockerイメージの登録
まずは、以下の記事を参考に、Dockerイメージを作成して、AWS ECRに登録してください。
AWS ECRにdockerイメージを登録する
AWS Batchの環境構築
では、AWS Batch環境構築をします。
Cloud Formationを利用して環境構築をするので、
まず、awscliなどをインストールした、Cloud Formationを実行できる環境を用意してください。
Cloud Formationの環境構築手順については、以下を参考にpythonをインストールし、pipでawscliをインストールするか、Amazon Linuxを使ってください。
Cloud Formation実行
yamlを作成
以下のyamlを作成します。
適宜、ご自分の環境にあった設定に読み替えてください。
AWSTemplateFormatVersion: 2010-09-09
Description: Build AWS Batch environment
Parameters:
SubnetIds:
Description: Subnets For ComputeEnvironment
Type: List<AWS::EC2::Subnet::Id>
Default: subnet-xxxxxxxx,subnet-yyyyyyyy
SecurityGroupIds:
Description: SecurityGroups For ComputeEnvironment
Type: List<AWS::EC2::SecurityGroup::Id>
Default: sg-zzzzzzzz
ContainerImage:
Description: Uri of container image to use in ECS
Type: String
Default: xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-aws-batch-repo
# あらかじめ、key pairを作成しておいてください
KeyPair:
Description: key pair
Type: String
Default: sample_key
Resources:
####### IAM #######
# ECSインスタンスを実行するrole
ecsInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
- arn:aws:iam::aws:policy/AmazonEC2FullAccess
- arn:aws:iam::aws:policy/AmazonECS_FullAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
Path: "/"
# Set InstanceProfile
ecsInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Roles:
- !Ref ecsInstanceRole
# AWS Batchを実行するrole
AWSBatchServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- batch.amazonaws.com
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole
Path: "/service-role/"
####### ComputeEnvironment #######
SampleComputeEnv:
Type: "AWS::Batch::ComputeEnvironment"
Properties:
Type: MANAGED
# 作成したIAMから取得
ServiceRole: !GetAtt AWSBatchServiceRole.Arn
ComputeEnvironmentName: sample-batch-compute-env
ComputeResources:
Ec2KeyPair: !Ref KeyPair
# 最大vcpu数、最大インスタンス数となります
MaxvCpus: 256
# 最小vcpu 0にすると自動でインスタンスをterminateしてくれる
MinvCpus: 0
# 起動するインスタンスの希望するvCPUの数
DesiredvCpus: 1
SecurityGroupIds: !Ref SecurityGroupIds
Type: EC2
Subnets: !Ref SubnetIds
# 作成したVPCから取得
InstanceRole: !GetAtt ecsInstanceProfile.Arn
InstanceTypes:
# 使用するインスタンスタイプ、optimalならおまかせ
- optimal
Tags: {"Name": "Batch Instance - sample"}
State: ENABLED
SampleJobQueue:
Type: AWS::Batch::JobQueue
Properties:
ComputeEnvironmentOrder:
- Order: 1
ComputeEnvironment: !Ref SampleComputeEnv
State: ENABLED
# jobの優先順位
Priority: 1
JobQueueName: sample-batch-queue
SampleJobDefinition:
Type: AWS::Batch::JobDefinition
Properties:
Type: container
JobDefinitionName: sample-batch-definition
ContainerProperties:
Command:
- sh
- /usr/local/init.sh
# memoryの上限
Memory: 4048
Vcpus: 2
Image: Image: !Ref ContainerImage
RetryStrategy:
Attempts: 1
syntax check
yamlのsyntax checkをします。
$ aws cloudformation validate-template --template-body file://aws-batch.yml
実行
実行して、環境を作成します。
$ aws cloudformation create-stack \
--stack-name sample-batch \
--template-body file://aws-batch.yml \
--capabilities CAPABILITY_IAM \
確認
作成されたことを確認します。
$ aws cloudformation describe-stacks --stack-name sample-batch
"StackStatus": "CREATE_COMPLETE",
になっていることを確認してください。
削除
削除する場合は以下のコマンドを実行してください。
$ aws cloudformation delete-stack --stack-name sample-batch
jobを実行する
今回は、awscliを手動で実行してトリガーとします。
まず、以下のコマンドで、jobの設定ファイルとなるjsonのテンプレートを生成します。
$ aws batch submit-job --generate-cli-skeleton > submit-job.json
生成されたjsonファイルを、以下のように編集します。
パラメータや、環境変数を設定することができます。
{
"jobName": "sample-batch-job",
"jobQueue": "sample-batch-queue",
"jobDefinition": "sample-batch-definition",
"parameters": {
"KeyName": "string"
},
"containerOverrides": {
"environment": [
{
"name": "access_token",
"value": "abcdef1234"
}
]
}
}
項目 | 設定値 |
---|---|
jobName | job名 |
jobQueue | 作成したJobQueueを指定 |
jobDefinition | 作成したJobDefinitionを指定 |
parameters | パラメータ |
environment | 環境変数 |
以下のコマンドでjobを実行します。
$ aws batch submit-job --cli-input-json file://submit-job.json
response
{
"jobId": "a94985d8-52d6-4ea0-95ac-2ccb0dcabc25",
"jobName": "sample-batch-job"
}
job実行
jobが実行されると、以下の順でjobが移動していきます。
submitted
-> runnable
-> starting
-> running
-> succeeded
また、runnableのタブに入ったまま、runningへ移動しない場合は、ECSの起動周りで問題が起きている可能性が高いので、EC2インスタンスにsshでログインして、原因を調査してください。
EC2インスタンス確認
EC2インスタンス一覧の画面で、
Batch Instance - sample
という名前でインスタンスが起動していることが確認できます。
実行結果Statusを確認
AWS BatchのJob画面で、実行結果のStatusを確認できます。
以下のように、succeededのタブにjobが移動していれば成功です。
3つ結果がありますが、今回の結果は一番下の選択されているものです。
もし、failedのタブに入れば、失敗しているので、failedタブのJob IDをクリックして、エラーの原因を調査してください。
Cloudwatchで出力結果の確認
出力結果がある場合は、Cloudwatch の /aws/batch/job
ロググループで確認することができます。
Batch完了後
自動でインスタンスがterminateされます。
まとめ
一通り触ってみて、バッチ処理を実行することはできました。
jobが登録されてからEC2インスタンスが立ち上がるので、リアルタイムで実行する処理には向いていませんが、非同期で時間のかかる処理を実行するのには向いてそうです。
別途、オートスケーリングの検証などもしてみたいと思います。
以上