仮説検証と技術選定のお話
自分の欲しいものを作った際に、色々試してたくさん学びを得られたというお話です。
概要
以下のような変遷で半年くらい断続的に旅をした結果、割と満足な結果を得られました。
- 第0世代 概念実証時代
- 第1世代 概念実証のリフト&シフト時代
- 第2世代 クラウドネイティブ時代の幕開け
- Puppeteer + TypeScript(ブラウザの自動操作)
- Cloud Functions(実行環境)
- Pub/Sub(分散実行)
- 第3世代 AWSで IaC な時代
- Puppeteer + TypeScript
- AWS Lambda(実行環境)
- Amazon SQS(分散実行)
- AWS CloudFormation(デプロイ自動化)
遠回りで無駄の多い旅路ではありましたが、振り返ると全体的に有意義であったように思います。
この記事は、各段階で考えたこと・感じたことについての備忘録です。
概念実証時代
今年(2021年)の5月ごろ、あるジャンルの商品を毎日たくさん、各商品おひとり様一個限定で、原価割れの価格で販売しているWebサイトがあることに気が付きました。
毎日回収すればお得そうだったので、bot*1を作って自動で回収できるようにしたいと思いました。
そこでとりあえず、以前使ったことのあった Selenium を使ってbotを作りました。
かなり雑な作りで動作も遅く、実行完了までに1時間弱かかるような出来ではありましたが、数年前に使ったことのある技術のみで作ったので小さな学習コストで、週末のうちに作り終えることができました。
この時代を通して、仮説を検証するために何かを作るにあたっては、とりあえず知っている範囲の知識で、できる限り低コストで作成すると企画倒れしないことがわかりました。
概念実証のリフト&シフト
とりあえずbotが動作するようになり、タスクスケジューラを設定したことで毎日自宅の端末で自動実行されるようになりました。
1か月くらい運用した結果、安定して収益を得られることが分かったので、今度はクラウドに置いてより確実かつ低コストで実行できるようにしたいと思うようになりました。
永遠に無料でメモリをブラウザが動くくらい多めに(1GB以上)使えて、連続実行可能時間が長め(最低1時間)なサービスを探した結果、GCPの Cloud Run がいい感じだとわかったので、botをそこで利用できるように改修しました。
こんな感じ で Docker コンテナ内に Flask でWebサーバを立てて、そこにGCPの Cloud Scheduler からHTTPリクエストを定時で投げるようにすることで実現できました。
Dockerコンテナの定義を作るのは初めてだったので、色々学べて楽しかったです。
(コンテナの中身は思ったより普通にLinuxで、Dockerfile の文法にさえ慣れればいい感じに書けるようになったので、もっと早く覚えればよかったと思いました。)
この時代を通して、苦手意識を長年持っていたDockerと仲良くなれました。
クラウドネイティブ時代の幕開け
時が経ち、多くの気づきを得て当初の数倍の回数の操作を繰り返して実行したくなったので、botを改修する必要が出てきました。
Cloud Runのようなコンテナのマネージドサービスでは大抵連続して1時間しかコンテナを実行できず、現状のままでは時間内に終わらないため、クラウド上で使い続けるには
- EC2みたいなIaaSに引っ越す
- 現在のモノリシックな構成を見直し、細かい単位で分割して実行されるようにする
あたりの対策を取る必要がありました。
1 だとサーバの料金が嵩みそうだったのと、せっかくなのでメンテナンスしやすくスケーラブルと噂のクラウドネイティブなアーキテクチャを体験してみたかったので、FaaSで実行できる単位に分割して実装しなおすことにしました。
GCP の Cloud Functions は、2GBのメモリのインスタンスを毎月74時間ちょっと無料で使えるらしいので、それを使ってみることにしました。
処理の分割の仕組みとしては、2つ関数を用意して、1つ目の関数で購入対象を特定してキュー(Pub/Sub)に入れて、2つ目の関数にちょっとずつ渡して順番に処理するという方法を採用しました。
これにより、各関数の実行時間を長くても5分以内に抑えることができるようになりました。
また、最近は Puppeteerの方がSeleniumより高い評価を受けているという話を聞いたので、書き直しついでに中身もPuppeteerに変えることにしました。
ネットやGithubで調べても同じことをやってそうな人がいなかったので、とりあえずテンプレートを作って置いときました。(後で誰も使ってない理由を理解することになるのですが...*2)
botの改修が完了し、以前は制限時間内に終わらなかったりしてたまに失敗していたbotがより確実に動作するようになり、また処理対象を増やすことができたので、以前の数倍の収益を得られるようになりました。
また、Puppeteerもすべてを明示的に非同期で待機させる思想が非常に好感触でした。*3
この時代を通して、分散処理の偉大さを学びました。
AWSでIaCな時代
改修の結果、毎月程々にまとまった利益が得られるようになったので、家族や親しい友人に展開して使ってもらうことで、もっとスケールさせたくなってきました。
しかし、これを実現するには一つ大きな障害がありました。
それは、デプロイの設定の大部分を手動で行う必要があることです。一般人にとって、たとえマニュアルがあったとしても慣れない操作をするのは非常に厳しいと思われます。
そこで、全体的にIaC(Infrastructure as Code)化を進めることで、誰でもコマンド一つだけでデプロイできるようにしようと考えました。*4
Cloud FunctionsでIaCを実現するための Cloud Deployment Manager をまず試してみましたが、Cloud Functions の定義を含む多くの主要な機能がbetaリリースだったりしてドキュメントやサンプルが少なく、利用のハードルがかなり高い状況だったため断念しました。
GCPが流行っていないのは、こういうところが原因なんだろうなと感じました。
そうこうしているうちに、AWSの Lambda にもかなり大きめな(毎月メモリ40万GB秒ぶんの)無料枠があることに気づいたため、長い間お世話になったGCPから、圧倒的なクラウドエコシステムを持つと音に聞くAWSに宗旨替えしてみました。
AWSのIaC基盤であるところのCloudFormationのテンプレートを初めて真面目に*5作ってみて、(GCPと比べて)ドキュメントやコミュニティが非常に充実していることに驚きました。
LambdaをSQSと組み合わせるテンプレートを公式が提供してくれているし、CloudFormationのテンプレートの各項目は細かいところまでドキュメント化されており、あらゆる情報がブログやStackOverflowに蓄積されています。
これ みたいに、私の欲しいサンプルやドキュメントも全部あったので、参考にしながら非常に容易に実装することができました。
最終的に、AWSコンソールでの操作を行うことなくCloudFormationですべてのリソースを自動作成してデプロイできるようになりました。
この時代を通して、AWSの信者になりました。
全体の感想など
プライベート・仕事を問わずあらゆる場面で役に立ちそうな開発スキルが色々身に付き、お小遣いも毎日もらえるようになる最高の体験でした。
皆さんもぜひ、あなたの見つけた素敵なアイデアを実装する旅に出かけてみてはいかがでしょうか。