はじめに
こんにちは、つかちゃんと申します。
現在は大学院生をしながら、長期インターンで Web エンジニアとして働いています。
今回は、自社サービスの運用の中で発生した
VPS 上のブラウザを 24 時間動かしつつ、デプロイごとに自動で再起動させたい
という少しニッチだけど面白い要件と、そんなニッチな要件に対して、Vercel Webhook + Firebase Functions + VPS でどう解決したかをまとめました。掲載許可はもらっていますが業務内容なのでコードはありません。
対象読者
- インフラガチ勢ではなく、アプリ寄りのエンジニア
- VPS や Webhook を絡めた運用に興味ある方
使用技術
- Vercel : フロントエンドのホスティング
- さくらVPS : 24時間ブラウザ起動を行うためのレンタルサーバー
- Firebase functions : Vercel からの Webhook を受け取り、VPS に通知するための API
背景
対象となるサービスは「ビンゴゲーム」の Web アプリです。
クライアントからは、次のような要望がありました。
- 出目を自動で回し続けたい
- その画面を常にモニターに映して、プレイヤーに見せたい
- 誰かの PC を開きっぱなしにしておく運用は避けたい
そこでクライアントからは、
パソコン管理が面倒なので、アプリを 24 時間立ち上げっぱなしにしたいです
という要件が出され、弊社の社長が二つ返事で受注。実装担当が自分、という流れになりました。
当時、VPS はほぼ初挑戦で、シェルスクリプトもこの案件でちゃんと書き始めたレベルでしたが、ひとまず次のようなシンプルな構成でスタートしました。
- VPSを借りてブラウザ(Chrome)をインストール
- 対象 URL を開いた状態で24時間稼働させる
そもそも初めてVPSを触りますし、この分野の開発は知らないことばかりでshellを初めて書いたりとなんとか実装しました。しかし以下の問題にぶち当たりました。
発生した問題
デプロイ後(mainにマージされた後)VPSが正常に動かない
おそらくブラウザのキャッシュの影響で変更があったコードに24時間稼働し続けているVPSが対応できておらずクライアントさんから正常に動作しないというバグの報告がたびたび上がるようになりました。
当初は、
- デプロイ後、毎回VPSにSSH ログイン
- ブラウザやプロセスを手動で再起動
という力技でしばらく(約半年…)乗り切っていましたが、
- サービス規模の拡大
- デプロイ頻度の増加
- ヒューマンエラーのリスク
などを考えると、さすがに自動化したい、という話になりました。
そこでコスト面も含めて検討した結果、以下のようなアーキテクチャに落ち着きました。
アーキテクチャ
- VPS 上に「ブラウザ + 軽量 Web サーバー(Express)」を用意
- 軽量サーバーに「再起動用エンドポイント」を実装
- Firebase Functions から VPS の再起動エンドポイントを叩けるようにする
- Vercel のデプロイ完了 Webhook から Firebase Functions を呼び出す
という構成になりました。ざっくりした流れは以下です。
なぜ VPS に軽量サーバーを立てたのか
VPS に「ただのブラウザ」だけ置いていると、
外部から「再起動してね」と伝える手段が SSH くらいしかありません。
しかし、
- sshでのやり方が分からないためWebhook → Functions → VPS のような HTTP ベースの連携にしたい
- ログやエラーをクラウド側(Functions)でまとめて見たい
といった理由から、VPS 側に小さな HTTP サーバー(Express)を置き、「HTTP リクエストを受け取ったらブラウザを再起動する」だけの役割を持たせ、属人化しないように心がけました。
なぜ直接 VPS を Webhook 先にしないのか
Vercel の Webhook の宛先を、直接 VPS にしてしまう案も検討しましたが、最終的に Firebase Functions を挟む構成にしています。その理由は次のとおりです。
- Functions 側で
- 認証・シークレットの管理
- IP 制限やレート制限
- ログの集約
- 将来の仕様変更を吸収できる
- VPS へのリクエストが失敗したときに、Functions でリトライや通知処理を挟める
- デプロイ関連の処理を「クラウド側に閉じ込めて」おけるため、VPS を単純な実行環境として保てる
結果として、
Vercel → Functions → VPS
という 3 段構成にはなりますが、運用やトラブルシュートの視点で見ると、個人的にはかなりいい設計ではないのかと思っております。
まとめ
現在も、この仕組みでビンゴゲームのモニター用画面は安定稼働しています。
- デプロイ後にブラウザが古いまま…という不具合は解消
- 手動で VPS を再起動する運用からも卒業
- ログや失敗時の原因調査も、Functions 側で追いやすくなった
デプロイ関連のバグって、実際に運用してみるまで気づかないことも多く、当時は正直かなり焦りました。ですが、調べてもあまり同じパターンの事例が見つからなかったので、この記事が同じような要件で悩んでいる方の何かの参考になればうれしいです。
何はともあれ、とても楽しい開発でした 🚀