ゴールデンウィークにOpenShiftでメタバースやってみた(今更)


# はじめに

みなさん、こんちには。
FacebookもMetaとなり、ビジネス書もたくさん発売され、一気に盛り上がり始めたメタバース。
なんとなく時代に取り残されない様にメタバースを技術的に追ってみたいと思いつつ、なかなか案件もないし、自分で一から実装するのもしんどい。そんな感じでもやもやしたコロナ禍のゴールデンウィーク。ネットを漁ってたら、「VRSpace」とかいうソフトウェアを発見しました。(<a href=https://opensource.com/article/22/1/open-source-metaverse>opensource.com</a>というRed Hatスポンサーのサイトから見つけました)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/8e91cc8b-7573-db54-7b64-f0da76646ace.png)

https://www.vrspace.org/

なんか
重そう
凄そう！と思いつつ、GitHubのソースコードを眺め、遊びでOpenShift(Kubernetes)の環境にデプロイしてみました。

https://github.com/jalmasi/vrspace

# VRSpaceって？
VRSpaceは、Spring Bootベースで実装されたオープンソースのマルチプレイヤ型WebVRアプリケーションです。数あるアバターを選んでVR空間にダイブし、アバター間でゲームしたり、プレゼンしたり、コミュニケーションしたり、と色々できます。ビデオチャットや音声チャットには、OpenViduが使われています。基本的には、クライアントサイドレンダリングで実装されているので、スマホとかだと全然動きません。パソコンかつGoogle Chromeで試しましょう。

簡単に構成を書くと、下図の感じで実装されてます。VRサーバがVR空間の管理を行い、ブラウザ側でbabylon.jsが3Dモデルをレンダリングします。アバターの位置とかは、VRサーバがブラウザからWeb Socketで受け取って管理します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/57453063-5ca6-1f18-90ff-38360283a18f.png)

クライアントのWebブラウザ上で何らか変更操作があると、VRサーバが変更を監視して、同じルーム内の他のクライアントへ変更をブロードキャストして変更を反映します。データベースではユーザIDの管理とかやってます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/dc6044ba-7015-9303-9376-ca29ba6895ac.png)


# 構築環境
- OpenShift v4.8以降(4.8以前はテストしてません)
- AWSまたはAzure（GCPはテストしてません）
- <a href=https://docs.gomplate.ca/>gomplate</a>
    - Goベースのテンプレートレンダラーです。マニフェスト内でfor文とか書けます。
- <a href=https://qiita.com/minamijoyo/items/63ae57b99d4a4c5d7987>envsubst</a>
    - 環境変数が埋め込まれたマニフェストをenvsubstに食わせると、環境変数を展開してくれるツールです
    - マニフェスト内に環境変数を埋め込んで管理できます

# 構築の流れ

マニフェストはこちらのGitHubを参照してください。

https://github.com/yd-ono/metaverse-demo

cloneしておきます。
```
$ git clone https://github.com/yd-ono/metaverse-demo
$ cd metaverse-demo
```

# 1. LET's Encryptを使えるようにする

VRSpaceはHTTPSが必須ですので、遊びと言えど、SSL証明書を取得します。Let's Encryptを使います。

```
# namespaceを作成
$ oc new-project letsencrypt

# ACME Controllerをデプロイ
$ oc create -fhttps://raw.githubusercontent.com/tnozicka/openshift-acme/master/deploy/cluster-wide/{clusterrole,serviceaccount,issuer-letsencrypt-live,deployment}.yaml

# SCC設定
$ oc adm policy add-cluster-role-to-user openshift-acme -z openshift-acme
```

これで完了です。ACME Controllerを使うと、Routeの`metadata.annotations`に`kubernetes.io/tls-acme: "true"`を指定すると、自動でLet's EncryptでSSL証明書を取得してくれます。便利です。

# 2. OpenViduのデプロイ
OpenViduはオープンソースのビデオ会議アプリケーションを提供するプロジェクトです。VRSpaceでビデオ会議や音声チャットの機能を有効にするにはOpenViduの構築が必要です。

https://openvidu.io/

OpenViduはKurentoに基づくビデオ会議アプリケーションのフレームワークで、Kurentoの機能を隠蔽して簡素化してくれます。APIサーバみたいなイメージですかね。以下のような構成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/f82895bc-cced-3559-45d3-de11c7f5e2d8.png)

まず、展開に必要な環境変数をセットします。※マニフェストに埋め込まれています。

```
$ export OPENVIDU_USERNAME=<任意のアカウント名>
$ export OPENVIDU_SERVER_SECRET=<任意のパスワード>
```

NAT配下の環境でOpenViduを使うには、TURNサーバが必要です。オープンソースのTURNサーバであるCOTURNを展開します。

```
$ oc new-project openvidu
$ oc create sa openvidu
$ oc adm policy add-scc-to-user anyuid -z openvidu 
$ gomplate -f manifest/openvidu/coturn-service.yaml | envsubst | oc apply -f -
```

COTURNサーバは`type: LoadBalancer`のServiceを使用します。以下の環境変数`TURNIP`が取得できるまで待ちます。

