AWS Batchのプレビュー版を触ってみる #reinvent

こんにちは、虎塚です。

re:Invent 2016で登場したAWS Batchを少し触ってみました。

AWS Batchを動かす前のセットアップ方法と、Getting Startedの操作手順をご紹介します。なお、ウィザードにしたがって実行するとハマる部分があったので、本記事ではAWS CLIを使った手順に書き換えました。

AWS Batchは、2016年12月16日現在プレビュー版です。正式リリースまでに、サービスや機能が変更される可能性があります。

セットアップ準備

Getting Startedに入る前に、次の準備をおこないます。

  1. IAMロールの作成
    1. Batchロールの作成
    2. ECSインスタンスロールの作成
  2. key-pairの作成
  3. VPCの作成
  4. セキュリティグループの作成
  5. 最新版のAWS CLIのインストール

1. IAMロールの作成

本ステップで作成する2個のIAMロールは、AWS Management ConsoleからBatchを初めて作成する時に、自動で生成されます。ただし、AWSサービスの役割や依存関係を理解するために、今回は事前に手動で作成します。

1.1. Batchロールの作成

AWS Batchは、ほかのAWSサービスを呼びだすため、AWS Batchに適切なパーミッションを与える必要があります。

IAMロールにAWSBatchServiceRoleがすでにあるかを確認します。 

aws iam list-roles | jq -r '.Roles[].RoleName' | grep AWSBatchServiceRole

AWSBatchServiceRoleがまだ存在しなければ、次の手順で作成します。

まず、信頼関係のポリシーファイルを作成します。

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "batch.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

次に、上のポリシーファイルを指定して、IAMロール (AWSBatchServiceRole) を作成します。

aws iam create-role \
  --role-name AWSBatchServiceRole \
  --assume-role-policy-document file://TrustedEntityForBatch.json

最後に、上のIAMロールに、マネージドポリシーのAWSBatchServiceRoleを適用します。

aws iam attach-role-policy \
  --role-name AWSBatchServiceRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole

AWSBatchServiceRoleは、AWSが提供するIAMポリシーです。現時点のポリシードキュメントは、次のページを参照してください。EC2、ECSのほかに、Auto Scalingの操作を許可しています。

1.2. ECSインスタンスロールの作成

AWS Batchは、ECSコンテナインスタンスで構成されているので、ECSコンテナagentをローカルで動かします。そのため、コンテナインスタンスをローンチするために使うIAMロールが必要です。このIAMロールは、過去にECSを起動したことがあれば、自動的に作成されています。

IAMロールにecsInstanceRoleがすでにあるかを確認します。 

aws iam list-roles | jq -r '.Roles[].RoleName' | grep ecsInstanceRole

ecsInstanceRoleがまだ存在しなければ、次の手順で作成します。

まず、信頼関係のポリシーファイルを作成します。

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

次に、上のポリシーファイルを指定して、IAMロール (ecsInstanceRole) を作成します。

aws iam create-role \
  --role-name ecsInstanceRole \
  --assume-role-policy-document file://TrustedEntityForEc2.json

最後に、上のIAMロールに、マネージドポリシーのAmazonEC2ContainerServiceforEC2Roleを適用します。

aws iam attach-role-policy \
  --role-name ecsInstanceRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role

AmazonEC2ContainerServiceforEC2Roleは、AWSが提供するIAMポリシーです。現時点のポリシードキュメントは、次のとおりです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:Submit*",
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}

ECSのクラスタ作成や、CloudWatch Logsへのログ出力を許可します。

2. key-pairの作成

AWS Batchを利用するリージョンにEC2のkey-pairを作成します。2016年12月16日現在、AWS Batchは、Virginiaリージョン (us-east-1) でだけ利用できます。

3. VPCの作成

AWS Batchを利用するリージョンに、パブリックなサブネットを1個だけ持つVPCを作成します。

4. セキュリティグループの作成

ステップ3のVPCと紐づくセキュリティグループを作成します。

AWS Batchのコンテナインスタンスは、外部からアクセスできるように設定する必要はありません。しかし、インスタンス内のログを確認したり、Dockerコマンドでジョブ内のコンテナを調査したりするために、SSH接続すると便利な場合があります。また、Webサーバの起動を含むジョブを実行する場合には、HTTP接続を許可しましょう。必要に応じて設定します。

5. 最新版のAWS CLIのインストール

AWS CLIを最新版にアップデートします。今回は、次のバージョンで動作確認をしました。

  • aws-cli/1.11.29 Python/2.7.10 Darwin/14.5.0 botocore/1.4.86
sudo pip install --upgrade awscli

Getting Started

それでは、Getting Startedを試します。

