Docker for Windows & WSLでファイルシステムのマウント

話題

Docker for Windows & WSLだと、dockerのマウント機能がうまく作用しないとか何とか。

Docker for WindowsをWSLから使う時のVolumeの扱い方 - Qiita

Docker-compose and incorrect absolute paths for volumes · Issue #1854 · Microsoft/WSL · GitHub

準備

今回の検証ではcentosのリポジトリを使用する。

$ docker pull centos
Using default tag: latest
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest

既存のイメージの確認

$ docker images
centos                     latest              1e1148e4cc2c        7 weeks ago         202MB

コンテナ化して/bin/bashを起動。

$ docker run -it centos /bin/bash
[root@5ae1d59d1da2 /]# ls
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

出る。

[root@5ae1d59d1da2 /]# exit
$

本題

コンテナ化する際にボリュームをマウントすることができる。 公式ではマウントの方法として、--mountを使用することが推奨されている。

The biggest difference is that the -v syntax combines all the options together in one field, while the --mount syntax separates them. Here is a comparison of the syntax for each flag. Use bind mounts | Docker Documentation

主な違いとしては、以下のようなものが挙げられる。

  • -mountではマウントの種類によって明示的にtypeを指定しているのに対し、-vでは与える引数の形式によりマウントの仕方を決めている。
  • --mountではマウント先のディレクトリ・ファイルが存在しない場合、エラーを表示するのに対し、-vでは勝手に作ってしまう。

詰まるところ、--mountを使用したほうが想定外の事態は起こりづらい。
ので、これを使用してマウントする。

以降、ホストOSではtest.txtの入った/home/kimoton/testdirからdockerコマンドを実行するものとする。

$ pwd
/home/kimoton/testdir
$ ls
test.txt

また、Windows側のディレクトリとして、
/mnt/c/Users/kimoton/Documents/windows_dirを作成し、その中にwindows_fileというテキストファイルを作成した。

$ ls /mnt/c/Users/kimoton/Documents/windows_dir
windows_file

WSLファイルシステムのマウント

まず、$(pwd)を指定することで、WSL側のファイルシステムをマウントしようとしてみる。

$ docker run \
  --rm \
  -it \
  --name wsl \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  centos
# ls /app/
target

何故か/appの中にtargetディレクトリが生成されるという結果になった。。

このdocker イメージをdocker inspectで見てみると、

        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/kimoton/testdir",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

/home/kimoton/testdir/target/appにマウントされている。
この/home/kimoton/testdir/targetはあくまでWSLから見たファイルパスであり、ホストOSであるWindowsのDockerカーネルからは見えていない。

Windowsファイルシステムのマウント

次に、Windows側のファイルシステムをマウントしてみる。

$ docker run \
    --rm \
    -itd \
    --name win\
    --mount type=bind,source=c:/Users/kimoton/Documents/windows_dir,target=/app \
    centos
# ls /app/
windows_file

/appの中にwindows_fileが配置されており、正常にマウントされていることがわかる。

先ほど同様に、このdocker イメージをdocker inspectで見てみると、

        "Mounts": [
            {
                "Type": "bind",
                "Source": "/host_mnt/c/Users/kimoton/Documents/windows_dir",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

今度は/host_mnt/c/Users/kimoton/Documents/Article/appにマウントされていることがわかる。
/host_mnt/は、WSLでのWindowsファイルシステムのマウント先を意味しているのだろう。

総括

  • WSLでdockerを使用する際は、現状Windowsファイルシステムからしかマウントできない。
  • 指定は、--mount type=bind,source=c:/path/to/source_dir,target=/target_dirのように行う。
  • WSL側でdockerデーモンが動くようになったら、WSLファイルシステムからのマウントも問題なくなると思う(動くらしいけど、docker-compose使えないのは渋いのでもう少し待ちます)。