Genvidを使った配信システムのクラウドデプロイ・サービス開始までの道のり

# Genvid SDKについて
Genvidは、インタラクティブなライブ動画配信を実現するSDKです。
https://www.genvidtech.com/ja/

Genvidはクラウドサーバー上で動かすサーバミドルウェア群と、ブラウザ側で動画と同期した通信処理を行うJavaScriptライブラリで構成されています。
動画再生側で通信ライブラリが動作できる環境さえあれば、配信アプリやプラットフォームは問わず使用できます。
現在は、主にFacebookとTwitch上で使用されています。

最近では、Facebook Gamingで配信されている『PAC-MAN COMMUNITY』のなかで、視聴者をゲームに招待できるゲーム配信者向けの機能「Play with Streamer」で使用されています。
https://www.facebook.com/fbgaminghome/blog/pac-man-community

また、近日『The Walking Dead』のコンテンツも配信予定です。
https://www.genvidtech.com/ja/press-releases/genvid-entertainment%E3%81%A8skybound-entertainment%E3%81%AF%E3%80%81-2022%E5%B9%B4%E3%81%AE%E5%A4%8F%E3%81%ABfacebook-gaming%E3%81%A8facebook-watch%E9%99%90%E5%AE%9A%E3%81%A7%E9%85%8D%E4%BF%A1/

## Genvidを使ったシステムの構築手順
Genvidは、UnityやUnreal Engineなどのゲーム開発環境に対してSDKを組み込んでコンテンツを開発します。
また、動画視聴者向けのボタンなどのUIはHtml+CSS+JavaScriptの任意のライブラリを使って開発します、
まずは、ゲーム（のような）ライブコンテンツを動作させるexeと、動画のストリーミング、ブラウザで表示するwebページの３つを同一PCでエミュレートする「ローカルテスト」を使いながら開発を進めていきます。

ローカルテストについては次のページに詳しく書いてあります。
・ローカルクラスタの開始
https://www.genvidtech.com/doc/ja/SDK-1.36.0/development_guide/game_integration/utilisation.html

その後、実際にクラウドサーバー上でシステムを構築します。
マニュアルでは「配信ガイド」として記載されています。
https://www.genvidtech.com/doc/ja/SDK-1.36.0/broadcasting_guide.html

マニュアルは順を追って説明されていますが、クラウドサーバーを使ったサービス開発を担当していないゲームエンジニアにとっては少々分かりにくいところがあります。
本投稿は、クラウド上での設定までに何をするべきなのかを順を追って紹介します。

## クラウドサービスの用意
Genvidのシステムを動作させるクラウドサービスを契約して用意します。
基本的には筆者はAzureを使っているので本記事はAzureベースになりますが、AWSでも手順はほぼ同一になります。
それぞれのサービスでどのような仮想マシンが必要になるかについては、以下の記事にまとめています。

https://qiita.com/Takaaki_Ichijo/items/7029e39b0644d9ab49ac

以下のコマンドは、Azure PowerShellでの実行となります。

# Bastionサーバーのデプロイ
まずは、Genvidシステム全体の管理を行うBastionサーバーをクラウド上で動かします。
BastionはWindowsサーバーで動作させます。Azureの場合はStandard_B2sです。

```Azure PowerShell
az login
genvid-bastion install --bastionid mybastion --checkmodules --update-global-tfvars --loadconfig
```

## Genvidデプロイイメージファイルの取得
Genvidがホストしているサーバーから、イメージファイルを取得します。
イメージファイルは「SDKgallery」という名前でAzureのストレージに保存されます。イメージの作成には、30 分から 1 時間かかります。

```Azure PowerShell

genvid-azure-image create-images
```

## Dockerビルドマシンでゲームとwebサーバーのイメージを作ってアップロード
Azure上でゲームと通信サーバーを動作させるために、ローカルでビルドしたwebサーバーデータ、ゲームデータをイメージファイル化してＡzureにアップロードします。
Genvid SDKインストールフォルダには bin/にdocker-machineが含まれています。これを使って、dockerビルドマシンをazure上に構築します。

```Azure PowerShell
bin\docker-machine create --driver azure --azure-subscription-id {サブスクリプションID} --azure-location "{使用するリージョン}" {docker-マシン名}
```
イメージには、クラスタの構築にどのようなVMを使用し、どんなオプションを利用するかを記述しています。
このDockerファイルを使ってwebのビルド処理とdockerイメージファイルの作成を行います。

# Genvid Clusterを作成する
Genvid Bastion UI上で、クラスターを新規に作成します。

![Bastion-UI- 2022-07-07 16-36-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/597976f6-bdc0-3aca-14be-14cc382472d2.png)

Genvidのシステムは複数のVMから構成され、1コンテンツ用のひとまとまりを「クラスター」といいます。
以下のコマンドでクラスターの初期設定をします。{CLUSTER_ID}には任意のクラスター名が入ります。

```Azure PowerShell
genvid-azure-image setup {CLUSTER_ID}
genvid-azure-image save {CLUSTER_ID}
```

