Rails × GCPの各サービスの紹介
※「株式会社YOJO Technologies」から「PharmaX株式会社」へ社名変更いたしました。この記事は社名変更前にリリースしたものになります。
はじめに
開発の竹内(@kenta_714)です。
弊社では6/12に漢方・サプリのサブスクリプションサービスであるYOJOのシステム基盤をHerokuからGCPへとリプレースしました。
今回利用したGoogle Cloudの各サービスについて概要と実際の使い方を紹介していきます。
全体構成
構成図はざっと以下の通りです。
大量にサービスがありますので、1つずつざっくりと説明させてください!
Cloud Run
Cloud RunはGoogle のスケーラブルにコンテナを実行できるマネージドコンピューティングプラットフォームです。
公式で挙げられている特徴として以下のものがあります。
YOJOではNext.js, BFF(Apollo Server)、Railsなどのアプリケーションを全てCloud Run上で実行しています。
フロントエンドはユーザーの購入履歴や住所などの管理の「webサーバー」、社内向けのメッセージ管理システムの「adminサーバー」の2つで構成されており、どちらもNext.jsで実装されています。2つのサービスはそれぞれTypeScriptで実装されたBFF(Backend for Frontend)を通して、Railsで実装されたAPIサーバーと通信します。これらの通信は図の中に矢印がないため分かりづらいかもしれません。
また、Railsによくあるバックグラウンド処理についてはサービス特性ごとに3つのCloud Runを稼働させて実現しています。
1つ目: ScheduleJobAPIサーバー
定期ジョブを登録するためのサーバーです。まず Cloud Scheduler から Cloud Pub/Sub にタスクがキューイングします。このキューをPush型 ScheduleJobAPIサーバー にリクエストを投げます。(下図参照)
ワンポイントHackとしては、配信先に指定するエンドポイントのURLをCloud RunのデフォルトURL(an.a.run.appで終わるURL)にすることで、Cloud Run側は「内部トラフィックのみの疎通」に設定することができます。また、ScheduleJobAPIサーバー側のroutes.rbにて環境変数による分岐を作っておくことで、不正なリクエストが発生しないようにしています。
このように工夫すればCloud Runでも比較的安全な環境を構築することが可能です。
2つ目: ScheduleJobWorkerサーバー
ScheduleJobAPIサーバーが登録したジョブを処理するサーバーです。通常のジョブサーバーと分割している理由は、定期ジョブと通常業務のジョブを分けることでサーバーの負荷分散と保守対応時の切り分けができるようするためです。
3つ目: Jobサーバー
Sidekiqを起動してAPIサーバーから登録されたジョブを実行するサーバーです。現状では5台を固定で稼働させています。Cloud Runはリクエスト数に応じてコンテナ数を上限してくれるので、Jobのリクエストが多くなってくると勝手にコンテナが増えてくれます。KubernetesはCPUやメモリの負荷を基準に水平スケールするのですが、デフォルトではリクエスト数による水平スケールは実装されていないと思うため、ジョブ系はCloud Runのほうが適任かもしれません。
4つ目: LINE受信サーバー/ pubsubサーバー
YOJOはLINEを活用したサービスであるため、患者さんからのメッセージはLINEから送られてきます。これらのメッセージをYOJOのシステムで処理するためにLINEの公式APIのWebhookを利用。これがLINE受信サーバーです。
その後LINE受信サーバーはCloud Pub/Subにメッセージを登録します。pubsubサーバーがサブスクライブをし、JSONの内容に応じた処理を実行します。例えば下図のような内容です。
こちらは type: text, text: "xxxxx" となっているとおり、ユーザーからのメッセージを表しています。場合によってはスタンプや画像が送付されるときもあります。
なお、一度 pubsubサーバー を経由させている理由は以下2つです。
次からはCloud Run以外のサービスについてそれぞれ説明していきます。
踏み台サーバー
Cloud Runは外部・内部からのSSH接続ができません。何かしら不具合が起きたときやちょっとした調査をしたいときにこの仕様は結構困ります。
そこでCloud RunやCloud SQLが配置されているVPC内にGCEでVMを起動しています。弊社ではこれを踏み台サーバーと呼んでいます。
実際に利用するときは、VM内で本番と同じイメージを使ったDockerコンテ
ナを起動し、Railsコンソールを叩くことが多いです。
サーバーレスVPCアクセス
Cloud RunやCloud FunctionsなどのサーバーレスのリソースをVPCに接続するために使用しています。
上記アーキテクチャ図ではCloud RunはサーバーレスVPCアクセスを経由してPrivate VPCのCloud SQLやMemorystore for Redisにアクセスしています。
詳細は別記事でまとめる予定です。
Cloud SQL
データベースサーバーです。YOJOではPostgreSQLを使用しています。
セキュリティの観点からPrivate VPCに配置して外部からアクセスできないようにしています。
Memorystore for Redis
SidekiqのJobを管理します。
Memorystore for Redisもセキュリティの観点からPrivate VPCに配置しています。
Cloud Scheduler
バッチタスクの起動を管理しています。
上述したように、Cloud SchedulerとPubSubでHTTPリクエストをshcedule-job-apiサーバーに投げてJobを登録しています。
Cloud Pub/Sub
LINEのメッセージ受信イベントやCloud Schedulerのイベントを処理するために導入しています。
Cloud Firestore
Cloud SQLとは別にLINEからのメッセージをCloud Firestoreに保存。Realtime Database機能を用いることで薬剤師向けの管理画面にリアルタイムにメッセージを反映したいためFirestoreを利用しています。
BigQuery
データ分析用です。
Cloud SQLにBigQuery接続用のリードレプリカを作成して定期的にデータを同期しています。Cloud SQLとBigQueryの接続には Cloud SQL federated queries を利用しています。制約によりパブリックIPを作成していますが、外部からの接続を許可していないので基本的にはプライベートIPと変わりません。
https://cloud.google.com/bigquery/docs/cloud-sql-federated-queries?hl=ja
Cloud Logging / Cloud Monitoring
Cloud RunやBiqQueryなど、サービスに関わるログをすべてCloud Loggingに集約しています。おかげで時間を追うだけでどのサービスから、どこにリクエストが飛んでどうなったか……という基本的なことがよく分かるようになりました。この話は以下の記事でも書いているとおりです。
まとめ
Cloud Runを中心に、様々なサービスをGoogle Cloudに統一したことで、オブザーバービリティやスケーラビリティを確保することが容易にできました。またコスト面でも複数のクラウドサービスを合算したりネットワークの遅延やデータ同期などに気を遣う必要がないためお得感はあります。
開発としても1つのクラウドサービスさえキャッチアップすれば良いので楽です。
自社のシステムに必要な非機能要件を満たせるのであれば、特定のサービスに集中しても問題ないと思いました。
この記事が気に入ったらサポートをしてみませんか?