[新機能] AWS Step FunctionsがAWS BatchとSNSに連携可能となったのでさっそく試してみた #reinvent

re:Invent 2018のキーノートで、AWS Step Functionsが新たに8つのマネージドサービスと連携可能になることが発表されました。このエントリでは、Step Functionsのサンプルプロジェクトとして用意されているバッチジョブの管理を実際に試してみました。
2018.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。サービスグループの武田です。

現在ラスベガスで開催中のre:Invent 2018のキーノートで、AWS Step Functionsが新たに8つのマネージドサービスと連携可能になることが発表されました。速報については濱田のエントリをどうぞ。

[神アップデート]Step Functionsが新たに8つのマネージドサービスと連携可能になりました! #reinvent

このエントリでは、Step Functionsのサンプルプロジェクトとして用意されている バッチジョブの管理 を実際に試してみましたので、その様子をお届けします。なお東京リージョンですでに使用可能ですので、今回も東京リージョンで実施しました(今アメリカなんですけどね)。

バッチジョブの管理

Step Functionsのサンプルとして用意されているプロジェクトで、少ないステップでAWS BatchおよびSNSと連携するステートマシンが作成できます。手組みしようとするとStep Functionsのステートマシンはもちろんのこと、Batchのジョブ定義やジョブキュー、SNSやIAMロールなどを用意する必要があります。

このサンプルプロジェクトを利用すると、用意されたAWS CloudFormationテンプレートのスタックを作成するだけで必要なリソースが作成されます。まずは使い方を覚えたいという用途に最適です。

やってみた

それではマネジメントコンソールから実際に作成して動作確認をしてみます。

CloudFormationスタックの作成

マネジメントコンソールを起動したらStep Functionsの画面に移動します。移動できたら[今すぐ始める]をクリックします。

「ステートマシンを定義する」画面になったら、[サンプルプロジェクト]を選択し、さらに[バッチジョブの管理]を選択します。

選択後、下にスクロールすると作られるステートマシンのJSONとビジュアルが確認できます。バッチジョブを実行し、成功/失敗によってそれぞれ通知を行うということが一目でわかります。

用意されているステートマシンの定義です。<PARTITION>などはプレースホルダーとなっていて、CloudFormationスタック作成時に実際の値に置換されます。

{
  "Comment": "An example of the Amazon States Language for notification on an AWS Batch job completion",
  "StartAt": "Submit Batch Job",
  "TimeoutSeconds": 3600,
  "States": {
    "Submit Batch Job": {
      "Type": "Task",
      "Resource": "arn:<PARTITION>:states:::batch:submitJob.sync",
      "Parameters": {
        "JobName": "BatchJobNotification",
        "JobQueue": "<BATCH_QUEUE_ARN>",
        "JobDefinition": "<BATCH_JOB_DEFINITION_ARN>"
      },
      "Next": "Notify Success",
      "Catch": [
        {
          "ErrorEquals": [ "States.ALL" ],
          "Next": "Notify Failure"
        }
      ]
    },
    "Notify Success": {
      "Type": "Task",
      "Resource": "arn:<PARTITION>:states:::sns:publish",
      "Parameters": {
        "Message": "Batch job submitted through Step Functions succeeded",
        "TopicArn": "<SNS_TOPIC_ARN>"
      },
      "End": true
    },
    "Notify Failure": {
      "Type": "Task",
      "Resource": "arn:<PARTITION>:states:::sns:publish",
      "Parameters": {
        "Message": "Batch job submitted through Step Functions failed",
        "TopicArn": "<SNS_TOPIC_ARN>"
      },
      "End": true
    }
  }
}

下部にある[次へ]を選択すると「リソースのデプロイ」確認画面になります。そのまま[リソースのデプロイ]をクリックします。

CloudFormationスタックが作成されました。最大10分かかるとのことですが、私の環境では4分ほどで完了しました。コーヒーでも飲んで待ちましょう。

しばらく待っているとステートマシンの作成が完了します。

実際に実行されたCloudFormationテンプレートですが、それなりに長いのでこのエントリの最後に補足情報として掲載しておきます。

作成されたリソースの確認

作成されたステートマシンの定義を確認すると、先ほどプレースホルダーだった箇所が実際の値に置き換わっていることが確認できます。

IAMロールはBatch用、Step Functions用、EC2コンテナ用の3つが作られています。

StepFunctionsSample-Batch-BatchJobNotificationExecロールにはBatchJobNotificationAccessPolicyというインラインポリシーがアタッチされています。Step FunctionsからBatchやSNSを実行するために必要な権限が付与されていることがわかります。

BatchJobNotificationAccessPolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "sns:Publish"
            ],
            "Resource": [
                "arn:aws:sns:ap-northeast-1:123456789012:StepFunctionsSample-BatchJobManagement841cc514-f239-45b5-aa7e-33648a548529-SNSTopic-13C2FBO11TFEY"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "batch:SubmitJob",
                "batch:DescribeJobs",
                "batch:TerminateJob"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "events:PutTargets",
                "events:PutRule",
                "events:DescribeRule"
            ],
            "Resource": [
                "arn:aws:events:ap-northeast-1:123456789012:rule/StepFunctionsGetEventsForBatchJobsRule"
            ],
            "Effect": "Allow"
        }
    ]
}

SNSトピックも作成されています。

ステートマシンを実行する前にサブスクリプションの設定を

ここまでで必要なリソースは作成されているため、すぐにでもステートマシンを実行することができますが、SNSのサブスクリプションの設定をしていないため通知が飛んできません。忘れずに追加しましょう。

今回はわかりやすくEmailを登録します。

Pendingになります。

飛んできたメールから確認すれば登録完了です。

いよいよステートマシンの実行

それではステートマシンを実行します。作成したステートマシンの画面を開いたら、下部にある[実行の開始]をクリックします。

実行名と入力値が入力できます。実行名は任意ですが1st-testとしました。入力値はデフォルトの{}です。入力できたら[実行の開始]をクリックします。

画面が切り替わり、バッチジョブが実行されていることが確認できます。

しばらく待っていると「Notify Success」を経由して終了しました。

成功通知がメールに来ていました!

失敗パターンも試してみる

成功パターンだけでなく失敗パターンも試してみましょう。バッチジョブをわざと失敗させればいいので、そうなるように変更を加えます。

まずはBatchのジョブ定義を変更します。ジョブ定義の画面を開いたら現在のリビジョンを選択し[新しいリビジョンの作成]をクリックします。

Commandの欄が見つかりますので、ls /fooなど失敗するコマンドを入力します。入力できたら画面下部の[Create Job Definition]をクリックします。これでRevision 2として追加できました。

次にStep Functionsから実行するバッチジョブのリビジョンも変更する必要があります。ステートマシンの画面にアクセスしたら、右上にある[編集]をクリックします。

12行目にJobDefinitionが見つかります。末尾の:1:2に変更します。これで先ほど追加したRevision 2のバッチジョブが呼び出されます。変更できたら右上の[保存]をクリックします。

失敗パターンの実行

それでは変更したステートマシンを実行します。実行方法は先ほどと同じで、実行名は2nd-testとしてみました。実行後、終了するまで8分ほどかかりましたが、おそらくリトライなどをしているのではないかと思われます。

失敗通知のメールも無事に来ていました。

まとめ

新機能の確認ということで、まずは用意されているサンプルプロジェクトをベースに検証をしてみました。AWS BatchやSNSとシームレスに連携できてとても素敵ですね!

現場からは以上です。

補足情報

最後に、サンプルプロジェクト作成時に実行されるCloudFormationテンプレートを掲載しておきます。どのようなリソースが作成されるのかぜひチェックしてみてください。

CloudFormationTemplate