または、Bastion-UIの左上「＋ADD Config」から新しいコンフィグ設定を追加できます。

![Bastion-UI- 2022-07-07 17-40-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/e84ba3f6-2efe-993f-a038-111e2e3ede4a.png)

Bastion UI上に設定した名前のクラスターが作成されますが、この時点ではまだVM群は空です。
ここに追加設定を含めながら、どんなVMを使うかの設定を行います。

![Bastion-UI- 2022-07-07 17-31-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/d29853f0-ca59-726e-c922-bc154c32e61a.png)

筆者の場合は追加設定として、ゲームを動作させるVMを「"Standard_NV8as_v4"」に指定し直しています。
また、SSL接続に必要なpfxファイル証明書を事前にアップロードし、そのパスを指定しています。

```tfvar.json
{
  "domain_name": "{ドメイン名}",
  "instance_game_type": "Standard_NV8as_v4",
  "location": "{Azureリージョン名}",
  "parent_domain_resource_group": "Domains",
  "resource_group_name": "{cluster id}",
  "shared_gallery_image_version": "1.35.0010",
  "wildcard_ssl_certificate_path": "{pfx証明書のパス}"
}

```

上記ページのDrag configuration files hereからjsonファイルをアップロードすると、設定の差分が反映されます。

このＴerraform設定で以下の設定が自動で行われます（Nomad, Vault, Consulを活用）
・各種サーバーデプロイ。
　ゲームが動作するwindowsサーバー、ビデオエンコードサーバー、Twitchオーバーレイ経由で届く通信のreductionサーバーなど。
・サービスメッシュの構築（各VM間の通信、ルーティング、シークレット管理）
・TwitchオーバーレイがアクセスするURLのdnsレコードの設定

## SDKイメージのアップロード
ローカルのSDKイメージを対象のクラスターにアップロードします。

```Azure PowerShell
$env:GENVID_BASTION_URL="{Bastionのドメイン}"
az login
genvid-sdk -c {CLUSTER_ID} upload-images-sdk
```

## ゲーム動作用のWindowsサーバーにドライバと設定を適用
ゲームを動作させるWindowsマシンには、各種ドライバをインストールする必要があります。
たとえばVirtual Audio Cable、NVIDIAまたはAMDのグラフィクスドライバをインストールします。

## SDKとゲーム、webサーバーのイメージファイルをアップロード
Azure CLI経由で、Genvid SDKイメージをアップロードします。

```CLI
az login
genvid-sdk -c {CLUSTER_ID} upload-images-sdk

genvid-sdk -c {CLUSTER_ID} setup

genvid-sdk -c {CLUSTER_ID} load-config-sdk
```

\imagesに保存したゲームのイメージファイル、webサーバーのイメージファイルをアップロードします。

```CLI
genvid-sdk -c {CLUSTER_ID} upload-images drkk -d .\images

genvid-sdk -c {CLUSTER_ID}  update-images
```

# クラスターに設定をロードする
クラスターのデプロイが終わった段階では、クラウドサーバーのVM一式が用意されたというだけで、この上で実行するゲームや、Twitchオーバーレイと通信を行うwebサーバー、動画エンコードや受信したデータのreduce設定などはまだカラです。
これらの設定を行うファイルをローカルで作成し、Azure Powershell経由でアップロード・適用します。

設定は、大きく分けてVMを作成するためのテンプレートファイルと、クラスターへロードする設定ファイルの2種類があります。

## Nomadジョブを生成するテンプレートファイル
GenvidシステムはNomadを使用しています。Nomadはジョブスケジューラです。「コンテナ」単位で分けられた各種ジョブを実行します。

### ゲーム実行サーバーのテンプレートファイル
ゲーム実行用の設定ファイルは、Genvid SDKインストールフォルダのサンプルに記述例があります。

Unityの例
\samples\cube\unity\templates\cloud\unity.nomad.tmpl 

UE4の例
\samples\cube\ue4\templates\cloud\ue4.nomad.tmpl

たとえばUnityの例では以下のようなファイルです。exe実行ファイル名と、どのような起動オプションをつけるかを指定しています。
ログファイルの保存場所と起動時の解像度などを指定しています。
また、先ほど作成・送信したゲームのイメージファイルのパスと、ログの出力先パスを指定しています。

```Unity.nomad.tmpl
job "unity" {
  datacenters = [
    # {{range $i, $dc := datacenters}}
    "{{$dc}}",
    # {{end}}
  ]

  group "unity" {

    network {
      port "sdkgui" {}
    }

    task "unity" {
      driver = "raw_exec"

      config {
        command = "unity_Cube.exe"
        args = [
          "-force-d3d11",
          "-logFile",
          "${NOMAD_ALLOC_DIR}\\logs\\unity.log",
          "-screen-height",
          "{{- keyOrDefault `genvid/encode/input/height` `720` -}}",
          "-screen-width",
          "{{- keyOrDefault `genvid/encode/input/width` `1280` -}}",
        ]
      }

      constraint {
        attribute = "${node.class}"
        value     = "game"
      }

      artifact {
        source = "{{ key `genvid/images/unity_Cube/url` }}"
      }

      env {
        GLOG_logtostderr     = "1"
        GENVID_LOGGER_PREFIX = "unity"
      }

      service {
        name = "sdkguiservice"
        port = "sdkgui"
      }
    }
  }
}

```

