マッタリ系インフラエンジニアがオンライン会議のために自社でライブ配信環境を作ってみた

やあ。最近ボドゲにハマっている、なかみねです。
コロナで外出できないので暇つぶしに色々と集めてみたらハマっちゃいました。
好きなボドゲは「ガイスター」「スカル」「ウボンゴ」です。
コロナが落ち着いたら会社でボドゲ部作って皆んなで楽しみたいなぁ〜
（このままの勢いでボドゲ紹介といきたいところですがまた今度）


今回の記事はかなり前に自社でライブ配信環境を構築することになったので、備忘録もかねて書いていきたいと思います。

## ◆はじめに
私が勤めている会社では、毎年３月末あたりに全体会議という全拠点対象の大きな会議を行なっています。しかし、このご時世なので一堂に会してというワケにはいかないため、オンラインで開催するっぽい雰囲気が。

「こりゃ今年の委員会メンバーは大変そうだな～、どうするんかな～」と完全に傍観者気分だったところ、突然上司から『**自社で配信環境作ってそれで会議のライブ配信やろうず**』と指名され、気づいたら環境構築担当として委員会にアサインしていました。
この時、開催まで残り１ヶ月半くらい・・・

なぜ自社構築？YouTubeLiveやGoogleMeetじゃアカンの？と思われたかもしれませんが、
もちろん当初は、YouTubeLiveやGoogleMeetあたりの利用を検討していました。
ところが、数百名が一斉に視聴を行なうと会社のインターネット回線を圧迫する可能性があるため、それらサービスは利用できず。

というのも、社内で利用している業務ツールの多くがインターネットを経由したSaaSになっていて、ライブ配信中の時間帯も業務を行なっている人が少なからずいるからです。
誰かの迷惑になるような会議になってしまっては元も子もありません。

なので「**業務に影響が無いように会議のライブ配信を行なう**」が最大の要件となりました。

そうなると手段はひとつ（じゃないかもしれないけど）
「イントラネット内に配信サーバーを構築する」になりますが、リモートワーク中で自宅から視聴する方も複数名いるので、そちらもカバーしなければいけません。

## ◆全体構成図
というワケで、最終的に下記のような構成で配信環境を構築しました。

* 社内から視聴する人はイントラネットが利用できるので、オンプレの配信サーバーにアクセスし視聴いただく。
* 自宅から視聴する人は自宅のインターネットを利用して、AWSにある配信サーバーにアクセスし視聴いただく。
![全体会議2021＠Qiita_全体構成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/bcd363a2-4570-aa2b-5a71-3365881476a5.jpeg)

## ◆環境
今回利用した環境は以下です。
EC2のインスタンスタイプは「m5.xlarge」を選択（オンプレ側のスペックに合わせました）

#### ライブ配信兼WEBサーバー（オンプレ／AWS EC2 共通）
* OS：CentOS 7.9.2009
* CPU：4コア
* メモリ：16GB
* ディスク：50GB（サイズは任意で）
* ミドルウェア：
    * Apache 2.4.6
    * PHP 7.4.16
    * mysqld 8.0.23
    * Wordpres 5.7.2
    * Nginx 1.20.1
    * nginx-rtmp-module
    * git 2.24.4
* 利用ポート：
    * 80（Apache）※配信ページアクセス用
    * 8080（Nginx）※Wordpressプラグインからのストリーミングファイル参照用
    * 1935（RTMP）※OBS配信PCからサーバーへの配信映像アップロード用

#### ライブ配信用ノートPC
* OS：Windows 10 Pro(64bit)
* CPU：Core i7-10870H（8コア）
* メモリ：32GB(16GB×2)
* ディスク：512GB(SSD M.2)
* グラフィックス：NVIDIA GeForce RTX2060
* 配信ソフト：OBS

なお、配信用ノートPCについては「e-TAMAYA」様から３週間ほどレンタルしました。
急な依頼にも関わらず、迅速にご対応頂き大変助かりました！ありがとうございました。