---
  AWSTemplateFormatVersion: 2010-09-09
  Description: AWS Step Functions sample project for getting notified on AWS Batch job completion
  Resources:
    BatchJobNotificationStateMachine:
      Type: AWS::StepFunctions::StateMachine
      Properties:
        RoleArn: !GetAtt [ BatchJobNotificationExecutionRole, Arn ]
        DefinitionString:
          !Sub
            - |-
              {
                "Comment": "An example of the Amazon States Language for notification on an AWS Batch job completion",
                "StartAt": "Submit Batch Job",
                "TimeoutSeconds": 3600,
                "States": {
                  "Submit Batch Job": {
                    "Type": "Task",
                    "Resource": "arn:${AWS::Partition}:states:::batch:submitJob.sync",
                    "Parameters": {
                      "JobName": "BatchJobNotification",
                      "JobQueue": "${jobQueueArn}",
                      "JobDefinition": "${jobDefinitionArn}"
                    },
                    "Next": "Notify Success",
                    "Catch": [
                        {
                          "ErrorEquals": [ "States.ALL" ],
                          "Next": "Notify Failure"
                        }
                    ]
                  },
                  "Notify Success": {
                    "Type": "Task",
                    "Resource": "arn:${AWS::Partition}:states:::sns:publish",
                    "Parameters": {
                      "Message": "Batch job submitted through Step Functions succeeded",
                      "TopicArn": "${snsTopicArn}"
                    },
                    "End": true
                  },
                  "Notify Failure": {
                    "Type": "Task",
                    "Resource": "arn:${AWS::Partition}:states:::sns:publish",
                    "Parameters": {
                      "Message": "Batch job submitted through Step Functions failed",
                      "TopicArn": "${snsTopicArn}"
                    },
                    "End": true
                  }
                }
              }
            - {snsTopicArn: !Ref SNSTopic, jobQueueArn: !Ref BatchJobQueue, jobDefinitionArn: !Ref BatchJobDefinition}
    BatchJobNotificationExecutionRole:
      Type: "AWS::IAM::Role"
      Properties:
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal:
                Service: states.amazonaws.com
              Action: "sts:AssumeRole"
        Path: "/"
        Policies:
          - PolicyName: BatchJobNotificationAccessPolicy
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action:
                    - "sns:Publish"
                  Resource:
                   - !Ref SNSTopic
                - Effect: Allow
                  Action:
                    - "batch:SubmitJob"
                    - "batch:DescribeJobs"
                    - "batch:TerminateJob"
                  Resource: "*"
                - Effect: Allow
                  Action:
                    - "events:PutTargets"
                    - "events:PutRule"
                    - "events:DescribeRule"
                  Resource:
                    - !Sub "arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForBatchJobsRule"
    SNSTopic:
      Type: AWS::SNS::Topic
    BatchVPC:
      Type: AWS::EC2::VPC
      Properties:
        CidrBlock: 10.0.0.0/16
    BatchInternetGateway:
      Type: AWS::EC2::InternetGateway
      DependsOn: BatchVPC
    PublicRouteTable:
      Type: AWS::EC2::RouteTable
      DependsOn:
      - BatchVPC
      - BatchVPCGatewayAttachment
      Properties:
        VpcId:
          Ref: BatchVPC
    BatchVPCGatewayAttachment:
      Type: AWS::EC2::VPCGatewayAttachment
      DependsOn:
      - BatchVPC
      - BatchInternetGateway
      Properties:
        VpcId:
          Ref: BatchVPC
        InternetGatewayId:
          Ref: BatchInternetGateway
    BatchSecurityGroup:
      Type: AWS::EC2::SecurityGroup
      Properties:
        GroupDescription: A security group for region-agnostic Batch resources
        VpcId:
          Ref: BatchVPC
    BatchSubnet:
      Type: AWS::EC2::Subnet
      DependsOn: BatchVPCGatewayAttachment
      Properties:
        CidrBlock: 10.0.0.0/24
        VpcId:
          Ref: BatchVPC
        MapPublicIpOnLaunch: 'True'
    PublicRoute:
      Type: AWS::EC2::Route
      DependsOn:
      - PublicRouteTable
      - BatchVPCGatewayAttachment
      Properties:
        RouteTableId:
          Ref: PublicRouteTable
        DestinationCidrBlock: 0.0.0.0/0
        GatewayId:
          Ref: BatchInternetGateway
    BatchSubnetRouteTableAssociation:
      Type: AWS::EC2::SubnetRouteTableAssociation
      Properties:
        RouteTableId:
          Ref: PublicRouteTable
        SubnetId:
          Ref: BatchSubnet
    BatchAWSBatchServiceRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Principal:
              Service: batch.amazonaws.com
            Action: sts:AssumeRole
        ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole
    BatchIamInstanceProfile:
      Type: AWS::IAM::InstanceProfile
      Properties:
        Roles:
        - Ref: BatchEcsInstanceRole
    BatchEcsInstanceRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: '2008-10-17'
          Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
        ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
    BatchJobDefinition:
      Type: AWS::Batch::JobDefinition
      Properties:
        Type: container
        ContainerProperties:
          Image:
            Fn::Join:
            - ''
            - - 137112412989.dkr.ecr.
              - Ref: AWS::Region
              - ".amazonaws.com/amazonlinux:latest"
          Vcpus: 2
          Memory: 2000
          Command:
          - echo
          - Hello world
        RetryStrategy:
          Attempts: 1
    BatchJobQueue:
      Type: AWS::Batch::JobQueue
      DependsOn:
      - BatchComputeEnvironment
      Properties:
        Priority: 1
        ComputeEnvironmentOrder:
        - Order: 1
          ComputeEnvironment:
            Ref: BatchComputeEnvironment
    BatchComputeEnvironment:
      Type: AWS::Batch::ComputeEnvironment
      DependsOn:
      - BatchSubnet
      - BatchSecurityGroup
      - BatchIamInstanceProfile
      - BatchAWSBatchServiceRole
      Properties:
        Type: MANAGED
        ComputeResources:
          Type: EC2
          MinvCpus: 0
          DesiredvCpus: 0
          MaxvCpus: 64
          InstanceTypes:
          - optimal
          Subnets:
          - Ref: BatchSubnet
          SecurityGroupIds:
          - Ref: BatchSecurityGroup
          InstanceRole:
            Ref: BatchIamInstanceProfile
        ServiceRole:
          Ref: BatchAWSBatchServiceRole
  Outputs:
    StateMachineArn:
      Value: !Ref BatchJobNotificationStateMachine
    ExecutionInput:
      Description: Sample input to StartExecution.
      Value:
        >
          {}