見出し画像

AWS Step FunctionsとAmazon ECSタスクで構成するバッチ基盤

みなさんこんにちは。マクアケ開発本部SREチームの稲村(@kzm0211)です。最近iPhone13miniからiPhone15に乗り換えたので、Lightningケーブルを片っ端から処分できてとても気分が良いです。

さて、最近弊社ではとあるバッチの実行基盤にAWS Step FunctionsとAmazon ECSタスクを使った構成を採用したのでそのお話をしようと思います。


バッチ基盤を検討するに至った経緯

弊社では、Jenkins の定期ジョブ実行機能をバッチサーバーの役割として利用しており、現在も現役バリバリ(死語?)で稼働しています。この基盤には比較的クリティカルな課題があり、近いうちにリプレイスを計画することにしました。

課題そのものについては今回は深くは説明いたしませんが、大きなポイントで言うとSPOFであること、スケーラブルではない構成にも関わらず、バッチが増え続けているため今後EOLや大きな問題が発生した際に、簡単にリプレイス出来ないことが挙げられます。

バッチ基盤の要件

細かい要件はいくつかありますが、概ね下記の要件を満たす構成を検討しました。

  • FuelPHP Tasksによるバッチ実行

  • 既存のバッチ基盤ではDockerイメージで実行されているため、既存のECRを使いまわしたい

  • バッチ実行に伴う引数は可能な限りそのまま使えるようにしたい

  • 多くの場合は10分以内に終了するが、数十分実行する長時間のバッチも存在する

  • 場合によっては事前処理を実施したい

  • スペックは柔軟に指定したい

  • リトライ処理を入れたい

  • 成功、失敗の通知をSlackに送りたい

  • 失敗した時に再実行ができるようにしたい

バッチの多くはFuelPHPのTasksを使っており、コンテナをベースとして稼働しています。よって、基本的にはコンテナをベースとした基盤を検討しました。

採用したバッチ基盤の構成

上記要件を踏まえて、弊社で主に採用しているAWSとGCP上のGKEの中で、下記が検討課題にあがりました。

このような構成比較表は他社でも多数にあるので詳細は割愛しますが、主に下記観点で比較を実施しました。

結論として、AWS Step Functions+Amazon ECSタスクの構成を採用しました。

理由としては、要件の時点でお気づきの方もいると思いますがバッチ基盤と言いながら、すでにJenkinsは単なるcronジョブを実行する仕組みではなく、簡易なワークフローの仕組みが求められていることから、シンプルな仕組みだけでは解決できないということが挙げられます。

そのため、ある一定構成に柔軟性があることと、通知や事前処理が行えるという要件を満たす構成としてAWS Step Functionsをベースとした基盤を採用することとしました。

ちなみに簡単にAWS Step Functionsについて説明すると、分散サービス群をワークフローとして連携させることのできる、オーケストレーションサービスです。AWSが提供する各サービスのそれぞれのAPIを複数実行することができ、1つのAPI実行単位を1ステップとして、ステップ数ごとに課金が発生する仕組みとなっています。

同様の仕組みとして、LambdaでAWSの各APIを実行するように実装するという方法もありますが、必要なインフラを事前に用意してAWS Step Functionsを使って各サービスを条件に応じてつなぎ合わせることで、ロジックの作り込みを減らすことができるようになります。

詳細は下記公式ドキュメントをご参照ください。

採用した構成の詳細

この構成では最小要件として、大きくわけて下記の3つの機能を実装しました。

1つ目はAmazon ECSタスクのタスク定義をOverrideして実行すること
2つ目はAWS Lambdaを使って、Slackへ通知を実施すること
3つ目はAmazon EventBridge Schedulerの重複実行を、Amazon DynamoDBを使って抑制すること

1つ目、ECSタスクのタスク定義をOverrideすることでFuelPHP TasksをJenkinsのときと同じ様に実行することが可能となりました。

2つ目のAWS LambdaによるSlack通知については、AWS ChatbotとAmazon SNS連携も検討したのですが、当時は通知内容をカスタマイズすることができず、無骨な通知を行うことしかできませんでした。

これだとどのバッチが成功したか失敗したかがパッと見でわからず不便なため、AWS Chatbotの採用は諦めてAWS Lambdaを使ってSlack通知するように実装しました。

※2023/9/12 にAWS Chatbotの通知のカスタムが行えるようになっているようです。
https://aws.amazon.com/jp/about-aws/whats-new/2023/09/custom-notifications-aws-chatbot/

また、バッチの実行ステータスがわかるようにAWS Step Functionsで工夫した点として、各ステップごとにAWS Step FunctionsのPassステートを通すようにしました。