AWS Batchにアクセスして、ウィザードで設定項目を確認します。ウィザードから実行したほうが手っ取り早いのですが、まだプレビュー版のため、GUIの設定項目に足りない箇所があります。

以降の手順では、AWS Management Console (ウィザード) から設定項目の確認をしつつ、AWSリソースの作成など環境に変更を及ぼす操作は、AWS CLIでおこないます。

1. ジョブの定義

ウィザードでは、最初にジョブ定義のオプションを次の2つからどちらか選びます。

  • Using Amazon EC2
    • コンピューティング環境、ジョブキューを作成し、ジョブを実際に送信する場合に選びます
  • No job submission
    • コンピューティング環境とジョブキューを作成するが、ジョブは送信しない場合に選びます

前者を選んだ場合は後続の1.1へ、後者を選んだ場合はステップ2へ進みます。今回は、前者を選びます。

1.1. 設定項目: ジョブ実行時間

ジョブについて次の項目を設定します。

  • Job definition
    • 初回は「Create new job definition (新規ジョブ定義の作成)」です。次回以降、すでに作成したジョブを選べるようになります
  • Job definition name
    • 任意 (first-run-job-definition)
  • Job role (オプション)
    • ジョブ実行時にコンテナがAWSサービスにアクセスする場合に、必要な権限を与えたIAMロールを指定できます

1.2. 設定項目: コンテナとコマンド

ジョブ実行に使うDockerイメージとコマンドを指定します。

  • Container image
    • 255文字までの英大小文字、数字、ハイフン、アンダースコア、コロン、ピリオド、スラッシュ、シャープ
    • 今回はDocker公式リポジトリのbusybox (library/busybox - Docker Hub) を指定します

コンテナは、デフォルトでDocker Hub registryにあるイメージを利用できます。ほかのリポジトリを指定する場合は、repository-url/image:tagの形式で指定します。たとえば、Amazon EC2 Container RegistryにあるイメージをAWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/my-web-app:latestの形式で指定できます。

  • Command
    • コンテナに渡すコマンドです。docker runコマンドのCOMMANDに割り当てられます
    • 今回は「echo, hello world」を指定します
  • vCPUs
    • コンテナに何個のCPUを割り当てるか指定します。docker runコマンドの--cpu-sharesオプションに割り当てられます
    • 今回は2を指定します
  • Memory (MiB)
    • コンテナに付与するメモリのハードリミットを指定します。コンテナのメモリ使用量がこの値を超えそうになった場合、コンテナは強制終了されます。docker runコマンドの--memoryオプションに割り当てられます
    • 今回は2000を指定します

1.3. 設定項目: パラメータ

オプションで、パラメータ置換のためのデフォルト値とプレースホルダーを指定します。今回は空のままにします。

1.4. 設定項目: 環境変数

オプションで、コンテナに渡す環境変数を指定します。これは、docker runコマンドの--envオプションに割り当てられます。今回は空のままにします。

なお、ここに認証情報などセキュアに保つべき情報を平文で指定してはいけません

1.5. 作業: コマンドでジョブ定義を作成する

これまでに確認した設定項目をもとに、コンテナのプロパティをJSONファイルに記述します。

{
    "image": "busybox",
    "vcpus": 2,
    "memory": 2000,
    "command": [
        "echo",
        "hello world"
    ]
}

上のファイルを指定して、ジョブ定義を登録します。

aws batch register-job-definition \
  --job-definition-name first-run-job-definition\
  --type container \
  --container-properties file://container-properties.json

2. コンピューティング環境とジョブキューの設定

AWS Batchは、ステップ1で定義したジョブを、本ステップで設定するコンピューティング環境で実行します。AWS Batchスケジューラがジョブを実行するまで、ジョブはジョブキューに送信されます。

2.1. 設定項目: コンピューティング環境

  • Compute environment type
    • Managed
    • AWSが管理してスケールを実行するコンピューティング環境です。Getting Startedではこちらだけ選択できます。
    • Unmanaged
    • ユーザがインスタンスやスケーリングを管理するコンピューティング環境です (Getting Startedでは、こちらは選択肢として表示されません)
  • Compute environment name
    • 自分が保持しているコンピューティング環境の中で一意になる名前をつけます
    • 今回は「first-run-compute-environment」にします
  • Service role
    • AWS Batchに、AWSリソースを操作する権限を与えます
    • セットアップ手順のステップ1.1で作成したAWSBatchServiceRoleを指定します
  • EC2 instance role
    • コンピューティング環境が作成したECSコンテナに、AWS APIを実行する権限を与えます
    • セットアップ手順のステップ1.2で作成したecsInstanceRoleを指定します

2.2. 設定項目: コンピューティングリソース