### Webサーバーのテンプレートファイル
Webサーバーのテンプレートサンプルは
\samples\cube\web\templates\cloud　にあります。

こちらも、先ほどアップロードしたイメージファイルのパスと、ログ出力先のパスを指定しています。
重要な設定として、env以下でTwitchサービスへのアクセスキーを指定しています。これは、Twitch ID名など、Twitchが持つ情報をオーバーレイ側で取得するとき、
オーバーレイ自体にキーを保持せずに、このサーバーから供給するものです。

```
job "web" {
  datacenters = [
    "{{$dc}}",
  ]

  group "web" {

    network {
      port "web" {
        static = 30000
      }
    }

    task "web" {

      driver = "docker"

      config {
        image        = "{{key `genvid/images/web/tag`}}"
        load         = "{{key `genvid/images/web/image` | replaceAll `.zip` `.docker`}}"
        force_pull   = "{{ key `genvid/images/web/dirty` | parseBool }}"
        network_mode = "host"

        // {{ if keyOrDefault "genvid/code/logging/fluentd/enabled" "false" | parseBool }}
        logging {
          type = "fluentd"
          config {
            fluentd-address = "${NOMAD_IP_web}:24224"
            tag             = "${NOMAD_TASK_NAME}"
          }
        }
        // {{ end }}
      }

      constraint {
        attribute = "${node.class}"
        value     = "public"
      }

      artifact {
        source = "{{key `genvid/images/web/url`}}"
      }

      env {
        GENVID_LIVESERVICE = "{{key `/genvid/encode/stream/service`}}"
        GENVID_LIVECHANNEL = "{{key `/genvid/encode/stream/channel`}}"

        GENVID_DISCO_SECRET = "{{ .Data.GENVID_DISCO_SECRET }}"
  
        GENVID_STUDIO_SECRET = "{{ .Data.GENVID_STUDIO_SECRET }}"

        GENVID_WEBGATEWAY_SECRET = "{{ .Data.GENVID_WEBGATEWAY_SECRET }}"

        CLIENT_SECRET = "{{ .Data.TWITCH_EXT_CLIENT_SECRET }}"

        ENDPOINT = "{{key `/cloud/endpoint/leaf`}}"
        SSL      = true

        PORT = "${NOMAD_PORT_web}"
      }

      resources {
        memory = 100
      }

      service {
        name = "web"
        tags = ["engage", "web"]
        port = "web"

        check {
          type     = "http"
          path     = "/health"
          interval = "5s"
          timeout  = "2s"
        }
      }
    }
  }
}

```
 
## Genvid設定ファイル
Genvid設定ファイルはhclまたはJSONで記述します。

https://www.genvidtech.com/doc/ja/SDK-1.36.0/reference/genvid_configuration/index.html

SDKに含まれるCubeサンプルを例に必要な設定について解説します。

### events.json
動画視聴を行うブラウザから来るボタン押下などの通シーンデータを、どのようにリダクションするかの設定です。
こちらの記事で詳細に紹介しています。

https://qiita.com/Takaaki_Ichijo/items/0eae7709741774722483

基本的には、Twitchオーバーレイから受信したデータをどのようにリダクションするか、という設定を行うJSON Schemeになります。

### Stream.hcl
動画配信サービスの設定を行います。
Twtichのチャンネル名や配信者キー、配信動画のビットレートなどを設定します。

### Web.hcl
クラスタ管理画面にリンクを作成し、サーバーを動作させるためのnodeのパスなどを設定します。

## Genvid設定ファイルの読み込み
各ファイルの設定は、以下のコマンドで読み込みを行います。

```CLI
genvid-sdk -c {CLUSTER_ID} load-config-sdk
genvid-sdk -c {CLUSTER_ID} load-config {ファイルパス} 
```
ファイル１つ１つをアップロードするのは面倒ですが、SDKに含まれるcubeサンプル
samples\cube\unity\unity.pyには、pythonスクリプトで複数の設定ファイルを一括アップロードできるコマンドがありますので、これを改造して利用すると便利です。

## Cluster UIにアクセスしてシステムを起動

![Cluster-UI- test 2022-07-07 18-09-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/eff7a4fb-779d-6253-c90a-1a627c1bab55.png)

この段階でCluster UIにアクセスすると、ゲームを動作させるapp、サーバーシステムのbins, nats, servicesとwebサーバーがジョブとして登録されている状態になります。
CLIからコマンドで

```
genvid-sdk -c {CLUSTER_ID} start
```
と打つか、Clsuter UIのStart Allボタンをクリックすることでシステムが起動し、Twitchへの配信がスタートします。