AWS Batchで非同期ジョブシステムが簡単に構築出来た話
前田です。
受託開発でAPIをGolangで開発中ですが、機能要件の中で時間がかかる処理をさばく必要があり、非同期処理をどう実装しようか検討した結果、AWS Batchを使って実装しようということになりました。
AWSのマネージドサービスで非同期タスクとして実行出来るのは、たとえばAWS LambdaなどがありますがAWS Lambdaと異なる点は、「5分以内という制限がない」「Dockerイメージで実行させるので制限が少ない」というメリットがあります。
今回は特に「処理時間が長くなる場合がり、確実に処理を終了させなければならない」という要件があり、AWS Batchサービスがぴったりだということになりました。
実際にAWS Batchを構築した際、初めての構築ということもありハマった箇所もあったのですが、普通であればジョブインスタンスを立てて、など色々検討しなければいけないことが大幅に削減出来たのでトータルのコストとしてはそれほどかからなかったのではないかと思います。
受託システムで開発した設計は以下のような感じでしたがAWS Batchを使えば簡単に構築できます。
今回はローカルのawscliからAWS Batchをキックしてジョブを動かすところまで復習を込めてやりたいと思います。
AWS Batch作成
AWS Batchの構成要素には下記の3つがあります。
名前 | 目的 |
---|---|
Job queues | ジョブキュー。ここにサブミットする。 |
Job definitions | どんなジョブかの定義場所。どんなDockerイメージを使うか、も定義する。 |
Compute environments | ジョブを動かすECS(EC2)を定義する。 |
順番的にはCompute environmentsかJob definitionを先に作り、最後にJob queueを作るのがいいと思います。
では作成していきます。
AWS Batchコンソールを開き、「Get started」を押します。
Define jobの画面になりますが、wizardを使わないで今回は個別に作っていきます。
「Skip wizard」を選択します。
Compute environmentsから作っていきます。
左側の「Compute environments」を選択し、「Create environment」を押します。
「Service role」はAWS Batchに割り当てるロールで、「Instance role」はAWS Batchで起動させるEC2インスタンスに割り当てるロールです。
IAMで予めロールを作っておいてもいいですし、一緒に作成してもいいと思います。
インスタンスからS3にアクセスする場合などは、「Instance role」に紐付けたロールに後で権限を追加します。
必須ではないですが、バッチで動かすEC2インスタンスにssh接続できるとデバッグなどが捗るので、EC2 key pair
にキーを割り当ててsshログイン出来るようにしておきます。
インスタンスタイプを選択しますが、今回はm3.medium(vCPU 1)を選択しました。
あまり小さいタイプのインスタンスを選択出来ないようになっています。
普段はJobインスタンスを起動しないのであれば、Minimum vCPUsは0にしておきます。
Jobを動かす最大インスタンス数が1つでよければMaximum vCPUsに1を選択します。
注意点としては、ここで選択するSubnet(EC2インスタンスが置かれる)は、インターネットにアクセス出来るSubnetでなければならないということです。
EC2を起動し、Dockerエージェントを起動して指定したDockerイメージを起動する為にはインターネットアクセスが必要になるからです。
フォーム埋めが終わったら最後に「Create」を押して作成します。
次にJob definitionを作成します。
左側のJob definitionを選択し、「create」を押します。
ECRにイメージをアップロードしておいて、Container imageに0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/test-job:latest
といったECRのイメージを設定してやればAWS BatchがECRからイメージをダウンロードしてコンテナを起動して動かしてくれます。
今回はサンプルなので、busyboxで動かします。
Hoge
という名前の引数を受け取って実行してみるので、コマンドはecho Ref::Hoge
にします。
あとは空白でCreateします。
最後にJob queueです。
左からJob queuesを選択し、Create queueを押します。
Compute environmentsに先ほど作成したtest-compute-environmentを選択してCreateします。
以上でAWS Batchでジョブを動かす環境が整いました。
ジョブをキューイング
awscliからジョブをキューイングしてみます。
IAMで適当にユーザーを作成します。
IAMユーザーはAWS Batchへのアクセスが必要なので、AWSBatchFullAccess
をアタッチします。
コンソールでキーをセットします。
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXX
以下のコマンドでジョブをサブミットします。
job-nameは任意で命名できますが、job-queueとjob-definitionはARNをセットしなければなりません。
AWS Batchコンソール画面で確認出来ますので、セットして以下のコマンドで送信します。
aws batch submit-job
--job-name submit_job_test
--job-queue arn:aws:batch:ap-northeast-1:99999999999999:job-queue/test-job-queue
--job-definition arn:aws:batch:ap-northeast-1:9999999999999:job-definition/test-job-definition:1
--parameters Hoge=test!
実行結果はCloudWatch Logsに送られます。
ちゃんと実行されることが確認出来ました。
以上でAWS Batchで非同期ジョブを実行する環境が構築出来ました。
今回はやっていませんが、ジョブのデプロイもECRにイメージをプッシュするだけなので簡単です。
あとはアプリからジョブをキックしたり、DataPipelineやLambdaと連携して定期バッチにして動かしたり、など色々応用が出来ますね。
今後も積極的に使っていきたいサービスです。