コンピューティング環境の構成要素であるEC2を、AWS Batchがどのように使うかを設定します。

  • Provisioning Model
    • Ondemand
    • オンデマンドインスタンスを利用します (今回はこちらを選択します)
    • Spot
    • スポットインスタンスを利用します
  • Allowed instance types
    • 「optimal」を選ぶと、ステップ1のジョブ定義で指定した使用メモリとvCPUに合わせて、特定のインスタンスファミリー (現在はM4, C4, R3) から最適なものが選ばれます。今回はoptimalにします
    • 特定のインスタンスファミリーの指定もできます
  • Minimum vCPUs
    • コンピューティング環境に保持する最小のvCPUを指定します。0より大きい値を指定すると、ジョブキューからの要請にかかわらず、常にコンピューティング環境が稼働状態になります。今回は0にします
  • Desired vCPUs
    • コンピューティング環境の起動時のvCPUを指定します。AWS Batchは最小と最大の間で、ジョブキューの要請に応じてvCPUを増減させます。今回は0にします
  • Maximum vCPUs
    • ジョブキューの要請にかかわらず、コンピューティング環境が使用できる最大vCPUを指定します。今回は4にします

2.3. 設定項目: ネットワーク

  • VPC Id
    • セットアップ手順のステップ3で作成したVPCを指定します
  • Subnets
    • セットアップ手順のステップ3で作成したサブネットを指定します
  • Security groups
    • セットアップ手順のステップ4で作成したセキュリティグループと、VPCに最初からあるdefaultセキュリティグループを指定します

2.4. 作業: コマンドでコンピューティング環境を作成する

これまでに確認した設定項目をもとに、コンピューティングリソースをJSONファイルに定義します。

{
    "type": "EC2",
    "minvCpus": 0,
    "maxvCpus": 4,
    "desiredvCpus": 0,
    "instanceTypes": [
        "optimal"
    ],
    "subnets": [
        "subnet-12345678"
    ],
    "securityGroupIds": [
        "sg-00000000",
        "sg-11111111"
    ],
    "ec2KeyPair": "batch-test",
    "instanceRole": "ecsInstanceRole",
    "tags": {
        "KeyName": "first-run"
    }
}

上のファイルを指定して、コンピューティング環境を作成します。

aws batch create-compute-environment \
  --compute-environment-name first-run-compute-environment \
  --type MANAGED \
  --compute-resources file://compute-resources.json \
  --service-role arn:aws:iam::123456789012:role/AWSBatchServiceRole

3. ジョブキューの設定

ジョブは、AWS Batchスケジューラによって実行されるまで、ジョブキューに送信されます。

3.1. 設定項目: ジョブキュー名と優先順位

ジョブキューには、優先順位を設定できます。優先順位は、整数の昇順です。ジョブキューが、1つのコンピューティング環境に複数関連付けられているとき、優先度が高いジョブキューから先に評価されます。

  • Job queue name
    • 任意 (first-run-job-queue)
  • Priority
    • 整数 (今回は1)

3.2. 設定項目: ジョブキューとコンピューティング環境の接続

さらに、ジョブキューに接続するコンピューティング環境を選択します。ジョブは、コンピューティング環境の指定した順序とリソースのキャパシティに基づいて、ジョブキューに送信されます。

3.3. 作業: コマンドでジョブキューを作成する

次のコマンドを実行して、ジョブキューを作成します。

aws batch create-job-queue \
  --job-queue-name first-run-job-queue \
  --priority 1 \
  --compute-environment-order order=1,computeEnvironment=first-run-compute-environment

上のようにstateをオプションで明示的に指定しない場合、ENABLEになります。ジョブを受け入れ可能なジョブキューが作成されます。

4. ジョブの送信と動作確認

4.1. 作業: ジョブの送信

次のコマンドで、ジョブを送信します。

aws batch submit-job \
  --job-name first-run-job \
  --job-queue first-run-queue \
  --job-definition first-run-job-definition
{
    "jobName": "first-run-job",
    "jobId": "80b14cc4-5be9-47f4-ad66-d47386aefbfc"
}

ここで返ってくるjobIdを使って、ジョブの実行状況を確認できます。

aws batch describe-jobs \
  --jobs 80b14cc4-5be9-47f4-ad66-d47386aefbfc | jq .
{
  "jobs": [
    {
      "status": "RUNNABLE",
      "container": {
        "mountPoints": [],
        "image": "busybox",
        "environment": [],
        "vcpus": 2,
        "command": [
          "echo",
          "hello world"
        ],
        "volumes": [],
        "memory": 2000,
        "ulimits": []
      },
      "parameters": {},
      "jobDefinition": "first-run-job-definition",
      "jobQueue": "arn:aws:batch:us-east-1:123456789012:job-queue/first-run-job-queue",
      "jobId": "80b14cc4-5be9-47f4-ad66-d47386aefbfc",
      "dependsOn": [],
      "jobName": "first-run-job",
      "createdAt": 1481871353375
    }
  ]
}

