バフェット・コードのブログ

企業分析やプロダクト開発にまつわる記事を配信中

バフェットコードのインフラ今昔物語

こんにちは!しゅう です。

過ごしやすくていい季節ですね、ずっと春であってほしい(花粉さえなければ)!

よろしくします。

バフェットコードのインフラ今昔物語

はじめに

現在(2025年4月)のバフェットコードは、AWS Elastic Container Service Fargate(以下、AWS ECS Fargate) をアプリケーションの実行環境として採用している1

バフェットコードのアプリケーションは、ざっくり分けると

  1. インターネットに"バフェットコード"を提供するRuby on Railsアプリケーション
  2. バフェットコードのデータを収集するWeb CrawlerとそれをRDBにETL2するImporter(つまりデータパイプライン)

の2つで、それは2017年の4月に僕がバフェットコードを作り始めた3頃から変わっていない。

バフェットコードのインフラ(つまり、アプリケーションの実行環境)は、これまたざっくり分けると

  1. 2017 ~ 2018: Heroku + さくらのレンタルサーバ
  2. 2018 ~ 2023: AWS Elastic Beanstalk + AWS Batch
  3. 2023 ~: AWS ECS Fargate + AWS Batch

の3つの時期がある。

今日は、バフェットコードのインフラの歴史を簡単に振り返ってみようと思う。

Heroku + さくらのレンタルサーバの時代

2017年の4月から2018年の4月まで、バフェットコードはHeroku + さくらのレンタルサーバで動いていた。

簡単に図で表すとこんな感じ。

Heroku + さくらのレンタルサーバの時代

前回のkosappiの記事にもあるように、バフェットコードのCI/CDはCircleCIで行われおり、GitHubからCircleCIをトリガーしてHeroku・さくらのレンタルサーバにデプロイを実行していた。

Herokuは、当時無料でWebサービスをホスティングするのに非常に便利なPaaSで、その無料枠4は当時のバフェットコードを動かすには十分だった。バフェットコードは現在に至るまでずっと(MySQLではなく)PostgreSQLを使っているが、これはHerokuの標準サポートがPostgreSQLだったことが大きい5

データパイプラインのほうは、「パイプライン」というほどのものではなく、1日何度か動くクローラとそれを加工するためのスクリプトがあるだけだった(とはいうものの、元データが元データなので、それを加工するためのスクリプトはそれなりに作るのが大変だった)。 データ置き場は安定のAmazon S3を使っていたが、データの加工・収集は

  • Web Crawlerはある程度動きっぱなしになる
  • Importerは1日何度かCronで動く

みたいな感じで、料金的にちょうどいいマネージドサービスが見当たらず、AWS EC2と比較してだいぶ料金的にお得だったさくらのレンタルサーバを採用した。

「料金の話ばかりしている」と思われるかもしれないが、当時のバフェットコードは、「週末有志が集まって、趣味の範囲でコードを書く」という感じだったので、とにかくインフラ費が負担にならないようにしたかった。

当時はまだ有料機能どころかログイン機能すらなく、また広告も貼っていなかったので、我々はインフラ費どころか「稼ぐすべ」を全く持たなかったのである。

AWS Elastic Beanstalk + AWS Batchの時代

サービスを作り始めて1年くらい、サービスを公開6してほどなくして、Herokuの無料枠がリソース不足になり始める。特に、そこそこのサイズのHeroku Postgresはそれなりにお金がかかり、AWS RDSのほうがお安いくらいだったので、今後のことも考えてAWSに引っ越すことにした。

2018年の4月から、AWS Elastic Beanstalk(以下、AWS EB) + AWS Batchの時代が始まる。

AWS Elastic Beanstalk + AWS Batchの時代

Ruby on Railsのアプリケーションに関しては、本当にそのまま

  • Heroku Web Dyno => AWS EB
  • Heroku Postgres => Amazon RDS

に移行した。AWSはHerokuと比較して使えるマネージドサービスが多く、より自由にアーキテクチャを設計できるようになった。

同時期、データパイプラインも複雑なものになってきて、素朴なcrontabではbatchを管理しきれなくなり、ジョブスケジューラを導入する必要が出てきた。スケジューラには様々な選択肢があったが、「その気になればPythonで何でも書ける」という自由度と、リトライのしやすさ、また僕が使い慣れていた事もあってApache Airflowを採用し、AWS EBで運用することにした。当然DBにはAWS RDSを用いる。

CrawlerとImporterはAWS Batchとして記述し、その依存関係をAirflowのDAGで管理する。この構成にしたことで、ETLをAirflowのDAG7として柔軟に記述できるようになり、またAWS Batchのお陰で直接的なランタイムの管理からも開放された。必要なときに必要な分だけリソースを確保・処理できるAWS Batchは、バフェットコードのような、ビジネスの規模の割にデータ処理が重いサービスと非常に相性がよく、バッチベースのETLでは、現在もこの仕組みを使っている。

それなりにお金がかかるようになってしまうが、ちょうどその頃ログイン・有料プランの機能の提供を考え始めていて、サービスの可用性・信頼性のことを鑑みても、インフラにそれなりにお金を使うべきタイミングが来ていた8

AWS ECS Fargate + AWS Batchの時代

2023年、バフェットコードのインフラは現在のAWS ECS FargateとAWS Batchを中心とした構成に移行することになる。

AWS ECS Fargate + AWS Batchの時代

この移行を決定した最大の理由は、個人の開発環境はDocker/Docker Composeで環境構築が気軽にできる一方で、本番環境がAWS EB(つまりはEC2インスタンス)のAmazon Linux上で直接動いているというギャップが、アプリケーションの運用やメンテナンスを複雑にしていたことにある。