```
#AWSの場合
$ export TURN_DOMAIN=`oc get svc coturn -o jsonpath='{.status.loadBalancer.ingress[*].hostname}'`

#Azureの場合
$ export TURNIP=`oc get svc coturn -o jsonpath='{.status.loadBalancer.ingress[*].ip}'`
```

`TURNIP`をセットできたら、以下の環境変数もセットします。

```
export MAILADDR=<your mail address>
export BASE_DOMAIN=<your base domain>
export STUN_LIST=`echo $TURNIP:3489 | base64`
export TURN_LIST=`echo ${OPENVIDU_USERNAME}:${OPENVIDU_SERVER_SECRET}@$TURNIP:3489 | base64`
```

COTURN、Kurento、OpenViduサーバをdeployします。

```
$ gomplate -f manifest/openvidu/redis-deployment.yaml | envsubst | oc apply -f -
$ gomplate -f manifest/openvidu/coturn-deployment.yaml | envsubst | oc apply -f -
$ gomplate -f manifest/openvidu/kms-deployment.yaml | envsubst | oc apply -f -
$ gomplate -f manifest/openvidu/openvidu-server-deployment.yaml | envsubst | oc apply -f -
```

OpenViduサーバのRouteを作成します。

```
$ gomplate -f manifest/openvidu/openvidu-server-route.yaml | envsubst | oc apply -f -
```

Routeのエンドポイントを確認して、`https://${OPENVIDU_SERVER_URL}` へアクセスし、TURNサーバ経由でビデオ配信ができることを確認してみましょう。OpenViduのエンドポイントURLは下記で確認できます。

```
$ export OPENVIDU_SERVER_URL=`oc get route openvidu-server -o jsonpath='{.status.ingress[*].host}'`
```


# 3. VRSpaceのデプロイ
公式のGitHubをforkした `https://github.com/yd-ono/vrspace` を用いてコンテナイメージを作成します。 オリジナルのソースコードはlocalhostでVRサーバを実行する前提になっており、localhostをOpenShiftのRouteのエンドポイントになるように修正しています。

`https://github.com/yd-ono/vrspace`をforkして、自分のGitHubのリポジトリで作業したい場合は、以下の環境変数をセットしてください。

```
$ export VRSPACE_GIT_URL=<forkしたリポジトリのURL>
```

forkしていない場合は、以下の通り環境変数を設定します。

```
$ export VRSPACE_GIT_URL=https://github.com/yd-ono/vrspace
```

続いて、以下のコマンドで、VRサーバのエンドポイントURLを取得し、環境変数へセットします。

```
$ export VRSPACE_SERVER_URL=vrspace.${BASE_DOMAIN}
```

あとは、コンテナイメージをビルドしてデプロイするだけです。もちろん、ローカルのPCなどでコンテナイメージをビルドして、任意のコンテナレジストリにpushしても良いですが、ここではOpenShiftのS2Iを用いてOpenShift上でビルドし、OpenShiftの内部のコンテナレジストリを用いてコンテナをデプロイしてみます。

ビルドする前に以下の通りService Accountを作っておきましょう。

```
$ oc new-project vrspace
$ oc create sa vrspace
$ oc adm policy add-scc-to-user anyuid -z vrspace
$ oc adm policy add-scc-to-user privileged -z vrspace
※SCCのセキュリティレベルを上げないとちゃんと動かなかった・・・
```

S2IでBuildしてみます。

```
$ gomplate -f manifest/vrspace/Dockerfile | envsubst | oc new-build --dockerfile=- --to=vrspace -
```

最後に、ビルドしたVRSpaceのコンテナイメージを使用してVRサーバをDeployし、Routeを設定します。

```
$ gomplate -f manifest/vrspace/vrspace-deployment.yaml | envsubst | oc apply -f -


$ cat manifest/vrspace/vrspace-route.yaml | envsubst | oc apply -f -
```

`https://${VRSPACE_SERVER_URL}/babylon/avatar-selection.html` へアクセスし、下記の画面が表示されたら完成です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/eec124c2-f564-2278-fde2-10e9492ad859.png)


こんな感じで適当にユーザIDを入力し、アバターを選択して、好きなスペースを選択すると色々遊べます。
![metaverse-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/6f63b93c-47db-d9cf-67b4-0e4793f7c112.gif)


# まとめ
今回は、OpenShiftにVRSpaceというオープンソースのWebVRアプリケーションをデプロイしてみました。COTURNで外部開放が必要なポートが多すぎてどうしようか...と思ったり、TCP/UDPの混合のServiceは作れないので、諦めたり、色々四苦八苦ありましたが、楽しみながらゴールデンウィークを過ごせたかなと思います。
VRSpaceもOpenViduもKubernetesへ展開する前提の実装になっていないので、あえてKubernetesへ展開する必要があったのか？！と言われると、それは微妙なので聞かないでください。
VRSpace自体は結構シンプルな実装になってて、WebVR初心者としてはそれなりに勉強になりました。皆さんも興味と時間があればぜひお試しあれ。