Node.js
WebRTC
CloudRun

Google Cloud Run は WebRTCのシグナリングサーバーに使えるか?


はじめに

この資料は WebRTC Meetup Tokyo #21 のLT発表資料です。

(が、WebRTC成分はゼロです)


自己紹介


  • インフォコム株式会社 がねこまさし


  • @massie_g

  • WebRTC Meetup Tokyo / Begginers Tokyo スタッフ



Cloud Run とは


  • Cloud Run は Google Cloud Platform (GCP)の新しいサービス

  • 自分で作ったコンテナを、Googleが用意したサーバー環境上で動かせる

  • http(s) の口を持ったWebアプリ/Web APIサーバーを手軽に作れる

  • スケーリングも勝手に面倒見てくれる



Cloud Run でできないこと


  • コンテナを使っていても、できないことがある

  • 単体ではステートを持てない

  • データーの永続化はできない

→ 他のサービスを組み合わせて利用

※WebRTC的に気になること


  • シグナリングサーバーに使えるのか? (WebSocketは使えるか?)



Cloud Run を使うには


  • 準備

  • コンテナのビルド

  • コンテナのデプロイ

詳しくは別記事にて ... Google Cloud Run を使うまで



サンプルの準備


  • シンプルな、1対1のビデオチャットのサンプル

  • サーバー側(コンテナ)は、Webサーバーと、WebSocketサーバー機能を持つ


    • Node.js + express + ws



  • 同一ポートで、httpとwebsocketを使用


    • PORT環境変数で指定されたポート番号を使用





サーバーのソースコードの抜粋

GitHubはこちら https://github.com/mganeko/webrtc_1to1

// --- get PORT from env --

let port = process.env.PORT;

// --- prepare server ---
const http = require("http");
const WebSocketServer = require('ws').Server;
const express = require('express');

const app = express();
app.use(express.static('public'));
let webServer = null;
const hostName = 'localhost';

// --- http ---
webServer = http.Server(app).listen(port, function () {
console.log('Web server start. http://' + hostName + ':' + webServer.address().port + '/');
});

// --- websocket signaling ---
const wsServer = new WebSocketServer({ server: webServer });



コンテナのビルド

Dockerfile

# Use the offical node.js image

FROM node:10.15.3-alpine

RUN mkdir /root/work
WORKDIR /root/work/
RUN apk add git
RUN git clone https://github.com/mganeko/webrtc_1to1.git
WORKDIR /root/work/webrtc_1to1
RUN npm install

# Run the web service on container startup.
EXPOSE 8080
CMD [ "node", "server_1to1.js" ]

※本当は node を直接起動するのは良くないらしい

「Docker node PID 1」で検索



ローカルでコンテナを実行


コンテナのビルド

$ docker build -t mganeko/webrtc_1to1 .



コンテナの実行

$ docker run -d -e PORT=1323 -p 8002:1323 --name webrtc mganeko/webrtc_1to1


mganeko/webrtc_1to1 はイメージ名(適宜置き換えてください)

2つのブラウザで http://localhost:8002 に接続 → OK



Cloud Run で実行


CloudBuildでビルド

$ gcloud builds submit --project cloud-run-webrtc1to1 --tag gcr.io/cloud-run-webrtc1to1/webrtc-1to1



CloudRunにデプロイ

$ gcloud beta run deploy --project cloud-run-webrtc1to1 --image gcr.io/cloud-run-webrtc1to1/webrtc-1to1


それぞれの値は適宜置き換えてください。

cloud-run-webrtc1to1 ... プロジェクトID

webrtc-1to1 ... サービス名

gcr.io/cloud-run-webrtc1to1/webrtc-1to1 ... イメージのURL



結果は NG

Chrome DevConsoleのNetworkタブ

cloudrun_ws.png

WebSocketが繋がらない (400 Bad Request)



Cloud Run の制約

Container runtime contract より


  • The container must listen for requests on 0.0.0.0 on the port defined by the PORT environment variable.

  • Your container instances must start an HTTP server within 4 minutes after receiving a request.

どうやらHTTPのみ使えて、WebSocketは使えない



無理やりシグナリングするには


  • HTTPで無理やり → Long Polling (COMET) しかない

自分で Log Polling 実装するにはどうすれば..?

あ、それって Socket.io がフォールバックでサポートしているはず!



Socket.io版サンプル


  • シンプルな、1対1のビデオチャットのサンプル

  • サーバー側(コンテナ)は、Webサーバーと、Socket.ioサーバー機能を持つ


    • Node.js + express + socket.io



  • 同一ポートで、httpとsocket.io(websocketとフォールバック)を使用


    • PORT環境変数で指定されたポート番号を使用





サーバー側ソースコードの抜粋

https://github.com/mganeko/webrtc_1to1_socketio


// --- get PORT from env --
let port = process.env.PORT;

// --- prepare server ---
const http = require("http");
const express = require('express');

const app = express();
app.use(express.static('public'));
let webServer = null;
const hostName = 'localhost';

// --- http ---
webServer = http.Server(app).listen(port, function () {
console.log('Web server start. http://' + hostName + ':' + webServer.address().port + '/');
});

// --- socket.io server ---
const io = require('socket.io')(webServer);
console.log('socket.io server start. port=' + webServer.address().port);



結果


  • websocket接続はエラー

  • xhr poll でシグナリングはできる

時間があったらデモ



厳密には


  • リクエストが増えると、自動的にスケールアウト


    • デフォルト設定では 80



  • 実運用では、同じインスタンスに繋がるとは限らない → シグナリングできない可能性あり


    • 試しに同時リクエスト数を 1 に設定 → シグナリングできない

    • ※どころか、コンソールの動きが一部おかしくなる??





シグナリングには、別の手段が順当

ちなみに Google App Engine FE は IaaSより高い



まとめ


  • Cloud Run 便利そう

  • が、シグナリングザーバーには向いてない

どうもありがとうございました!