Docker + nginxでマルチ配信を構築


仕事でマルチ配信の話が出たため、Dockerを用いて一つのライブ出力から複数のRTMPサーバにデータを転送する中継サーバを構築してみました。その際に色々と調べたため備忘録として本記事にまとめます。

背景

そもそものきっかけは

  1. アプリで配信したライブを自社製のライブPlayer以外にYoutubeやFacebookに対して同時配信したい
  2. 複数配信先はCMSなどで自由に指定できるようにしたい
  3. RTMPの出力はアプリからで一つに制限されているため、RTMPを複数の配信先に中継するサーバが必要
  4. そもそもそれは可能なの??

から始まり、勉強がてらdockerを用いてローカルに中継サーバを構築してみることにしました。

成果物・構成

成果物は以下の通りです。

◆ソースコード

◆構成

stream server にRTMPを渡すために ffmpeg を使用する構成になっています。

Dockerfile

FROM ubuntu:20.04

RUN apt update
RUN apt upgrade -y
RUN apt auto-remove -y

RUN apt install -y language-pack-ja
RUN update-locale LANG=ja_JP.UTF8

RUN apt install -y build-essential libpcre3 libpcre3-dev libssl-dev libz-dev zlib1g-dev unzip git curl wget vim
WORKDIR /usr/local/src/
RUN curl -LO http://nginx.org/download/nginx-1.20.0.tar.gz
RUN curl -LO https://github.com/arut/nginx-rtmp-module/archive/afd350e0d8b7820d7d2cfc3fa748217153265ce6.tar.gz
RUN tar xvzf nginx-1.20.0.tar.gz
RUN tar xvzf afd350e0d8b7820d7d2cfc3fa748217153265ce6.tar.gz
WORKDIR /usr/local/src/nginx-1.20.0
RUN ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-afd350e0d8b7820d7d2cfc3fa748217153265ce6 --with-debug
RUN make
RUN make install
COPY conf/nginx.conf /usr/local/nginx/conf/nginx.conf
COPY conf/nginx_single.conf /usr/local/nginx/conf/nginx_single.conf
WORKDIR /var/local/www/hls
RUN chmod 777 /var/local/www/hls

# ffmpeg install
WORKDIR /usr/local/src/
RUN wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz \
      && tar Jxvf ffmpeg-release-amd64-static.tar.xz \
      && cp ffmpeg-*-amd64-static/ffmpeg /usr/bin/

WORKDIR /var/local/www/hls

マルチ配信の仕組み

RTMPの通信はnginxの nginx-rtmp-module を用いています。Dockerfile のnginxとnginx-rtmp-moduleのインストールしてる箇所は以下の通りです。

RUN apt install -y build-essential libpcre3 libpcre3-dev libssl-dev libz-dev zlib1g-dev unzip git curl wget vim
WORKDIR /usr/local/src/
RUN curl -LO http://nginx.org/download/nginx-1.20.0.tar.gz
RUN curl -LO https://github.com/arut/nginx-rtmp-module/archive/afd350e0d8b7820d7d2cfc3fa748217153265ce6.tar.gz
RUN tar xvzf nginx-1.20.0.tar.gz
RUN tar xvzf afd350e0d8b7820d7d2cfc3fa748217153265ce6.tar.gz
WORKDIR /usr/local/src/nginx-1.20.0
RUN ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-afd350e0d8b7820d7d2cfc3fa748217153265ce6 --with-debug
RUN make
RUN make install

RTMPを受信し、複数のRTMPサーバへ転送するための設定ファイルは以下の通りです。

# ~~~省略~~~~

rtmp {
    server {
        # ~~~省略~~~~

        application live {
            # ~~~省略~~~~

            allow publish all;          # RTMP push 許可
            allow play 127.0.0.1;       # RTMP pull 有効(ffmpegに対して)

            # 変換コマンド
            exec ffmpeg -re -i rtmp://localhost/${app}/${name} -codec:v libx264 -g 3 -f flv rtmp://localhost/stream1/${name};
            exec ffmpeg -re -i rtmp://localhost/${app}/${name} -codec:v libx264 -g 3 -f flv rtmp://localhost/stream2/${name};
        }

        # ~~~省略~~~~
    }
}

http {
    # ~~~省略~~~
}

処理の順番は以下の通りです。

  • allow play 127.0.0.1; で受信したRTMPを再度localhostに転送
  • localhostに転送したものを2プロセスのffmpegを用いてそれぞれのストリームサーバ rtmp://localhost/streamN/${name}; に転送
    • exec ffmpeg -re -i rtmp://localhost/${app}/${name} -codec:v libx264 -g 3 -f flv rtmp://localhost/stream1/${name};
    • exec ffmpeg -re -i rtmp://localhost/${app}/${name} -codec:v libx264 -g 3 -f flv rtmp://localhost/stream2/${name};

感想

勉強目的で作ってみましたが、大部分は nginxffmpeg の機能を用いて実現しているためコーディングはせずに構築することができました。
今回の成果物では配信先は同じコンテナ内のRTMPサーバに対してですが、ffmpeg コマンドを書き換えることでYoutubeやFacebookに対して配信することは可能です。

勉強後に後から知ったのですがAWS Elemental MediaLiveでRTMP出力が可能であることが判明しました。実サービスでマルチ配信を実現する際は負荷などを考慮すると素直にAWSに頼るのが良さそうです。

参考サイト