私はサイドプロジェクトで Wazaterm というWebサービスを開発しています。 WazatermはブラウザからLinuxを操作する端末(Terminal)Webアプリケーションです。 SSHでVPSなどのサーバに接続してリモート上で開発している人をターゲットとしています。
今年はWazatermアドベントカレンダーで使い方等を説明しているので詳しくはそちらを見ていただければと思いますが、特長として下記があります。
- ブラウザから操作するのでOS/Device非依存
- CPUとメモリを自由に選べる
- SSHが使える
- ルート権限がある
- WebhookによるSuspend, Resumeの自動化できる
- バックアップを取れる
- 250以上のテーマから選べる
- ブラウザを利用するので日本語入力ができる
この記事では、Wazatermの解説よりもどのようなアーキテクチャになっているか説明したいと思います。
サービスの全体像
コスト面で有利なスポットインスタンスの利用
AWSのEC2スポットインスタンスを利用しています。最近ではスポットインスタンの価格帯も安定しています。そして、キャパシティが足りなくてTerminateされるということも滅多にありません。Amazonのブラックフライデーでも少なくても私が使っているインスタンスは落ちることはありませんでした。Wazaterm にスポットインスタンスを利用したのはやはり価格面です。最大80%以上のコストのメリットがあります。また利用していないときに停止することができるのも環境に優しいので良い点だと思います。
コンテナとしてLXDを採用
EC2インスタンスとユーザが使うLinuxの権限を分けるためにコンテナを利用しました。データを保存する必要があるのでDockerでは実現することはできないので、いくつかコンテナやVMを検証しましたが直感的にわかりやすく、ドキュメントもある程度しっかりして、Linuxでは広く使われているLXD/LXCを採用しました。
ホストOSにはDebianを採用
AWSのスポットインスタンスでは明確にhibernateをサポートすると言っていませんが、検証してみるとhibernateが成功するタイプのインスタンスがあることがわかりました。ホストOSがUbuntuのときに失敗するケースがあり、Debianの方が成功したのでDebianを採用しました。他のディストリビューションは検証していません。
PackerでAMIを作成
ホストのイメージも毎回手動で入れるのは面倒なのでPackerを利用しています。冪等性ですね。
Heroku上にRails
サーバは慣れているRailsを採用しました。メインの業務でも開発して5年になるので呼吸をするように開発できます。RailsからAWS Ruby APIを叩いています。シンプルな構成をHeroku上に構築しています。
- Postgres — main DB
- Redis — background job(Sidekiq) + cache
- Sendgrid — email
- Papertrail — log
ttydを使いUbuntuコンテナにアクセスする
ブラウザからterminalを使うJSモジュールは数多くあります。VS Codeのターミナルで使われるxterm.jsとサーバプロセスの組み合わせのモジュールもたくさんあります。私はttydを採用しました。ttydをforkしてビルドしたものを使っていたのですが、esbuildを試したくなり、ttydのソースをコピーしてきてRails側でPrecomileしています。JSはtypescriptです。(適材適所でレイアウトで切ってJQueryも利用しています)
課金回り
Stripeを採用しています。やはりAPIドキュメントが素晴らしいです。3時間ぐらいで課金回りを実装できたのは驚きました。Paypalのこととか思い出すと遠い目になりますね。
まとめ
個人のプロジェクトでSasS(Paas寄り?)を作るのは面白いです。インフラからフロントまで全て作れるので、全ての技術スタックを検証して実装、またそれを考えるのは楽しいですね。サイドプロジェクトで実験したものを本業へと知見を生かせているのでとても良いサイクルです。”プログラマたるもの自分のツールは自分で作る”を実行できています。できればマネタイズもできれば良いのですが、まぁそれは数年かけてということにしておきます。
PS 来年はGraviton2(Graviton3も)を検証して導入していきたい。