Passステートの説明は下記の公式にあるように、なにもせずにデバッグのために使うこともできますが、「フィルターを使用して JSON ステート入力を変換し、変換されたデータをワークフローの次のステートに渡すこともできます」とあるように、入力結果を別のJSON形式に変換することが可能です。

上記仕組みを利用して、Parametersとして通知に必要な値を加工するようにしました。

これにより、ステートの度に変わるJSONを意識することなく、Lambda側では入出力を統一することが出来ました。

3つ目のAmazon DynamoDBへのIDの保存については、本基盤の調査時にAmazon EventBridgeの仕様として下記クラスメソッド社の記事を拝見し、念のためAWSのサポートにも問い合わせを実施して実装しました。

AWSサポートからは、Amazon EventBridgeは稀に短時間内に重複実行する場合があるとの回答をいただいたため、クラスメソッド社のブログ記事の実装をそのまま採用しています。

本実装により、EventBridgeの基盤の制約とも言える重複実行を制御しています。

具体的には、EventBridge Schedulerが実行されたときのIDをDynamoDBに保存して、バッチが実行されるたびに保存されたIDが重複しているかどうかをチェックします。重複している場合は、バッチを実行せずに終了します。

なお、すべてのバッチが、短時間において稀に発生しうる重複実行が許容できる場合は、当該実装は不要であると言えます。

また、正常にバッチが実行されている状態で、EventBridgeの重複実行ではなく単純な定期実行によるバッチ実行の重複は本実装では制御できない課題があります。たとえば5分おきに実行するジョブが、そのタイミングで処理するデータ量により、稀に実行が5分以上かかってしまうとします。このとき、次の実行はスキップさせたいのですが、素朴な実装ではそれを実現することができません。

この辺りは実行するバッチ自体の特性や、重複実行におけるリスクを踏まえて、必要な調査を検討したほうが良さそうです。

弊社の今後の課題として、このバッチ自体の重複実行制御においても上記同様のDyanamoDBを使ったIDチェックが採用出来ないか検討中です。

実際に採用してみて

すべてのバッチを置き換えるのはリスクがあるため、2023年9月現在ではまずは一部チームのバッチ実行のみ採用を実施しました。
※当該基盤の話をした際に採用を前向きに検討してくれた社内チームに感謝!

SRE管轄ではない別チーム管理のバッチのため、導入まではSREチームで行い、本番導入時のフォローをしてもらいながら進めて、導入後の管理はお任せするようにしました。最初は単一のバッチ実行から始めましたが、新しいバッチ基盤導入後はそのチームで別のバッチも追加してくれたようで、問題なく稼働しているようでした。

▼マクアケ開発各チームとSREチームの連携についてはこちら

すべてTerraformで管理し、バッチの追加もすべてtfvarsでJSON形式で行えるようにしたことと、できる限りAWS Step Functionsの構成をシンプルにしたことと、構成説明を何度か行ったこと、あとなにより当該チームがTerraformの運用をすでに行っていることが成功した要因だと考えています。

今後の展望

現在は通知部分がAWS LambdaになっているのでAWS LambdaをやめてAWS Chatbot+Amazon SNSに変更すること、また、他のバッチ自体を切り替えてJenkinsが抱える課題を解決していこうと目下取組中です。

また、AWS Step Functions自体の学習コストが高く、クラウドインフラ担当ではない場合にキャッチアップのハードルがあることと、既存のJenkins上での作業に開発メンバーが慣れているため、完全に切り替えるまでには相当の準備と覚悟が必要だと考えています。

クラウドインフラに知見のあるメンバーによる手厚いサポート、そして将来的には組織としての知見獲得を、SREチームとして今後推進していく予定です。

AWS Step Functions自体は、AWSの各サービスのAPIを簡単に呼び出せてとても便利です。構成管理がJSONのため、最初は慣れるまで大変ですが、構成の適用は一瞬で行えますし、先述したPassステートを活用することでデバッグも容易に行えます。

本記事がバッチ基盤の選定や、AWS Step Functionsの導入を検討している方の一助になれば幸いです。

 --------------------------------------------------------------------------

現在マクアケではエンジニアの募集をしております。
もっとマクアケについて知りたい方は、社員インタビュー記事や以下リンクからカジュアル面談・エントリーのお申し込みをお願いいたします!

◉エントリーをご希望の方

◉カジュアル面談をご希望の方

◉マクアケの中の人を知りたい方

この記事がおもしろかった!と思っていただけたら、是非「スキ」&「シェア」をしていただけますと嬉しいです。

この記事が気に入ったらサポートをしてみませんか?