https://www.e-tamaya.co.jp/

## ◆手順
Apache, PHP, mysqld, Wordpress, gitのインストール設定は割愛しますので
適宜インストールを行なってください。Wordpressが動く環境であればOKです。

### １．Nginxの設定
##### Nginxのソースをダウンロードし解凍
```
$ cd /usr/local/src/
$ wget http://nginx.org/download/nginx-1.20.1.tar.gz
$ tar zxvf nginx-1.20.1.tar.gz
$ cd nginx-1.20.1
```

##### RTMPモジュールのgitプロジェクトをclone
```
$ git clone git://github.com/arut/nginx-rtmp-module.git
```

##### NginxをRTMPモジュールと一緒にコンパイルしインストールする
```
$ ./configure --add-module=nginx-rtmp-module/
$ make
$ make install

何かエラーが出たら下記をインストールください
$ yum install openssl-devel pcre-devel gcc make
```

##### 下記にNginxのディレクトリが作成されるので設定ファイルを開く
```
$ ls -l /usr/local/nginx/
$ vi /usr/local/nginx/conf/nginx.conf
```

##### Nginxの設定ファイルに配信設定を追記
```/usr/local/nginx/conf/nginx.conf
http {
～～～～～～途中割愛～～～～～～～
    server {
            # 80番ポートはApache/Wordpressで使用するため8080に変更
            listen 8080;

            location / {
                # キャッシュさせない
                add_header 'Cache-Control' 'no-cache';

                # CORS対策(Apache/Wordpress側から動画ファイルを参照するため)
                add_header 'Access-Control-Allow-Origin' '*' always;
                add_header 'Access-Control-Expose-Headers' 'Content-Length';
                if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
                }
                types {
                    # 動画ファイルの拡張子とMIMEタイプを関連付け(tsは動画のセグメントファイル、m3u8はインデックスファイル)
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
                }
                # ルートディレクトリには動画ファイルの格納先ディレクトリを指定
                root /vol/;
            }
    }
}

rtmp {
    server {
          # RTMPのポート
          listen 1935;
          # ファイルの分割サイズ
          chunk_size 4096;

          application live {
                # ライブ配信機能を有効化
                live on;

                # HLS ストリーミング有効化
                hls on;

                # m3u8とtsファイルの格納ディレクトリを指定（※１．ここが後々のWodpressプラグインで設定する「http://サーバーIP/hls/ストリームキー.m3u8」になる）
                hls_path /vol/hls/;

                # tsファイルの分割間隔（長いと低負荷で遅延大、短いと高負荷で遅延小）※環境合せて適宜調整
                hls_fragment 1s;
                # m3u8ファイルに何秒ぶんのtsファイルを取り込むか
                hls_playlist_length 10;

                # nginxからのストリームをrtmpとして消費しないようにする
                deny play all;

                # ライブ配信が終了したら指定のディレクトリにアーカイブを保存する
                record all;
                record_path /vol/recordings/;
                record_suffix -%Y%m%d%H%M.flv;
                record_unique on;
          }
    }
}
```

##### Nginxの起動スクリプト作成
```
$ cat > /usr/lib/systemd/system/nginx.service << EOF
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

EOF
```

##### Nginxを再起動
```
$ systemctl restart nginx
$ systemctl status nginx
```

### ２．CloudEndureを使ってオンプレサーバーをEC2に移行
自宅から視聴する人用に、AWS環境にも配信サーバーを用意する必要があります。
普通にEC2を起動して同じようにセットアップしてもよかったんですが、興味本位でCloudEndureを使って移行してみました。
詳細は割愛しますが、簡単に説明するとエージェント型の移行ツールです。
移行元にエージェントを入れてCloudEndureコンソールで連携設定を行なうだけで、AWS側に丸っと転送してくれます。
※最近「AWS Application Migration Service (AWS MGN)」という類似のサービスをローンチしたそうです。
![全体会議2021＠Qiita_CloudEndure1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/4831019b-1b3e-1c8b-0e14-7b4a31086bcd.jpeg)
手順は下記の記事がわかりやすかったので参考にさせて頂きました。

