[UPDATE] AWS Elemental MediaLiveでVPC経由での出力ができるようになりました!
はじめに
清水です。本日お届けするアップデート情報はこちら、ブロードキャストグレードのライブ動画処理サービスであるAWS Elemental MediaLiveでVPC経由での出力ができるようになりました。(AWS Elemental MediaLive User GuideのDocument historyを確認すると2021/01/27付で更新がありました。)
AWS Elemental MediaLiveでは2019/03のアップデートでVPC経由での入力に対応していましたが、出力についてはVPCに未対応となっていました。
今回のアップデートにてVPC経由での出力に対応したことにより、例えばAmazon EC2インスタンスにプライベートIPを介して出力するといったことが可能になります。そのほかにも、VPCエンドポイント経由でアクセス元を限定したAmazon S3に出力をしたり、AWS Direct Connectを経由して接続先のオンプレミス環境に出力する、といったことなども想定されているようです。このVPC Outputを利用することで、VPC内にMediaLiveのChannelが使用するENIが作成されます。実際に使用するには、このENIに対し適切なネットワーク環境を設定する必要があります。(例えば、パブリックなのかプライベートなのか、NATゲートウェイやVPCエンドポイントなどが必要か否か、などなど。)User Guideには図解での解説もありますので、利用の際はこちらでまず詳細を確認すると良いかと思います。
本エントリではこのMediaLiveのVPC Output機能を使って、EC2上のプライベートIPにWebDAVとしてHLS出力を行います。確認のため、EC2インスタンにローカルからパブリックIPで接続し、HLS配信を視聴しました。
EC2上にMediaLiveが出力するWebDAVサーバを準備する
まず事前準備として、EC2上でWebDAVサーバを準備します。今回はNginxを使用しました。EC2はAmazon Linux 2のArm版、インスタンスタイプはt4g.largeとし、パブリックサブネットで起動します。NginxでWebDAVを動かすためのngx_http_dav_moduleモジュール、そしてnginx-dav-ext-moduleモジュールを組み込む必要があるため、Nginxをソースコードからビルドします。
Nginxのビルド
まずは事前に、ビルドの際に必要となりそうなモジュールをyumでインストールしておきます。
$ sudo yum install -y gcc pcre-devel zlib-devel openssl openssl-devel libxml2-devel libxslt-devel
作業ディレクトリ(/home/ec2-user/build/nginx)に移動して、Nginxのソースコードとnginx-dav-ext-moduleのコードをダウンロード、展開しておきます。
$ cd /home/ec2-user/build/nginx $ wget https://nginx.org/download/nginx-1.19.6.tar.gz $ tar xvf nginx-1.19.6.tar.gz $ wget https://github.com/arut/nginx-dav-ext-module/archive/master.zip $ unzip master.zip
nginx-dav-ext-moduleについては、master.zipをunzipすることでnginx-dav-ext-module-masterというディレクトリが作成されます(/home/ec2-user/build/nginx/nginx-dav-ext-module-master)。これをconfigureの際に--add-module
で組み込みます。
$ cd /home/ec2-user/build/nginx/nginx-1.19.6 $ ./configure --with-http_dav_module --add-module=/home/ec2-user/build/nginx/nginx-dav-ext-module-master 2>&1 | tee log_configure.log
configureを実行すると最後にsummaryが出力されます。設定ファイルやバイナリファイルへのパスがまとまっているのでこちらは控えておくと良いでしょう。
Configuration summary + using system PCRE library + OpenSSL library is not used + using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx modules path: "/usr/local/nginx/modules" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp"
続いてmake、make installします。
$ make 2>&1 | tee log_make.log $ sudo make install 2>&1 | tee log_make_install.log
Nginxの設定
Nginxのビルドとインストールが完了したら、続いて設定ファイルを編集します。個人的にファイル編集しやすいようにEmacsをyumでインストールしておきます。
$ sudo yum install -y emacs
ルートディレクトリは/var/www/data
とし、事前に作成しておきます。dataディレクトリは検証目的ということでパーミッションを777
にしています。(実際には環境などにあわせて適切に設定が必要となる認識です。)
$ sudo mkdir /var/www $ sudo mkdir /var/www/data $ sudo chmod 777 /var/www/data
設定ファイル(nginx.conf)を編集します。ポート8080でWebDAVを稼働させるほか、同じディレクトリをポート80の通常のHTTPアクセスで参照できるようにしておきます。
$ sudo emacs /usr/local/nginx/conf/nginx.conf
編集前後を比較すると以下のようになります。実際の設定ファイル(nginx.conf)全体は本エントリの末尾に補足として記載しておきます。
$ diff /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.default 44,45c44 < # root html; < root /var/www/data; --- > root html; 80,93d78 < } < < # WebDAV < server { < listen 8080; < client_max_body_size 1g; < location / { < root /var/www/data; < client_body_temp_path /var/www/client_temp; < dav_methods PUT DELETE MKCOL COPY MOVE; < create_full_put_path on; < dav_access group:rw all:r; < dav_ext_methods PROPFIND OPTIONS; < }
設定ファイル編集後、構文チェックをします。
$ sudo /usr/local/nginx/sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
問題ないようですので、Nginxを起動します。
$ sudo /usr/local/nginx/sbin/nginx
Nginxの動作確認
動作確認として、ローカル環境からWebDAV経由での書き込み、HTTP GETでの参照を確認しておきます。事前にEC2にアタッチしているセキュリティーグループで、ローカル環境からの80、8080のポートを許可しておきます。
まずはWebDAV経由での書き込みです。
% curl -v -X PUT http://18.XXX.XXX.XXX:8080/test.txt --data-ascii "Hello, WebDAV" * Trying 18.XXX.XXX.XXX... * TCP_NODELAY set * Connected to 18.XXX.XXX.XXX (18.XXX.XXX.XXX) port 8080 (#0) > PUT /test.txt HTTP/1.1 > Host: 18.XXX.XXX.XXX:8080 > User-Agent: curl/7.64.1 > Accept: */* > Content-Length: 13 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 201 Created < Server: nginx/1.19.6 < Date: Sun, 31 Jan 2021 07:16:03 GMT < Content-Length: 0 < Location: http://18.XXX.XXX.XXX:8080/test.txt < Connection: keep-alive < * Connection #0 to host 18.XXX.XXX.XXX left intact * Closing connection 0
続いて、WebDAVで書き込んだ内容が参照できるかの確認です。こちらは80番ポートへのアクセスになります。
% curl http://18.XXX.XXX.XXX/test.txt Hello, WebDAV%
WebDAVでの書き込み、また80番ポートからの読み込みアクセスも問題なさそうです。続いて、本題のMediaLiveでのVPC Outputの確認に移ります。
AWS Elemental MediaLiveでVPC Outputを試してみる
VPC Outputの出力先となるEC2上のWebDAV環境が準備できました。それでは本題のMediaLiveのVPC Outputリソースを作成していきます。
MediaLive Inputリソースの作成
まずはInputの作成です。Input typeはRTMP (push)とします。Network modeでPublic/VPCの選択がありますが、ここはPublicとします。ここで選択するVPCはVPC Inputの機能で2019/03にアップデートされたものですね。([アップデート] AWS Elemental MediaLiveでVPCからの入力がサポートされていました | Developers.IO)
Input security group、Input destinationsも設定します。Input classは今回は検証目的のためSINGLE_INPUTとしました。最後の[Create]ボタンでInputを作成します。
MediaLive Channelリソースの作成
続いてChannelを作成します。Channel nameを入力してIAMロールを選択、ここでIAMロールのアップデートが促されたら実施しておきます。(EC2に関する権限が増えていました、今回のUPDATEに関連するのかも、と推測しています。)
今回はChannel TemplateでLive event / HLS
を選択しました。Channel classはSINGLE_PIPELINE、Input specificationsはデフォルトのまま、CDI input specificationsもデフォルト状態としておきます。
続いて、本題となるOutput deliveryの選択です。今回のアップデートで新たに追加された設定項目ですね。デフォルト状態では以下のようにPublic
が選択されています。
ここでVPC
を選択します。するとVPC settingsの項目が現れますので、VPCサブネット、セキュリティグループをそれぞれ選択します。サブネットはプライベートサブネットとなっているものを選択しました。またセキュリティグループについては、先ほどWebDAV機能を有効にしたNginxが稼働するEC2にポート8080でのアクセスができるよう設定したものを選択しています。EC2でのセキュリティグループ設定と同様ですが、サブネットの属するVPCに紐づいているセキュリティグループを選択する必要があります。EIPについても設定が可能なようですが、今回は未指定としました。
Inputについては先ほど作成したものをアタッチします。Output groupsの設定にて、HLS group destinationのURLにWebDAVの宛先を入力します。具体的には http://10.82.21.196:8080/hls
としました。プライベートIPアドレスであることと、ポートを8080で指定している点がポイントです。またHLS settingsの項目、CDN Settingsは(デフォルトですが)HLS webdav
となっていることを確認しておきます。
なお、Channel TemplateでLive eventを選択しており、HLS outputsは4つのABRから構成されるのがデフォルトですが、検証目的ですので、1つのOutputのみ残し、ほか3つは削除しました。これで[Create channel]ボタンからChannelを作成します。
なお、本エントリでは検証のためChannel classをSINGLE_PIPELINEとしていますが、STANDARDとした場合は以下のようにサブネットを2つ、異なるAZで選択する必要があります。(Select two subnet in two different Availability Zones)
VPC OutputのENIの確認
Channel作成後にリソースについて確認してみると、Destinationsの項目、Egress endpointsがENIとなっていることが確認できます。
EC2のマネジメントコンソールでNetwork Interfaceの項目についても確認してみましょう。medialiveで検索するとENIが確認できます。プライベートIPとして10.82.31.146
が割り当てられていること、パブリックIPは割り当てられていないことなどがわかりますね。
実際のライブ配信を視聴しての確認
それでは実際に映像を打ち上げ、VPC Output経由のライブ配信を視聴してみます。今回映像打ち上げにはiPhone6s上のZixi ONAIRを使用しました。
MediaLiveのChannelをスタートさせ、ライブエンコーダから映像を打ち上げたら、まずはEC2側で確認してみます。WebDAVのデータ書き込み先となるディレクトリを参照してみましょう。以下のようにm3u8ファイル、tsファイルがそれぞれ書き込まれているのがわかります。
$ ls -l /var/www/data/ 合計 22072 -rw-rw-r-- 1 nobody nobody 200 1月 31 09:51 hls.m3u8 -rw-rw-r-- 1 nobody nobody 352 1月 31 09:52 hls_720p30.m3u8 -rw-rw-r-- 1 nobody nobody 2775444 1月 31 09:51 hls_720p30_00001.ts -rw-rw-r-- 1 nobody nobody 2569772 1月 31 09:51 hls_720p30_00002.ts -rw-rw-r-- 1 nobody nobody 2418996 1月 31 09:51 hls_720p30_00003.ts -rw-rw-r-- 1 nobody nobody 2669036 1月 31 09:51 hls_720p30_00004.ts -rw-rw-r-- 1 nobody nobody 2223664 1月 31 09:52 hls_720p30_00005.ts -rw-rw-r-- 1 nobody nobody 2482540 1月 31 09:52 hls_720p30_00006.ts -rw-rw-r-- 1 nobody nobody 2488180 1月 31 09:52 hls_720p30_00007.ts -rw-rw-r-- 1 nobody nobody 2465244 1月 31 09:52 hls_720p30_00008.ts -rw-rw-r-- 1 nobody nobody 2484984 1月 31 09:52 hls_720p30_00009.ts
Nginxのアクセスログも確認してみます。以下のようにMediaLiveのENIのプライベートIPである10.82.31.146
から書き込みがあるのが確認できます。
$ cat /usr/local/nginx/logs/access.log 10.82.31.146 - - [31/Jan/2021:09:51:36 +0000] "PROPFIND / HTTP/1.1" 207 424 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:36 +0000] "PUT /hls_720p30_00001.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:42 +0000] "PUT /hls_720p30_00002.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:48 +0000] "PUT /hls_720p30_00003.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:48 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:49 +0000] "PROPFIND / HTTP/1.1" 207 424 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:49 +0000] "PUT /hls.m3u8 HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:54 +0000] "PUT /hls_720p30_00004.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:51:54 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:00 +0000] "PUT /hls_720p30_00005.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:00 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:06 +0000] "PUT /hls_720p30_00006.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:06 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:12 +0000] "PUT /hls_720p30_00007.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:12 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:18 +0000] "PUT /hls_720p30_00008.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:18 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:24 +0000] "PUT /hls_720p30_00009.ts HTTP/1.1" 201 25 "-" "Elemental 2.18.3.706629" 10.82.31.146 - - [31/Jan/2021:09:52:24 +0000] "PUT /hls_720p30.m3u8 HTTP/1.1" 204 25 "-" "Elemental 2.18.3.706629"
続いて、EC2に対してパブリックIPからのアクセスになりますが、視聴についても確認してみます。macOS上のSafariブラウザに、http://[EC2のパブリックIP]/hls.m3u8
を入力します。
視聴できました!
まとめ
AWS Elemental MediaLiveの新機能、VPC Outputについて、WebDAVが稼働しているEC2にプライベートIPでHLS出力を書き込むことにより動作を確認してみました。MediaLiveではこれまでもInputについてはVPCに対応していましたが、今回OutputもVPC対応したことで、より柔軟なネットワーク構成がとれるようになったかと思います。プライベートIPでEC2やDirect Connect接続先に出力したい、という場合に活躍しそうですね。ただし柔軟になった反面、ネットワーク構成をきちんと把握しておく必要もあります。User GuideにもVPCなどAWSネットワークまわりに精通していること、と前提がありますね。計画的に利用していきたい機能かなと思いました。
補足
nginx.conf
本エントリの動作確認にあたり、実際に使用したNginx設定ファイル(nginx.conf)が下記になります。デフォルト状態の設定(nginx.conf.default)から書き換えた部分をハイライト表示しています。
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { # root html; root /var/www/data; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # WebDAV server { listen 8080; client_max_body_size 1g; location / { root /var/www/data; client_body_temp_path /var/www/client_temp; dav_methods PUT DELETE MKCOL COPY MOVE; create_full_put_path on; dav_access group:rw all:r; dav_ext_methods PROPFIND OPTIONS; } } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }