このチュートリアルでは、永続的な接続により双方向通信を行う 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 の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
始める前に
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Cloud Run, Memorystore for Redis, Serverless VPC Access, Artifact Registry, and Cloud Build APIs.
- 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
(大阪)asia-south1
(ムンバイ、インド)europe-north1
(フィンランド) 低 CO2europe-southwest1
(マドリッド) 低 CO2europe-west1
(ベルギー) 低 CO2europe-west4
(オランダ) 低 CO2europe-west8
(ミラノ)europe-west9
(パリ) 低 CO2me-west1
(テルアビブ)us-central1
(アイオワ) 低 CO2us-east1
(サウスカロライナ)us-east4
(北バージニア)us-east5
(コロンバス)us-south1
(ダラス) 低 CO2us-west1
(オレゴン) 低 CO2
ティア 2 料金を適用
africa-south1
(ヨハネスブルグ)asia-east2
(香港)asia-northeast3
(ソウル、韓国)asia-southeast1
(シンガポール)asia-southeast2
(ジャカルタ)asia-south2
(デリー、インド)australia-southeast1
(シドニー)australia-southeast2
(メルボルン)europe-central2
(ワルシャワ、ポーランド)europe-west10
(ベルリン) 低 CO2europe-west12
(トリノ)europe-west2
(ロンドン、イギリス) 低 CO2europe-west3
(フランクフルト、ドイツ) 低 CO2europe-west6
(チューリッヒ、スイス) 低 CO2me-central1
(ドーハ)me-central2
(ダンマーム)northamerica-northeast1
(モントリオール) 低 CO2northamerica-northeast2
(トロント) 低 CO2southamerica-east1
(サンパウロ、ブラジル) 低 CO2southamerica-west1
(サンティアゴ、チリ) 低 CO2us-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 インスタンスと同じデフォルト ネットワークに、
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 ロールをこれらのサービスに与える必要があることにご注意ください。
クリーンアップ
このチュートリアル用に新規プロジェクトを作成した場合は、そのプロジェクトを削除します。既存のプロジェクトを使用し、このチュートリアルで変更を加えずに残す場合は、チュートリアル用に作成したリソースを削除します。
プロジェクトを削除する
課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。
プロジェクトを削除するには:
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
チュートリアル リソースを削除する
このチュートリアルでデプロイした 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 アクセス診断ツールをご覧ください。