https://qiita.com/issie_/items/814e727677148cd0fcd5

### ３．配信用ノートPC側でOBSを設定
OBS起動 ＞ 設定 ＞ 配信　　を選択して「**`オンプレ側配信サーバー`**」に向けての設定を行ないます。
![全体会議2021＠Qiita_OBS1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/eb94f7ab-6200-6368-0271-e89d196458a9.jpeg)

設定 ＞ 出力 ＞ 録画 ＞ 出力モード：詳細　　を選択して「**`AWS側配信サーバー`**」に向けての設定を行ないます。
![全体会議2021＠Qiita_OBS2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/5d25b1ee-f662-5dfa-7455-819233f9fd5e.jpeg)
これでOBS側の設定が完了です。試しになにか配信してみて動作確認を行ないましょう。
「配信開始」ボタンでオンプレ側配信サーバーへ、「録画開始」ボタンでAWS側配信サーバーへそれぞれ出力が行なわれます。
![全体会議2021＠Qiita_OBS5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/9878de89-048f-007a-88f7-a6d2a3a74f14.jpeg)

なお、シーンの設定については配信内容によって様々です。
今回の場合だと配信スタジオに司会者をたてて進行、事前に各部署で作成頂いた動画の前フリを行なうシナリオだったので、司会の映像を設定した「司会パート」と、動画ファイルを設定した「動画パート」でシーンを分けて、配信映像を切り替える方法を取りました。
![全体会議2021＠Qiita_OBS3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/8e8a40af-030d-87e8-bd62-e0c9746ff38c.jpeg)
レイアウトはこんな感じ（配信有識者のW氏が考えてくれました。あざます！！
![全体会議2021＠Qiita_OBS4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/dfc3cd2b-716c-3499-cc3f-ee82d0c45bf9.jpeg)

### ４．Wordpressプラグインの設定と配信ページの作成
各視聴会場からアクセスさせる動画再生ページについては、開催まで時間もなかったので、Wordpressを使うことにしました。「FV Player」プラグインを使って動画を埋め込みます。
※プラグインのインストール手順は割愛

Wordpress管理画面TOP ＞ FV Player ＞ Add New　　を選択してプラグインの設定を行ないます。
![全体会議2021＠Qiita_WP1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/8da614ad-bccb-f5af-90c9-2de26386faeb.jpeg)
`（※１）ストリーミングファイル名の「stream」部分はOBS側で設定したストリームキーと一致するようにしてください`
![全体会議2021＠Qiita_WP2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/66976003-8cba-1d50-4923-698349cd5dd0.jpeg)

Wordpress管理画面TOP ​＞ 投稿　　を選択して配信ページを作成します。
![全体会議2021＠Qiita_WP3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/c02d93a9-f793-8f44-fe00-c51f16a4f006.jpeg)

完成したページがこちら。非常にシンプルな仕上がりです(^q^)
![全体会議2021＠Qiita_WP4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/7b7c5dcf-747e-bee4-c3b9-62a805963773.jpeg)

これで全ての準備が完了し、当日無事にライブ配信での会議を行なうことができました。
いやぁ～、無事に終わってよかったよかった。
![配信スタジオ風景.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813765/0c2ce3a1-d265-bfc7-c39b-615453d0c4ec.jpeg)


やってみて思いましたが、意外と配信環境の構築自体は難しくなかったなと感じました。
ただし、配信リハは数日かけて何度か行なったほうが良いです。特に複数拠点で視聴する場合は、遅延状況や画質の状態が拠点によって様々なので、状況をみながらOBS側のビットレートなどを調整しましょう。

それでは！（ひんっ