Docker上 で MiniDLNA を動かす

# MiniDLNA とは
MiniDLNAはその名の通り[DLNA/UPnP](http://kotonohanoana.com/archives/2292)サーバで、LAN内のクライアントに動画や音声をストリーミングするものです。CIFSやNFSなどのファイル共有でも 動画や音声の再生はできるわけですが、再生のし始めやスキップするときには DLNAのほうが軽い気がします。
MiniDLNAは、先達のDLNAサーバである mediatombよりも設定がシンプルで軽快な動作がウリとのこと。現在は[ReadyMedia](http://sourceforge.net/projects/minidlna/)に名前が変わっていますが、Ubuntu 14.04のリポジトリではまだMiniDLNAなので、この記事ではMiniDLNAと呼称します。

# Dockerfile を記述する

Ubuntu 14.04において、MiniDLNAは[Backports](https://help.ubuntu.com/community/UbuntuBackports)にいるので今回はppaを使ってインストールします。

* add-apt-repository を使うため software-properties-common をインストール
* add-apt-repository で ppa:djart/minidlna を追加
* MiniDLNA をインストール
という流れです。

```:Dockerfile
FROM ubuntu:14.04
MAINTAINER flny flny@example.com

RUN apt-get install -y \
      software-properties-common

RUN add-apt-repository ppa:djart/minidlna -y

RUN apt-get update && apt-get install -y \
      minidlna

ADD minidlna.conf /etc/minidlna.conf
ADD start.sh /start.sh

RUN chmod +x /start.sh

EXPOSE 8200
EXPOSE 1900/udp

CMD /start.sh
```

設定ファイル /etc/minidlna.conf を変更する箇所は多くありません。media_dir にサーバで公開するディレクトリを記述するのと、ポート番号(デフォルト8200)を必要に応じて変更する、friendly_nameでクライアントから見たサーバ名を指定する、くらいでしょうか。
なお、ここで指定したポート番号に加えて、1900/udp も開ける必要があります。

```:minidlna.conf
(略)
# If you want to restrict a media_dir to a specific content type, you can
# prepend the directory name with a letter representing the type (A, P or V),
# followed by a comma, as so:
#   * "A" for audio    (eg. media_dir=A,/var/lib/minidlna/music)
#   * "P" for pictures (eg. media_dir=P,/var/lib/minidlna/pictures)
#   * "V" for video    (eg. media_dir=V,/var/lib/minidlna/videos)
media_dir=V,/mnt/pub/lib/movie
(略)
# Port number for HTTP traffic (descriptions, SOAP, media transfer).
# This option is mandatory (or it must be specified on the command-line using
# "-p").
port=8200
(略)
# Name that the DLNA server presents to clients.
# Defaults to "hostname: username".
friendly_name=minidlna
(略)
```

起動は普通にserviceコマンドで行います。

```:start.sh
#!/bin/bash

service minidlna start
/bin/bash
```

# イメージのビルドとコンテナの作成

buildコマンドでイメージをビルドします。

```
$ docker build -t minidlna docker/minidlna/
Sending build context to Docker daemon  7.68 kB
Step 1 : FROM ubuntu:14.04
 ---> e9ae3c220b23
Step 2 : MAINTAINER flny flny@example.com
 ---> Using cache
 ---> 768ca4ac1367
Step 3 : RUN apt-get install -y       software-properties-common
 ---> Running in bdc4a354e1de
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:
  ca-certificates gir1.2-glib-2.0 iso-codes krb5-locales libasn1-8-heimdal
  libcurl3-gnutls libdbus-glib-1-2 libgirepository-1.0-1 libglib2.0-0
  libglib2.0-data libgssapi-krb5-2 libgssapi3-heimdal libhcrypto4-heimdal
  libheimbase1-heimdal libheimntlm0-heimdal libhx509-5-heimdal libidn11
  libk5crypto3 libkeyutils1 libkrb5-26-heimdal libkrb5-3 libkrb5support0
  libldap-2.4-2 libroken18-heimdal librtmp0 libsasl2-2 libsasl2-modules
  libsasl2-modules-db libwind0-heimdal libxml2 openssl python-apt-common
  python3-apt python3-dbus python3-gi python3-pycurl
  python3-software-properties sgml-base shared-mime-info unattended-upgrades
  xml-core xz-utils
(略)
```

ご覧の通り、最初のsoftware-properties-commonのインストールで追加パッケージが死ぬほど入るので、一瞬ppa使わないほうがよかったかなと思いましたが このまま進めます。

```
Step 4 : RUN add-apt-repository ppa:djart/minidlna -y
 ---> Running in ce05b0ca1683
gpg: keyring `/tmp/tmpa_efmo2i/secring.gpg' created
gpg: keyring `/tmp/tmpa_efmo2i/pubring.gpg' created
gpg: requesting key 8E2B7601 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpa_efmo2i/trustdb.gpg: trustdb created
gpg: key 8E2B7601: public key "Launchpad PPA for Thanos Kyritsis" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK
 ---> 1a4f7b3aa575
Removing intermediate container ce05b0ca1683
Step 5 : RUN apt-get update && apt-get install -y       minidlna
 ---> Running in affec8556e53
(略)
The following extra packages will be installed:
  libavcodec54 libavformat54 libavutil52 libexif12 libflac8 libgsm1 libid3tag0
  libjpeg-turbo8 libjpeg8 libmp3lame0 libogg0 libopenjpeg2 libopus0
  liborc-0.4-0 libschroedinger-1.0-0 libspeex1 libtheora0 libva1 libvorbis0a
  libvorbisenc2 libvpx1 libx264-142 libxvidcore4
Suggested packages:
  opus-tools speex
(略)
```
MiniDLNAも中々の追加っぷりですが、数分待てば終わります。

```
Removing intermediate container 1cfe8408f5fb
Step 10 : EXPOSE 1900/udp
 ---> Running in 3aaba6e7e63e
 ---> 2f59d9cc512e
Removing intermediate container 3aaba6e7e63e
Step 11 : CMD /start.sh
 ---> Running in cefe9da14814
 ---> a82bb362f45f
Removing intermediate container cefe9da14814
Successfully built a82bb362f45f
```

次に runコマンドでコンテナを作成します。-p オプションでポートを開け、-v オプションでホストのディレクトリをコンテナと共有しています。
またこのとき、--netオプションでネットワークモードをhostにする必要があります。デフォルトのbridgeのままだと、DLNAクライアントがサーバを認識できません。

```
$ docker run -itd --net=host -p 8200:8200 -p 1900:1900/udp -v /mnt/pub:/mnt/pub --name minidlna minidlna
2c8f8edebabcab7e03be9b5f29f7697c2575aaf5ee77c55a9ffbb40328624e70
```

# 動作を確認する

netstatで サービスが起動しているか確認します。

```
$ netstat -na | grep 1900
udp        0      0 0.0.0.0:1900            0.0.0.0:*
$ netstat -na | grep 8200
tcp        0      0 0.0.0.0:8200            0.0.0.0:*               LISTEN
```

起動しているようです。
ブラウザで http://<サーバのIPアドレス>:8200/ を開き、確認することもできます。
![minidlna.png](https://qiita-image-store.s3.amazonaws.com/0/87156/36c1f492-5cf8-67ff-6fd7-99289df56802.png)
Media library の Video files:78は、minidlna.confで指定した/mnt/pub/lib/movie 以下に78個の動画が見つかり、サーバに認識されたことを意味します。
もし--net=hostを付け忘れてコンテナを作成してしまうと、Connected clientsのHW Address(MACアドレス)が全てFF:FF:FF:FF:FF:FFになるので 異常に気付くことができます。このときはコンテナを一旦削除して 作成し直しましょう。

最後にDLNAクライアントで動画を再生してみます。AndroidアプリGinkgoDlnaを使いました。
GinkgoDlnaを起動し、friendly_nameで指定したDLNAサーバ名が表示されれば成功です。
![Screenshot_2016-01-16-19-24-16.png](https://qiita-image-store.s3.amazonaws.com/0/87156/13fefa05-c378-056f-3678-b2fb1f28137f.png)

もし表示されない場合、DLNA/UPnPのトラフィックがDLNAクライアントに届いていないということになります。

* コンテナのネットワークモードが host でない
* サーバとクライアントが同一ネットワークにない
* サーバとクライアントの間にある機器(ルータとか)がUPnP、1900/udpを通さない設定になっている

あたりが原因でしょうか。

DLNAサーバ名が表示されたら、サーバ名 -> Video -> All Video とタップすれば、MiniDLNAが認識している動画の一覧が表示されます。さらに動画をタップすると、再生が始まります。
![Screenshot_2016-01-16-21-04-11.png](https://qiita-image-store.s3.amazonaws.com/0/87156/305930cc-13f6-4232-cc10-d4947cd3c4d0.png)

なお、DLNAクライアント自身が再生するか、再生用の別のアプリが呼ばれるかはDLNAクライアントの機能によります。(GinkgoDlnaは後者のタイプ)

以上