AWS上で長時間かかるプログラムを実行したいけれど、Lambda には最大実行時間15分という制限があり使えない。かといって専用のECSタスクやEC2インスタンスを作るのは大袈裟すぎる。どうしよう...
そんなときにもってこいなのが AWS Batch です。本記事では、実際にそのような状況で AWS Batch を利用した際の設定手順やトラブルシューティングについてご紹介します。
AWS Batch とは?
AWS Batch は、フルマネージドのバッチ実行サービスです。Fargate, EC2, EKSといった基盤を選択でき、コンテナイメージを用意するだけで簡単にバッチ処理の実行基盤を作成することができます。
事前準備
Batch にリソースをデプロイするにあたり、ECR にコンテナイメージを用意しておきます。
プライベートリポジトリとローカル環境間におけるイメージのpull&pushについてはこちらの記事をご参照ください。
今回は上記の「dev-km_loader」を使用します。
ジョブ設定
ジョブ設定の手順は以下の通りです。
- ジョブ定義
- コンピューティング環境作成
- ジョブキュー作成
- ジョブ作成
ジョブ定義の内容をもとに、指定したコンピューティング環境でリソースが作成され、ジョブキューに送信されたジョブを実行するイメージです。
ジョブ定義
最初にジョブとオーケストレーションの設定を行います。
オーケストレーションタイプは推奨の「Fargate」を設定します。ジョブ定義の構造は、「従来の containerProperties 構造を使用」で作成するとログ出力されない問題があったため、チェックを外してレガシー構造で作成することにします。
続いてジョブ定義の設定を行います。
上記で設定した項目は以下の通りです。
- 全般設定
- 名前:ジョブ定義名
- タスクプロパティ
- 実行ロール:ユーザの代わりにECSタスクを実行するロール。ecsTaskExecutionを指定
- エフェメラルストレージ:タスクに割り当てられるストレージの量
なお、タスク実行ロール「ecsTaskExecutionRole」に付与している権限は以下の通りです:
- AmazonEC2ContainerRegistryReadOnly
- AmazonECSTaskExecutionRolePolicy
- AmazonS3ReadOnlyAccess
- SecretsManagerReadWrite
次にコンテナ設定を行います。
上記で設定した項目は以下の通りです。
- 名前:任意のコンテナ名
- イメージ:参照するコンテナイメージのURI
- リソースの要件
- CPU:コンテナに割り当てるvCPUの数
- メモリ:コンテナに割り当てるメモリ容量
- ロギングの設定
- ログドライバー:awslogs
ロギングの設定はオプションですが、今回はコンテナのログを CloudWatch に送るためログドライバーに「awslogs」を指定しておきます。Pythonアプリケーションの場合、loggerやprintで標準出力/標準エラー出力に出力された内容を対象にログが収集されます。
最後に設定を確認し、問題がなければ「ジョブ定義を作成」をクリックして完了です。
コンピューティング環境作成
コンピューティング環境はジョブ定義と同じく「Fargate」を選択します。
インスタンス設定では、Fargate Spot 容量を使用するかを選択できます。スポットインスタンスを利用する Fargate Spot の場合、コストを大幅に節約できるとのことです。
最大vCPUはジョブ定義と同じ2としています。
ネットワーク設定では、実行環境のVPC、サブネット、セキュリティグループなどの設定を行います。
設定を再度確認し、問題がなければそのまま作成を行います。数分待ち、「Valid」となればOKです。
ジョブキュー作成
続いてジョブキューの作成を行います。
オーケストレーションタイプは「Fargate」とし、「接続されたコンピューティング環境」には上記で作成したコンピューティング環境を指定します。
ジョブ作成
作成したジョブ定義とジョブキューを設定します。
その他の設定はデフォルトのまま進み、「ジョブを送信」をクリックします。
ジョブを送信すると、ジョブの実行が開始されます。
ジョブ定義で awslogs の設定を行った場合、CloudWatchの/aws/batch/jobs配下にジョブのログイベントが出力されます。
補足:ジョブを呼び出して実行
Step Functions には Batch:SubmitJob があり、ジョブ定義とジョブキューをもとにジョブを実行することができます。他の処理と組み合わせて実行したい場合に便利です。
トラブルシューティング
ジョブ実行に失敗
以下のエラーが出た場合、ECSとECRの通信が正しくできていません。
ResourceInitializationError: unable to pull secrets or registry auth: The task cannot pull registry auth from Amazon ECR: There is a connection issue between the task and Amazon ECR. Check your task network configuration.
対策として、コンピューティング環境のネットワークの設定を見直します。今回の場合、セキュリティグループのアウトバウンドのすべての通信を許可することで解決しました。
タスク実行に失敗
「Essential container in task exited」でタスク実行に失敗した場合、アプリケーションになんらか問題がある可能性があります。主に以下の原因が考えられます。
- アプリケーション内でエラーが発生し落ちた
- アプリケーション内の処理を行うのに必要なタスクロールが設定されていない
いずれの場合も CloudWatch のログからエラーログを確認し、適切な対処を行います。
※タスクロールはコンテナのアプリケーション実行時に利用されるロールです。例えばS3バケットからのデータ取得や DynamoDB への書き込みなどが必要な場合、それらに対応する権限をもつタスクロールを設定する必要があります。
AWS Batch の場合、ジョブ定義の「タスクロール」で設定可能です。
課金について
AWS Batch 自体に料金はかからず、基盤として利用するサービス(ECS, EC2, EKS)に対してのみ料金が発生します。
今回の場合は Fargate なので、CPU、メモリ、エフィメラルストレージのコストの合計が請求対象の料金となります。こちらの例と同様に計算すると、求める料金は以下のようになります。
サービスが1つのECSタスクを使用し、月に一度約30分間(1800秒)実行されて、その間にECSタスクが2vCPU、16GBのメモリ、21GBのエフィメラルストレージを利用する場合:
- CPU:1 * 2 * $0.000014044 * 1800 * 1 = $0.05
- メモリ:1 * 16 * $0.00001536 * 1800 * 1 = $0.04
- ストレージ:1 * (21 - 20) * $0.0000000369 * 1800 * 1 = $0.00
より、月額料金は $0.09 = 13円(1ドル140円)
※上記は東京リージョンの場合
激安です。
さいごに
AWS Batch について、実際の例をもとに詳しくご紹介しました。
AWS Batch は Lambda のような実行時間制限がなく、フルマネージドで手軽に運用できる便利なサービスです。Lambda と違い自分でコンテナイメージを用意する必要はありますが、そのひと手間も苦に感じないくらいの良さがあります。
「AWS Batch を初めて知った」「Lambda でやろうと思ってあきらめた処理がある」という方は、ぜひ AWS Batch の利用も検討してみてください。