Docker for Windowsでsambaを使う

# はじめに
通常、Dockerコンテナはサービスだけを担当していて、永続化したいディレクトリはホストマシンからマウントして利用していると思います。

この方法は、MacやLinuxなどの場合はうまくいくのですが、Docker for Windowsでは、うまくいきません。Docker for Windowsでもフォルダをマウントすることは出来るのですが、ファイルシステムが違うため、コンテナ側(Linuxコンテナ)からパーミッションを変更出来ずrootユーザーでしか書き込み出来ないなどの問題があります。

つまり、例えばphpサーバーのコンテナを建てたとしても、phpがrootユーザーで実行されていない限り、phpからマウントしたフォルダに書き込めなくなってしまいます。

そこでDocker for Windowsの場合、`docker create volume`コマンドでボリュームを作成し、ディレクトリの代わりにdocker volumeをマウントして利用することが一般的だと思うのですが、その場合、今度は、Windowsホスト側からvolumeの中身が見たり編集したりすることが出来ません。

そこで、この記事では、docker volumeをsambaでマウントして、Windowsから編集出来るようにする方法を紹介します。

(なお、ここに紹介する方法を使わなくても、ローカルでsambaのポート(139や445など)を使用していない場合は、単純にローカルのポートフォワードでsambaサーバーに接続することが出来るかも知れません。私の環境では、これらのポートをWindows側で使用しているためダメでした。)

# Docker for Windowsのネットワーク構成

図で表すと次のようになります。

![docker-diagram.png](https://qiita-image-store.s3.amazonaws.com/0/105847/d9de520d-64e4-4b0d-2429-2aaf0881f42a.png)

・Windowsホストとコンテナの間には、MobyLinuxVMがあります。
・WindowsホストとMobyLinuxVMはDockerNATというネットワークでつながっています。
・MobyLinuxVMと各コンテナはDocker0というネットワークでつながっています。(コンテナをデフォルトで立ち上げた場合）

このままでは、Windowsホストからコンテナ1のSambaに接続出来ないため、routeコマンドでDocker0ネットワークへのルートを設定してあげるというのがこの記事の趣旨です。

# docker volumeの作成

まずは、sambaにマウントするためのvolumeを作成しておきます。

```
> docker volume create samba-public
```

これで、`samba-public`という名前でボリュームが出来ました。

# sambaコンテナの作成

ここでは簡単に、既存のsambaコンテナのイメージである `dperson/samba`を使用して、sambaコンテナを立ち上げます。`dperson/samba`について詳しくは
https://hub.docker.com/r/dperson/samba/~/dockerfile/
を確認してください。

マウント先ディレクトリは`/mnt/public`とし、ログイン不要で誰でも読み書き出来るものとします。共有フォルダ名は`public`です。また、コンテナ名として`samba_server`としました。

```
> docker run --name samba_server -v samba-public:/mnt/public -d dperson/samba -s "public;/mnt/public;yes;no;yes;all;none"
```

これでsambaコンテナが立ち上がりました。このコンテナはdockerのブリッジネットワーク(172.17.x.x)で立ち上がっていると思います。次のコマンドでIPアドレスを確認してみてください。

```
> docker exec -it samba_server ip addr show dev eth0
```

私の環境では、次のような結果になりました。

```
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

つまり、このコンテナのIPアドレス/サブネットは、172.17.0.2/16です。つまり、ネットワークとしては、172.17.0.0/255.255.0.0 となります。

# routeの設定

sambaコンテナのIPアドレス 172.17.0.2は、dockerのブリッジネットワーク(docker0ネットワーク)なので、Windowsホストからは直接接続出来ません。
そこで、ルートを設定してあげます。そのためには、dockerホストであるMobyLinuxVMのIPアドレスが必要になります。

Docker for WindowsのSettingsを押して、ネットワークを確認してみてください。デフォルトでは、`10.0.75.0`となっていると思います。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3130353834372f30323133313239612d323234312d353239372d643131392d3564646666303636303266652e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/105847/45905dba-c30b-2236-f995-15241c55abd7.png)

この場合、WindowsホストのIPアドレスは10.0.75.1、MobyLinuxVMのIPアドレスは、10.0.75.2になります。

注意：
 Hyper-Vマネージャを立ち上げて、MobyLinuxVMの情報を見るとIPアドレス 10.0.75.2であるが分かるかも知れません。が、自分の環境ではHyper-V上でIPアドレスは表示されませんでした。

![スクリーンショット 2018-04-13 8.25.19.png](https://qiita-image-store.s3.amazonaws.com/0/105847/d5ec99b5-5351-4a66-b347-fba5a3d2c5fd.png)

その代わり、MobyLinuxVMのMacアドレス（物理アドレス）は分かるので、Windows上で `arp`コマンドを使うことで

```
> arp -a
インターフェイス： 10.0.75.1 --- 0x20
 インターネット アドレス　物理アドレス　種類
 10.0.75.2    00-15-5d-02-81-1d   動的
 10.1.75.255  ff-ff-ff-ff-ff-ff   静的
  ...
```

10.0.75.*系でそのMacアドレス（物理アドレス）になっているIPアドレスを見つければ、それがMobyLinuxVMであることが分かります。 /注意終わり





次に、routeを設定します。次のコマンドは管理者権限が必要なので、コマンドプロンプトなどのターミナルを管理者権限で起動して行います。

```
> route add 172.17.0.0 mask 255.255.0.0 10.0.75.2
```

このコマンドの意味は、10.0.75.2 (MobyLinuxVM)を経由して、172.17.0.0/255.255.0.0 (Docker0サブネット)に接続するという意味です。

routeを設定すると、Windowsホストからアクセスすることが出来るようになります。
Windowsのネットワークから

```
\\172.17.0.2
```

で接続してみましょう。すると、publicフォルダが確認出来て、読み書き出来るようになっていると思います。

![スクリーンショット 2018-04-11 12.17.48.png](https://qiita-image-store.s3.amazonaws.com/0/105847/573b86d3-4ab9-b53a-3985-6ce5631bda87.png)

# 補足

route addコマンドは、Windowsをリブートすると消えてしまうので、永続化したい場合は、`-p`オプションを使います。

```
> route -p add 172.17.0.0 mask 255.255.0.0 10.0.75.2
```

削除するときは

```
> route delete 172.17.0.0
```

確認するときは

```
> route print
```
です。

# 終わりに

この方法を使えば、docker volumeをsambaマウント出来るので、別のコンテナでhttpdサーバーを建てて同じvolumeをマウントしておけば、Windowsからも読み書きできるし、便利なのではないかと思います。

面倒なときは、一つのコンテナにhttpdもsambaもすべていれて、直接マウント出来るようにするのもいいかもしれません。（私は、コンテナが増えるのがイヤなので、こちらの方が好きです）

httpdサーバーと連携させる場合や、逆にWindows側の共有フォルダをLinux側からsmbマウントして見るなど（この方法だと、コンテナを立ち上げていない状態でも編集が出来るので便利な側面もある）、需要があればまた描きたいと思います。

# 情報募集

MobyLinuxVMのIPアドレスを得るのに、docker for Windowsのsettings画面からネットワーク(DockerNAT)の設定で確認しましたが、もっと簡単に直接MobyLinuxVMのIPを知る方法ってあるのでしょうか？