AWS EBは OS(Amazon Linux) x ランタイム(Ruby) x ミドルウェア(Ruby on Rails)で"プラットフォーム"と呼ばれる実行環境がバージョン管理され、それなりの頻度でプラットフォームの更新タスクがやってくる。特にAmazon Linuxのバージョンアップが鬼門で、ネイティブライブラリのbuildが通らなくなったり、起動・終了スクリプトのPATHが微妙に変わって動かなくなったり、ちょっとしたことでハマることが多かった。そして、それを解決するにはEC2インスタンスにsshして何が起こっているかを詳細に調べる必要があり、EBのプラットフォームのバージョンアップはチームの一大イベントになってしまっていた。

これらの運用負荷を抜本的に解消するため、Amazon ECS Fargateに移行することにした9。 前述の通り、個人の開発環境はすでにDocker化されていたので、GitHub ActionsでビルドしたDockerイメージをECRにpushし、ECS Fargateで実行すればよかった。大変だったのはむしろアプリケーションをECSで動かす以外の部分、例えば起動・終了スクリプトや監視やログ収集の移行であった10

あわせて、データパイプラインでも、ECS on Fargateの利用を開始した。AirflowはRuby on Railsのアプリケーションと同じく、EBからECSへの移行を行った。さらに、CrawlerをAWS Batchでのバッチ処理からECSでの常駐プロセスへの変更した。これはサービスが成長し、収集すべきデータの量が増えたことに加えて、より即時性も求められるようになったためだ。 日次処理が中心だったImporterのバッチ処理も、毎時、一部では15分ごとに実行するものが増えてきている。

Webサーバの実行環境をAWS EBからAWS ECS Fargateへ移行は、単位時間あたりの料金はEBに軍配が上がるが、諸々の運用負荷(つまるところ我々エンジニアの人件費)を考えると十分元が取れると判断した。 一方Crawlerのバッチ処理から常駐プロセスへの移行は、ECS上にTaskが常に起動し続けることになるため、時間単位の従量課金であるAWS ECS Fargateの料金にそのまま反映される。また、運用面でも「失敗したらエラー通知して、必要に応じてリトライ」というような簡単なものではなくなり、Webサーバと同様に監視が必要になり、それにもまた料金がかかる11。 この頃には少しずつ年間で契約しくれる法人利用のお客様も増えてきて、それに伴って求められる機能の期待値も変化しており、まさに「レイテンシとスループット(つまりAWS ECSのコスパ)はトレードオフ」な選択をしたと言える。

まとめ

今回は、リリース前から現在までのバフェットコードのインフラの歴史を振り返ってみた。こうしてみると、インフラの歴史はアプリケーションの、もっと言えばバフェットコードのサービスそのものの成長と密接に関連していて、バフェットコードの成長とともにインフラも進化していったことがわかる。

当たり前のことだが、AWSに限らずクラウドのサービスはお金をかければかけるほど便利な機能を使えるようになるし、運用時の心配事も少なくなる。その一方で、インフラのコストはそのまま会社の利益を圧迫するので、コスパの観点は常に重要である。売上の増分がそのままAWSへの支払いの増分になってしまったら、本末転倒だ。

また、バフェットコードは少人数で開発・運用しているので、できる限り統一した技術スタックでインフラを構成することを心がけている。このことは、terraform moduleを使って仕組みを使いまわしたり、運用ノウハウを効率的にチームに蓄積するときに大きなメリットになる。 今後もバフェットコードのインフラは、技術の進化やサービスの拡大に応じて変わり続けるはずだ。その中で一貫して目指すのは、「コストと便利さのバランスを取りながら、エンジニアチームがより本質的な課題に集中できる環境」を安定して維持することだと思う。

宣伝

バフェットコードでは、サービスの成長にあわせてインフラ、広くは開発者体験を改善してくれるエンジニアを募集しています。 一緒にバフェットコードの成長を加速させていきましょう!

career.buffett-code.com

Appendix


  1. 当然、すべてがそうなわけではなく、多くのAWS Lambda Functionsも存在するし、検索エンジンはAWS OpenSearchを使っている。
  2. データの抽出(Extract), 加工(Transform), 保存(Load)を指す。バフェットコードのETLについては、こちらを参照。
  3. 何を隠そう、僕がバフェットコードを(少なくともシステム開発と言う意味では)最初に作り始めた張本人である。
  4. 今のHerokuには無料枠がなくなってしまった。
  5. それまで僕はRDBはMySQLとOracleしか使ったことなくて、「新しく何か作るなら、使ったことないやつを使ってみたい」という気持ちもあった。当時は8年もバフェットコードを作っているなんて、考えもしなかった。
  6. 何を持って「公開」というかが微妙なところだが、このエントリでは「ドメインを取って、インターネットにサービスを晒す」ことを指すことにする。
  7. ものすごく雑に説明すると、「AをDownloadして、Bのデータと合わせてCをDBに入れて、その結果からDを計算する」というのを書く感じです。
  8. 2019年のクラウドファンディングがまさにそのログイン・有料プランの開発を行うためのもの。結果的に800万円を超える額を集めることができた。
  9. Amazon EKSと比較して、AWS ECS Fargateはよりシンプルで、料金面でも有利である。
  10. 特に、監視はそれまでEC2インスタンス単位でMackerelをインストールして使っていたため、抜本的な見直しが必要だった。
  11. AWS CloudWatchを使っているが、まぁそれなりのお値段になる。