この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どうも!西村祐二@大阪です。
2017年8月にCloudformationにてAWS Batchがサポートされましたので、Cloudformationの勉強を兼ねて試してみたいと思います。
さっそくやっていきましょう!
使用できるリソースタイプを確認
ドキュメントよりテンプレート作成時に使用できるリソースタイプを確認します。 AWS Batchでは下記3つのリソースタイプが使用できるようです。
AWS::Batch::ComputeEnvironment
AWS::Batch::JobDefinition
AWS::Batch::JobQueue
環境
Mac: macOS Sierra 10.12.6 AWS CLI: aws-cli/1.11.145 Python/3.6.1 Darwin/16.7.0 botocore/1.7.3
事前準備
下記ブログで作成したAWS Batch環境を見本に今回作成しますので事前に確認をお願いします。
aws-cliのアップデート
最新のバージョンへアップデートしておいてください。
$ sudo pip install -U awscli
テンプレート作成
今回、AWS Batchの「Compute environments」「Job queues」「Job definitions」を構築するテンプレートを作成していきます。 いきなり、3つの環境を含めてたテンプレートを作成するのは大変なのでそれぞれ分割してテンプレートを作成し、あとで1つにまとめたいと思います。
Compute environmentsのテンプレートを作成
Compute environmentsを構築するためにはテンプレート内で ServiceRole、SecurityGroupIds、Subnets、InstanceRoleを指定する必要があります。 そのため今回はIAMとVPCも含めたテンプレートを作成したいと思います。
IAMのManagedPolicyArns箇所は適時変更ください。 今回は事前準備のところで紹介した記事を参考にしているためInstance roleにCodeCommitとS3の権限を付与しています。(下記コード134-135行目)
IAMは名前を指定すると重複する可能性があるため、特に指定していません。 指定せずにスタック作成すると任意の文字列を付与してくれます。
今回ソースが長くなりすぎてしまうので、割愛していますが、 Compute environmentsのパラメータを Parametersセッションとして外に出しておくと良いかと思います。
テンプレート作成時の必須の項目などはこちらのドキュメントを確認しながら作成するのが良いかと思います。
batch-env.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Build AWS Batch environment
#========VPC========#
Resources:
# Create VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: default
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"vpc" ] ]
# Create Public RouteTable
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"pub-route" ] ]
# Create Private RouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"pri-route" ] ]
# Create Public Subnet A
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: 'true'
AvailabilityZone: "ap-northeast-1a"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PublicSunetA" ] ]
PubSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRouteTable
# Create Public Subnet C
PublicSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: 'true'
AvailabilityZone: "ap-northeast-1c"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PublicSunetC" ] ]
PubSubnetCRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicRouteTable
# Create Private Subnet A
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.10.0/24
AvailabilityZone: "ap-northeast-1a"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PrivateSubnetA" ] ]
PriSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref PrivateRouteTable
# Create Private Subnet C
PrivateSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.11.0/24
AvailabilityZone: "ap-northeast-1c"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PrivateSubnetC" ] ]
PriSubnetCRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateRouteTable
# Create InternetGateway
myInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"igw" ] ]
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref myInternetGateway
# Route for InternetGateway or VPNGateway
myRoute:
Type: AWS::EC2::Route
DependsOn: myInternetGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref myInternetGateway
#=======IAM========#
# Create ecsInstanceRole
ecsInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
## start
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
## end
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
- arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Path: "/"
# Set InstanceProfile
ecsInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Roles:
- !Ref ecsInstanceRole
# Create AWSBatchServiceRole
AWSBatchServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
## start
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- batch.amazonaws.com
Action:
- sts:AssumeRole
## end
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole
Path: "/service-role/"
###
### ---ComputeEnvironment---
###
MyComputeEnv:
Type: "AWS::Batch::ComputeEnvironment"
Properties:
Type: MANAGED
#作成したIAMから取得
ServiceRole: !GetAtt AWSBatchServiceRole.Arn
ComputeEnvironmentName: cfn-env
ComputeResources:
MaxvCpus: 256
MinvCpus: 0
DesiredvCpus: 0
SecurityGroupIds:
#作成したVPCから取得
- !GetAtt MyVPC.DefaultSecurityGroup
Type: EC2
Subnets:
#作成したVPCから取得
- !Ref PrivateSubnetA
- !Ref PublicSubnetA
#作成したVPCから取得
InstanceRole: !GetAtt ecsInstanceProfile.Arn
InstanceTypes:
- optimal
Tags: {"Name": "Batch Instance - cfn test"}
State: ENABLED
動作確認
▼スタック作成前に構文チェックを行いエラーがないことを確認します。
$ aws cloudformation validate-template --template-body file://batch-env.yml
▼今回スタック名を「batch-env」として作成します。テンプレートにIAMリソースがある場合、capabilities
オプションを付ける必要があります。
$ aws cloudformation create-stack --stack-name batch-env --template-body file://batch-env.yml --capabilities CAPABILITY_IAM
▼作成したスタックのステータスを確認します。 無事スタックの作成が完了したら下記コマンドより「CREATE_COMPLETE」が表示され、 テンプレートで設定した値で「cfn-env」という名前の「Compute environments」が作成されています。 失敗した場合は「ROLLBACK_COMPLETE」となりロールバックされます。
$ aws cloudformation describe-stacks --stack-name batch-env | awk '{print $NF}'
Job queuesのテンプレートを作成
同様にJob queuesのテンプレートを作成していきます。 ComputeEnvironmentを指定する必要があるので、先程作成した名前を指定しておきます。
batch-queue.yml
###
AWSTemplateFormatVersion: 2010-09-09
Description: AWS Batch Job queues from cfn
###
###---Resources:JobQueue---
###
Resources:
MyJobQueue:
Type: AWS::Batch::JobQueue
Properties:
ComputeEnvironmentOrder:
- Order: 1
ComputeEnvironment: cfn-env
State: ENABLED
Priority: 1
JobQueueName: cfn-queue
動作確認
▼スタック作成前に構文チェックを行いエラーがないことを確認します。
$ aws cloudformation validate-template --template-body file://batch-queue.yml
▼今回スタック名を「batch-queue」として作成します。
$ aws cloudformation create-stack --stack-name batch-queue --template-body file://batch-queue.yml
▼作成したスタックのステータスを確認します。 無事スタックの作成が完了したら下記コマンドより「CREATE_COMPLETE」が表示され、 テンプレートで設定した値で「cfn-queue」という名前の「Job queues」が作成されています。 失敗した場合は「ROLLBACK_COMPLETE」となりロールバックされます。
$ aws cloudformation describe-stacks --stack-name batch-queue | awk '{print $NF}'
Job definitionsのテンプレートを作成
同様にJob definitionsのテンプレートを作成していきます。
ドキュメントには必須とのは記載ありませんが
RetryStrategy
の設定がないとエラーとなるようです。
指定するコマンド、コンテナイメージは下記ブログで作成したものを指定しています。
batch-def.yml
###
AWSTemplateFormatVersion: 2010-09-09
Description: AWS Batch Job definitions from cfn
###
###---Resources:JobDefinition---
###
Resources:
MyJobDefinition:
Type: AWS::Batch::JobDefinition
Properties:
Type: container
JobDefinitionName: cfn-def
ContainerProperties:
Command:
- sh
- /usr/local/init.sh
Memory: 2000
Vcpus: 2
Image: 1234567890.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
RetryStrategy:
Attempts: 1
動作確認
▼スタック作成前に構文チェックを行いエラーがないことを確認します。
$ aws cloudformation validate-template --template-body file://batch-def.yml
▼今回スタック名を「batch-def」として作成します。
$ aws cloudformation create-stack --stack-name batch-def --template-body file://batch-def.yml
▼作成したスタックのステータスを確認します。 無事スタックの作成が完了したら下記コマンドより「CREATE_COMPLETE」が表示され、 テンプレートで設定した値で「cfn-def」という名前の「Job definitions」が作成されています。 失敗した場合は「ROLLBACK_COMPLETE」となりロールバックされます。
$ aws cloudformation describe-stacks --stack-name batch-def | awk '{print $NF}'
スタックの削除
次に作成したテンプレートを1つにまとめるため、作成したスタックを削除しておきます。 JobQueueではComputeEnvironmentを指定しているため 「batch-env」より先に「batch-queue」を削除してください。
$ aws cloudformation delete-stack --stack-name batch-queue
$ aws cloudformation delete-stack --stack-name batch-env
$ aws cloudformation delete-stack --stack-name batch-def
1つのテンプレートにまとめる
個別に作成した3つのテンプレートを1つのテンプレートにまとめてみます。
ポイントとして、「JobQueue」のリソースを作成する際に「ComputeEnvironment」を指定する必要があるので、!Ref MyComputerEnv
として、値を指定しています。
batch.yml
AWSTemplateFormatVersion: 2010-09-09
Description: AWS Batch ALL
#========VPC========#
Resources:
# Create VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: default
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"vpc" ] ]
# Create Public RouteTable
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"pub-route" ] ]
# Create Private RouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"pri-route" ] ]
# Create Public Subnet A
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: 'true'
AvailabilityZone: "ap-northeast-1a"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PublicSunetA" ] ]
PubSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRouteTable
# Create Public Subnet C
PublicSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: 'true'
AvailabilityZone: "ap-northeast-1c"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PublicSunetC" ] ]
PubSubnetCRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicRouteTable
# Create Private Subnet A
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.10.0/24
AvailabilityZone: "ap-northeast-1a"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PrivateSubnetA" ] ]
PriSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref PrivateRouteTable
# Create Private Subnet C
PrivateSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.11.0/24
AvailabilityZone: "ap-northeast-1c"
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"PrivateSubnetC" ] ]
PriSubnetCRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateRouteTable
# Create InternetGateway
myInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Join [ "-", [ "cfn" ,"igw" ] ]
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref myInternetGateway
# Route for InternetGateway or VPNGateway
myRoute:
Type: AWS::EC2::Route
DependsOn: myInternetGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref myInternetGateway
#=======IAM========#
# Create ecsInstanceRole
ecsInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
## start
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
## end
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
- arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Path: "/"
# Set InstanceProfile
ecsInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Roles:
- !Ref ecsInstanceRole
#InstanceProfileName:
# Create AWSBatchServiceRole
AWSBatchServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
## start
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- batch.amazonaws.com
Action:
- sts:AssumeRole
## end
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole
Path: "/service-role/"
#========Batch========#
# Create ComputeEnvironment
MyComputeEnv:
Type: "AWS::Batch::ComputeEnvironment"
Properties:
Type: MANAGED
ServiceRole: !GetAtt AWSBatchServiceRole.Arn
ComputeEnvironmentName: cfn-env
ComputeResources:
MaxvCpus: 0
MinvCpus: 0
DesiredvCpus: 0
SecurityGroupIds:
- !GetAtt MyVPC.DefaultSecurityGroup
Type: EC2
Subnets:
- !Ref PrivateSubnetA
- !Ref PublicSubnetA
InstanceRole: !GetAtt ecsInstanceProfile.Arn
InstanceTypes:
- optimal
Tags: {"Name": "Batch Instance - cfn test"}
State: ENABLED
# Create JobQueue
MyJobQueue:
Type: AWS::Batch::JobQueue
Properties:
ComputeEnvironmentOrder:
- Order: 1
ComputeEnvironment: !Ref MyComputeEnv
State: ENABLED
Priority: 1
JobQueueName: cfn-queue
# Create JobDefinition
MyJobDefinition:
Type: AWS::Batch::JobDefinition
Properties:
Type: container
JobDefinitionName: cfn-def
ContainerProperties:
Command:
- sh
- /usr/local/init.sh
Memory: 2000
Vcpus: 2
Image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
RetryStrategy:
Attempts: 1
動作確認
▼スタック作成前に構文チェックを行いエラーがないことを確認します。
$ aws cloudformation validate-template --template-body file://batch.yml
▼今回スタック名を「batch」として作成します。 スタック作成完了までに多少時間がかかるため、完了までwaitしてくれるコマンドをつなげておきます。
$ aws cloudformation create-stack --stack-name batch --template-body file://batch.yml --capabilities CAPABILITY_IAM && aws cloudformation wait stack-create-complete --stack-name batch
▼作成したスタックのステータスを確認します。 無事スタックの作成が完了したら下記コマンドより「CREATE_COMPLETE」が表示され、 テンプレートで設定したAWS Batchの環境が作成されています。 失敗した場合は「ROLLBACK_COMPLETE」となりロールバックされます。
$ aws cloudformation describe-stacks --stack-name batch | awk '{print $NF}'
スタックの削除
AWS Batchの環境が必要なくなったらスタックを削除することで環境をまとめて削除することができます。 削除完了まで多少時間がかかるため、削除が完了するまでwaitしてくるコマンドをつなげておきます。
$ aws cloudformation delete-stack --stack-name batch && aws cloudformation wait stack-delete-complete --stack-name batch
さいごに
いかがだったでしょうか。 テンプレートの作成は慣れるまでなかなか大変ですが、 自在に扱えるようになればとても効率よく作業が行えるため これからも積極的に利用していきたいと思います。
誰かの参考になれば幸いです。