外資就活プロダクトエンジニアリングチームで主にバックエンドの開発をしています、広瀬です。 ハウテレビジョンにジョインして半年経ちました。
弊社では勤怠管理に freee を導入していますが、freee の API を使用して Slack からスタンプで打刻できるアプリを自作して運用しています。公式にも同様のアプリ(人事労務freee)があるようですが、共有のチャネル上でおこなうことで、他の人の勤務状況も見える形にしています。
これまではこの勤怠ボット(Slack アプリ)を Heroku 上で動作させていたのですが、利用する外部サービスの整理・統一をおこなう中で、AWS に移行することになりました。
勤怠ボットの概要
勤怠ボットの基本的な動作は以下のとおりです。
- Slack 上でコマンドを入力をトリガーに、freee の認証画面を開くダイアログを表示する。ブラウザ上で認証が成功すると勤怠ボットへリダイレクトされるので、ユーザーごとのアクセストークンを DynamoDB テーブルに保存する。
- Slack チャネルへの特定のメッセージ投稿をトリガーに、保存しておいたユーザーごとのアクセストークンを利用して freee API を呼び、打刻をおこなう。アクセストークンの有効期限に応じて更新をおこなう。
実装の詳細には触れず基本的にはそのまま移行したため、ここでは実装の詳細については触れません(理解していません)。
参考
- Bolt (Slack アプリケーションフレームワーク)
- freee Developers Community (freee API リファレンス)
AWS Lambda での問題点
社内向けのサービスのためアクセス頻度も多くはないため、コストを考えると AWS Lambda で動作させるのが最適と考えていました。しかし既存アプリをそのまま移行しようとすると、以下のような様々な問題がありました。
- 既存の勤怠ボットアプリが JST で動作することを前提としていたが、AWS Lambda は UTC 固定。
- TZ 環境変数で変更できそうだが、動作保証外とのこと。
- node_modules を含めると、AWS Lambda のサイズ上限 250 MB をオーバーしてしまう。
- esbuild でバンドルすることで制限以下に減らることができましたが、使用していた DI ライブラリが要求している emitDecoratorMetadata 設定に esbuild が対応していないらしく、正常に動作しませんでした。
- Slack からのリクエストだけでなく freee からの OAuth 認証コールバック受信をおこなっているが、Bolt の Lambda アダプターとの併用がうまくできない。
- 短時間で処理を完了できず、タイムアウトしてしまう。
- Slack は 3 秒以内に応答を返さないといけないため通常はレスポンスを返してから実処理をおこなう形となりますが、Lambda では途中でレスポンスを返すことができません。Bolt の Lazy Listeners という機能を使うと解決しそうではありましたが、時間の都合上ちゃんと試すことができず(無念)。
実装をよく把握してそれぞれ対応すれば解決はできたかもしれませんが、基本的には今あるものを動かすことを優先して、他の方法を検討することにしました。
AWS App Runner を選択した経緯
Lambda のランタイムでなくコンテナのまま動作させるため、以下のサービスを検討しました。
AWS Lambda (コンテナ)
Lambda ではランタイムではなくコンテナイメージを動かすこともできます。この場合 1~3 は解決できそうですが、まだ大きな 4. の課題は残ります。
Amazon ECS
サーバーレスは諦めて普通にコンテナで動かしてしまおうか・・しかし今までよりコストがかかるのは明白。社内用のサービスなのでコストは可能な限りケチりたいところ。ALB を省くと HTTPS の設定が面倒になりそうです。
AWS App Runner
App Runner は、コードまたはコンテナイメージから直接ビルド、デプロイ、オートスケールするサービスを構築するマネージドサービスです。ECS + ALB + デプロイワークフローをワンセットで提供してくれるようなもので、今回のようなツールに対しては大がかりかなと思っていたのですが、料金体系が ECS とは異なりアクセス数が少ない場合にはむしろ安上がりになるようでした。
料金
App Runner では、処理していない時間はスタンバイ中のメモリーサイズに対してのみ料金がかかります。単価は以下のとおり。
- プロビジョニング: 0.007 USD/GB・h
- アクティブ時: 0.064 USD/vCPU・h + 0.007 USD/GB・h
スペックは最小の 0.25 vCPU, 512 MB で問題なく動作したため、プロビジョニングに対する料金は 2.5 USD/月ほど。実際に運用してみたところ、月間 20,000 リクエスト程度であり、合計で 3.5 USD/月程度に収まっています。
使用するサービスごとの料金を比較してみると、以下のとおりでした。
サービス | 月額料金 (概算) | |
---|---|---|
AWS Lambda | ほぼゼロ | |
Amazon ECS (on EC2) | 10 USD (t3.micro の場合) | ALB を使用する場合 + 18 USD |
Amazon ECS (on Fargate) | 11 USD | ALB を使用する場合 + 18 USD |
AWS App Runner | 3.5 USD |
構築
社内サービスとはいえ、いや社内サービスだからこそ属人化してしまいがちなのでちゃんと IaC も組んでおきました。手順の一部は以下に整理したのでよろしければご覧ください。
まとめ
App Runner はスケールする Web サービスを簡単に構築することに優れていますが、制限が多かったり、ブラックボックスな点もあり本番サービスに活用するにはまだ難しい点もあるように思います。そのため様子見ではあったのですが、逆にこのようなちょっとしたツールに使うのもコスト面で良いかもしれません。