しばらく待つとジョブのステータスがSUBMITTEDになり、コンピューティング環境が用意されている間はRUNNABLEになり、成功するとSUCCEEDEDになります。

AWS Management Consoleでもジョブの状態を確認できます。

AWS Batchのステータス

4.2. 作業: ログの確認

ジョブが成功した後、CloudWatch Logsにログファイルが生成されます。ジョブの実行中や失敗後には、ログが出ないようです。

  • ロググループ名: /aws/batch/job
  • ログストリーム名: JOB_NAME/JOB_ID/12345678-1111-2222-3333-121234567890
    • 例: first-run-job/80b14cc4-5be9-47f4-ad66-d47386aefbfc/393e9485-bca8-495c-9f92-35dc3c929b31

コンテナのログを確認するには、コンピューティング環境として起動されたEC2インスタンスにSSH接続します。インスタンスにパブリックIPアドレスがついていない場合は、EIPを一時的につけます (これも明示的な設定箇所はなかったので、コンピューティング環境として指定したVPCサブネットの設定によるのではないかと思います)。

/var/log/ecs/ディレクトリ下にECSのログファイルがあるので、Dockerコンテナが無事起動したかなどを確認できます。

4.3. 考察: 気づいたこと

ジョブ実行中に、AWS Batchがコンピューティング環境のために起動したAWSリソースを見ていて、気づいたことを挙げます。

  • AWS Batchが起動したAWSリソース (EC2、Launch Configuration、Auto Scaling groupなど) は、Management ConsoleからもAWS CLIからも見える (隠蔽されない)
  • AWS Batchは、今回c4.largeインスタンスを選択して起動した
    • c4.largeは、vCPU値2、メモリ3.75GiB
  • AWS Batchが起動したEC2インスタンスは、詳細モニタリングが有効になっている
  • AWS Batchが起動したEC2インスタンスは、AWSが提供するECS最適化AMI (Amazon Linux AMI 2016.09.c x86_64 ECS HVM GP2) から起動されていた
  • Auto ScalingのMaxSizeが2
    • おそらく、コンピューティング環境の設定で、Maximum vCPUsとして4を指定したため
    • AWS BatchがEC2のインスタンスタイプにc4.large (vCPU=2) を自動で選んだので、4/2=2になる
  • Auto ScalingのMinSizeが0
    • コンピューティング環境の設定で、Minimum vCPUsとして0を指定したため
  • Auto ScalingのDesiredCapacityが5分ごとに1ずつ増加して2で停止した
    • コンピューティング環境の設定で、Desired vCPUsとして0を指定したため
    • Auto Scaling groupのDefault Cooldown=300(sec)にしたがって、5分ごとに起動した
    • コンピューティング環境の設定項目では明示的に指定しなかったので、この設定値は規定の値なのかもしれない
  • AWS Batchが起動したAuto Scaling groupとLaunch ConfigurationのNameタグは、末尾に共通のIDがついている
    • 同一のコンピューティング環境の構成要素であることを示している

環境の片付け方

有効なジョブキューはいきなり削除できません。まず、StateをDISABLEDにします。

aws batch update-job-queue \
  --job-queue first-run-job-queue \
  --state DISABLED

次に、ジョブキューを削除します。

aws batch delete-job-queue \
--job-queue first-run-job-queue

ジョブキューのステータスがDELETINGに変わります。しばらくするとジョブキューが削除されます。

コンピューティング環境も同様です。まず、コンピューティング環境のStateをDISABLEDにします。

aws batch update-compute-environment \
  --compute-environment first-run-compute-environment \
  --state DISABLED

次に、コンピューティング環境を削除します。

aws batch delete-compute-environment \
  --compute-environment first-run-compute-environment

コンピューティング環境のステータスがDELETINGに変わるとともに、AWS Batchによって作成されたAuto Scaling groupのDesitredが0になります。しばらくすると、Auto Scaling groupが削除され、それにともなってEC2もterminateされます。

おわりに

今回は、プレビュー版が出たばかりのAWS Batchを触ってみました。AWS BatchはAWS Lambdaの容量が大きい版みたいな感じだろう、という噂を聞いていましたが、たしかにそういう面もあるかもしれません。巨大なvCPUやメモリを指定してジョブをまかせることができます。

といっても、echoコマンドだけでは動きがよくわからないので、もう少しメモリやCPUを消費するような作業をさせてみる必要がありそうです。また、上手く動かない時のトラブルシューティングには、コンテナの知識が必要そうなので、勉強しようと思います。

それでは、また。

参考