このチュートリアルでは、永続的な接続により双方向通信を行う WebSocket を使用して、マルチルームのリアルタイム チャット サービスを作成する方法について説明します。WebSocket を使用すると、サーバーに更新をポーリングすることなく、クライアントとサーバーの両方がメッセージを相互に push できます。
セッション アフィニティを使用するように Cloud Run を構成できますが、これはベスト エフォート型アフィニティになります。つまり、新しいリクエストが、別のインスタンスにルーティングされる可能性がまだあるということです。そのため、チャット サービスのユーザー メッセージは、1 つのインスタンスに接続されたクライアント間だけでなく、すべてのインスタンス間で同期する必要があります。
デザインの概要
このサンプル チャット サービスは、Memorystore for Redis インスタンスを使用して、ユーザー メッセージを保存し、すべてのインスタンス間で同期します。Redis は Pub/Sub メカニズムを使用して(Cloud Pub/Sub プロダクトではありません)、任意のインスタンスに接続された登録済みクライアントにデータを push し、HTTP で更新をポーリングしないようにします。
ただし、push 更新があっても、起動されたインスタンスはコンテナに push された新しいメッセージのみを受信します。以前のメッセージを読み込むには、メッセージ履歴を永続ストレージ ソリューションに保存して取得する必要があります。このサンプルでは、Redis の従来のオブジェクト ストアの機能を使用して、メッセージ履歴をキャッシュに保存して取得します。

Redis インスタンスは、アクセス制御されたプライベート IP を使用してインターネットから保護され、Redis インスタンスと同じバーチャル プライベート ネットワークで実行されているサービスに限定されます。したがって、Cloud Run サービスが Redis に接続するには、サーバーレス VPC アクセス コネクタが必要です。サーバーレス VPC アクセスの詳細をご確認ください。
制限事項
このチュートリアルでは、エンドユーザー認証やセッション キャッシュについては説明しません。エンドユーザー認証の詳細については、Cloud Run チュートリアルのエンドユーザー認証をご覧ください。
このチュートリアルでは、チャット メッセージの履歴を制限なく保存し、取得するために、Firestore などのデータベースを実装することはありません。
このサンプル サービスを本番環境で使用できるようにするには、追加の要素が必要です。レプリケーションと自動フェイルオーバーを使用した高可用性を実現するには、スタンダード ティアの Redis インスタンスをおすすめします。
目標
WebSocket を使用する Cloud Run サービスを作成、ビルド、デプロイする。
Memorystore for Redis インスタンスに接続して、インスタンス間で新しいメッセージを公開および登録する。
サーバーレス VPC アクセス コネクタを使用して、Cloud Run サービスを Memorystore に接続する。
費用
このドキュメントでは、課金対象である次の Google Cloud コンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
始める前に
- Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
-
Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。
-
Google Cloud プロジェクトの課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
-
Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。
-
Google Cloud プロジェクトの課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
-
Cloud Run, Memorystore for Redis, Serverless VPC Access, Artifact Registry, and Cloud Build API を有効にします。
- gcloud CLI をインストールして初期化します。
必要なロール
チュートリアルを完了するために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。
-
Artifact Registry 読み取り(
roles/artifactregistry.reader
) - Cloud Build 編集者(
roles/cloudbuild.builds.editor
) -
Cloud Memorystore Redis 管理者(
roles/redis.admin
) - Cloud Run 管理者(
roles/run.admin
) - サービス アカウントの作成(
roles/iam.serviceAccountCreator
) - プロジェクト IAM 管理者(
roles/resourcemanager.projectIamAdmin
) -
サーバーレス VPC アクセス サービス エージェント(
roles/vpcaccess.serviceAgent
) - サービス アカウント管理者(
roles/iam.serviceAccountAdmin
) -
Service Usage ユーザー(
roles/serviceusage.serviceUsageConsumer
)
ロールの付与の詳細については、アクセスの管理をご覧ください。
gcloud
のデフォルトを設定する
Cloud Run サービスを gcloud のデフォルトに構成するには:
デフォルト プロジェクトを設定します。
gcloud config set project PROJECT_ID
PROJECT_ID は、このチュートリアルで作成したプロジェクトの名前に置き換えます。
選択したリージョン向けに gcloud を構成します。
gcloud config set run/region REGION
REGION は、任意のサポートされている Cloud Run のリージョンに置き換えます。
Cloud Run のロケーション
Cloud Run はリージョナルです。つまり、Cloud Run サービスを実行するインフラストラクチャは特定のリージョンに配置され、そのリージョン内のすべてのゾーンで冗長的に利用できるように Google によって管理されます。
レイテンシ、可用性、耐久性の要件を満たしていることが、Cloud Run サービスを実行するリージョンを選択する際の主な判断材料になります。一般的には、ユーザーに最も近いリージョンを選択できますが、Cloud Run サービスで使用されている他の Google Cloud サービスのロケーションも考慮する必要があります。使用する Google Cloud サービスが複数のロケーションにまたがっていると、サービスの料金だけでなくレイテンシにも影響します。
Cloud Run は、次のリージョンで利用できます。
ティア 1 料金を適用
asia-east1
(台湾)asia-northeast1
(東京)asia-northeast2
(大阪)europe-north1
(フィンランド)低 CO2
europe-southwest1
(マドリッド)低 CO2
europe-west1
(ベルギー)低 CO2
europe-west4
(オランダ)europe-west8
(ミラノ)europe-west9
(パリ)低 CO2
me-west1
(テルアビブ)us-central1
(アイオワ)低 CO2
us-east1
(サウスカロライナ)us-east4
(北バージニア)us-east5
(コロンバス)us-south1
(ダラス)us-west1
(オレゴン)低 CO2
ティア 2 料金を適用
asia-east2
(香港)asia-northeast3
(ソウル、韓国)asia-southeast1
(シンガポール)asia-southeast2
(ジャカルタ)asia-south1
(ムンバイ、インド)asia-south2
(デリー、インド)australia-southeast1
(シドニー)australia-southeast2
(メルボルン)europe-central2
(ワルシャワ、ポーランド)europe-west12
(トリノ)europe-west2
(ロンドン、イギリス)europe-west3
(フランクフルト、ドイツ)europe-west6
(スイス、チューリッヒ)低 CO2
me-central1
(ドーハ)northamerica-northeast1
(モントリオール)低 CO2
northamerica-northeast2
(トロント)低 CO2
southamerica-east1
(サンパウロ、ブラジル)低 CO2
southamerica-west1
(サンティアゴ、チリ)us-west2
(ロサンゼルス)us-west3
(ソルトレイクシティ)us-west4
(ラスベガス)
Cloud Run サービスをすでに作成している場合は、Google Cloud コンソールの Cloud Run ダッシュボードにリージョンが表示されます。
サンプルコードを取得する
使用するコードサンプルを取得するには:
ローカルマシンにサンプル リポジトリのクローンを作成します。
Node.js
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。
Cloud Run のサンプルコードが含まれているディレクトリに移動します。
Node.js
cd nodejs-docs-samples/run/websockets/
コードについて
Socket.io は、ブラウザとサーバー間でのリアルタイム双方向通信を可能にするライブラリです。Socket.io は WebSocket の実装ではありませんが、複数の通信プロトコルに対応するシンプルな API を提供する機能を、信頼性の向上、自動再接続、すべてのクライアントまたは一部のクライアントへのブロードキャストなどの追加機能とラップします。
クライアントサイドの統合
クライアントは、接続ごとに新しい Socket インスタンスをインスタンス化します。このサンプルはサーバーサイドでレンダリングされるため、サーバー URL を定義する必要はありません。ソケット インスタンスはイベントを出力しリッスンできます。
サーバーサイドの統合
サーバーサイドで、Socket.io サーバーが初期化され、HTTP サーバーに接続されます。クライアントサイドと同様に、Socket.io サーバーがクライアントと接続すると、接続ごとにソケット インスタンスが作成され、メッセージの出力やリッスンに使用されます。Socket.io では、「チャットルーム」用の簡易インターフェース、または任意のチャンネルも用意されていて、ソケットが自由に参加または離脱できます。
Socket.io には、ソケットを提供しているサーバーに関係なく、すべてのクライアントにイベントをブロードキャストする Redis アダプタも用意されています。Socket.io では、Redis の Pub/Sub メカニズムを使用するだけで、データは保存しません。
Socket.io の Redis アダプタは、チャットルームのメッセージ履歴の保存に使用された Redis クライアントを再利用できます。各コンテナは Redis インスタンスへの接続を作成します。Cloud Run は多数のインスタンスを作成できます。これは、Redis がサポートする 65,000 接続をかなり下回っています。この量のトラフィックをサポートする必要がある場合は、サーバーレス VPC アクセス コネクタのスループットも評価する必要があります。
再接続
Cloud Run のタイムアウトは最大 60 分です。そのため、タイムアウトが発生する可能性に備えて、再接続ロジックを追加する必要があります。場合によっては、Socket.io が切断または接続エラーイベントの後に自動的に再接続を試みます。クライアントが同じインスタンスに再接続する保証はありません。
すべてのリクエストが閉じるかタイムアウトするまで、アクティブな接続がある間はインスタンスが保持されます。Cloud Run のセッション アフィニティを使用している場合でも、新しいリクエストはアクティブなコンテナにロードバランスされるため、コンテナはスケールインできます。トラフィックの急増後に多数のコンテナが保持されることが懸念される場合は、未使用のソケットが頻繁にクリーンアップされるように最大タイムアウト値を下げることができます。
サービスの配布
Memorystore for Redis インスタンスを作成します。
gcloud redis instances create INSTANCE_ID --size=1 --region=REGION
INSTANCE_ID はインスタンスの名前(例:
my-redis-instance
)に置き換え、REGION_ID はすべてのリソースとサービスのリージョン(例:us-central1
)に置き換えます。インスタンスに、デフォルトのサービス ネットワーク範囲から IP 範囲が自動的に割り振られます。このチュートリアルでは、Redis インスタンスのメッセージのローカル キャッシュに 1 GB のメモリを使用します。詳細については、ユースケース用の Memorystore インスタンスの初期サイズの決定をご覧ください。
サーバーレス VPC アクセス コネクタを設定します。
Redis インスタンスに接続するには、Cloud Run サービスが Redis インスタンスの承認済み VPC ネットワークにアクセスする必要があります。
VPC コネクタごとに、コネクタ インスタンスを配置する独自の
/28
サブネットが必要です。この IP 範囲は、VPC ネットワーク内の既存の IP アドレス予約と重複してはいけません。たとえば、10.8.0.0
(/28
)はほとんどの新規プロジェクトで機能しますが、10.9.0.0
(/28
)など、別の未使用のカスタム IP 範囲を指定することもできます。現在予約されている IP 範囲は、Google Cloud コンソールで確認できます。gcloud compute networks vpc-access connectors create CONNECTOR_NAME \ --region REGION \ --range "10.8.0.0/28"
CONNECTOR_NAME は、アプリケーションの名前に置き換えます。
このコマンドは、Redis インスタンスと同じデフォルト VPC ネットワークに、
e2-micro
マシンサイズのコネクタを作成します。コネクタのマシンサイズを大きくすると、コネクタのスループットを向上させることができますが、コストも増加します。また、コネクタは Redis インスタンスと同じリージョンに配置する必要があります。サーバーレス VPC アクセスの構成の詳細をご確認ください。Redis インスタンスの承認済みネットワークの IP アドレスを使用して、環境変数を定義します。
export REDISHOST=$(gcloud redis instances describe INSTANCE_ID --region REGION --format "value(host)")
サービス ID として機能するサービス アカウントを作成します。このアカウントには、デフォルトでは、プロジェクト メンバーシップ以外の権限は付与されません。
gcloud iam service-accounts create chat-identity gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:chat-identity@PROJECT_ID.iam.gserviceaccount.com \ --role=roles/serviceusage.serviceUsageConsumer
コンテナ イメージをビルドして Cloud Run にデプロイします。
gcloud run deploy chat-app --source . \ --vpc-connector CONNECTOR_NAME \ --allow-unauthenticated \ --timeout 3600 \ --service-account chat-identity \ --update-env-vars REDISHOST=$REDISHOST
プロンプトが表示されたら、
y
と入力して必要な API をインストールするように応答します。これが必要なのはプロジェクトに対して 1 回だけです。設定ページに記載されているように、デフォルト値を設定しない場合は、別のプロンプトにプラットフォームとリージョンを指定して応答します。ソースコードからのデプロイで詳細をご確認ください。
試してみる
完成したサービスを試すには:
ブラウザで、前述のデプロイの手順により提供された URL に移動します。
自分の名前とチャットルームを追加してログインします。
チャットルームにメッセージを送信します。
これらのサービスを開発し続けることにした場合、Google Cloud の他のサービスへの Identity and Access Management(IAM)アクセスが制限されます。他の多くのサービスにアクセスするには、追加の IAM ロールをこれらのサービスに与える必要があることにご注意ください。
費用の説明
5 GB の Redis インスタンスとサーバーレス VPC アクセス コネクタを備えたアイオワ(us-central1)にホストされているチャット サービスの費用内訳の例。
プロダクト | 月額 |
---|---|
Redis | 費用 = プロビジョニングされた容量(5 GB)× リージョン階層の料金(us-central1) スタンダード ティア: 5 GB × $0.054 GB/時間 × 730 時間/月 = $197 ベーシック ティア: 5 GB × $0.027 GB/時間 × 730 時間/月 = $99 |
サーバーレス VPC アクセス | 費用 = マシンサイズの料金 × インスタンス数(最小インスタンス数はデフォルトで 2) f1-micro: $3.88 × 2 インスタンス = $7.76 e2- micro: $6.11 × 2 インスタンス = $12.22 e2-standard-4: $97.83 × 2 インスタンス = $195.66 |
Cloud Run | 費用 = Cloud Run サービス リソース利用時間 × 料金 × インスタンス数 メモリ: 0.5 GiB × $0.00000250 / GiB-s × 60 秒/分 × 60 分/時間 × 8 時間 × 30.5 日 × 4 インスタンス = $4.39† CPU: 1 vCPU × $0.00002400 / vCPU-s × 60 秒/分 × 60 分/時間 × 8 時間 × 30.5 日 × 4 インスタンス = $84.33† リクエスト: $0.40 / 100 万 ~= $0 ネットワーキング: $0.085/GB/月 ~= $0 |
合計 | $197 + $12.22 + $89 ~= $298/月 |
† シナリオの詳細については、以下の説明をご覧ください。
このチュートリアルでは、スタンドアロンのベーシック ティアの Redis インスタンスを使用します。サービス階層をスタンダードにアップグレードすると、高可用性を実現するためにクロスゾーン レプリケーションと自動フェイルオーバーが自動的に有効になります。リージョンと容量も Redis の料金に影響します。たとえば、アイオワ(us-central1)のスタンダード ティア 5 GB インスタンスは 1 時間あたり $0.054/GB です。時間あたりの費用は 5 × $0.054 なので、1 時間につき約 $0.27、つまり月額 $197 ということになります。Memorystore インスタンスの初期サイズを決定して、Redis の料金の詳細を確認してください。
サーバーレス VPC アクセス コネクタは、インスタンスのサイズと数、下り(外向き)ネットワークによって課金されます。サイズと数を大きくすると、スループットが向上し、メッセージのレイテンシが短縮されます。マシンには、f1-micro、e2-micro、e2-standard-4 の 3 つのサイズがあります。インスタンスの最小数は 2 であるため、最小コストはマシンサイズの 2 倍になります。
Cloud Run の料金は、メモリ、CPU、リクエスト数、ネットワーキングなどのリソースの使用量に応じて課金され、100 ミリ秒単位で切り上げて計算されます。このチュートリアルでは、Cloud Run のデフォルトの設定である 512 MiB と 1 vCPU を使用します。各費用は、それぞれ 0.5 GiB × $0.00000250 / GiB 秒、1 vCPU × $0.00002400 / vCPU 秒、またはインスタンスあたり合計 $0.091/時間です。制限事項や推奨事項は言語によって異なりますが、同時実行は合計費用に大きく影響します。同時実行数を増やすと、必要なインスタンスの数が減ることがあります。最大 1,000 個のインスタンス(同時リクエスト 250 個)で、最大 25 万個のクライアントに対応できます。たとえば、250 の同時実行で 1,000 人の従業員に対応するサービスの場合、少なくとも 4 つのインスタンスが必要になります。1 日 8 時間で 1 か月にわたり 4 つのインスタンスを使用する場合、$0.091 × 4 インスタンス × 8 時間 × 30.5 日 = $89 になります。リクエスト数とネットワーキングは追加コストが発生しますが、おそらく最小限になります。
このアイオワ(us-central1)でホストされているチャット サービスの場合、5 GB の標準 Redis インスタンスのコストが $197、デフォルトのサーバーレス VPC アクセス コネクタのコストが $12.22、Cloud Run サービスの見積もりコストが $89、月額合計が $298 となりました。Google Cloud 料金計算ツールで概算費用を確認します。
クリーンアップ
このチュートリアル用に新規プロジェクトを作成した場合は、そのプロジェクトを削除します。既存のプロジェクトを使用し、このチュートリアルで変更を加えずに残す場合は、チュートリアル用に作成したリソースを削除します。
プロジェクトを削除する
課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。
プロジェクトを削除するには:
- Google Cloud コンソールで、[リソースの管理] ページに移動します。
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。
チュートリアル リソースを削除する
このチュートリアルでデプロイした Cloud Run サービスを削除します。
gcloud run services delete SERVICE-NAME
SERVICE-NAME は、選択したサービス名です。
Cloud Run サービスは Google Cloud コンソールから削除することもできます。
チュートリアルの設定時に追加した gcloud のデフォルト リージョン構成を削除します。
gcloud config unset run/region
プロジェクト構成を削除します。
gcloud config unset project
このチュートリアルで作成した他の Google Cloud リソースを削除します。
- Artifact Registry から
gcr.io/PROJECT_ID/chat-app
という名前のサービス コンテナ イメージを削除します。 - サービス アカウント
chat-identity@PROJECT_ID.iam.gserviceaccount.com
を削除します。 - Memorystore for Redis インスタンスを削除します。
- サーバーレス VPC アクセス コネクタを削除します。
- Artifact Registry から
次のステップ
Socket.io の仕組みで、詳細および高度な使い方を確認する。
サーバーレス VPC アクセスの構成の詳細を確認する。
Memorystore と Cloud Run での WebSocket の使用のベスト プラクティスを確認する。
サーバーレス VPC アクセス診断ツールで、サーバーレス ネットワーキングの問題のトラブルシューティングの方法を確認する。