虚無ありき

うるせーーーしらねーーー

docker run `-v` Option の挙動

tl;dr

  • -v Option をよく使うが、Permission の挙動に癖がある
  • 色々実験してみる

Environment

  • Ubuntu: 16.04
  • Docker: 18.09.1
  • docker-compose: 1.23.1
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.5 LTS
Release:    16.04
Codename:   xenial
$ docker --version
Docker version 18.09.1, build 4c52b90
$ which docker
/usr/bin/docker
$ docker-compose -v
docker-compose version 1.23.1, build b02f1306

やってみる

File が存在しない場合

$ ls -l
$ docker run -it --rm \
    -v test_file.txt:$PWD/test_file.txt \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 06:49 test_file.txt
# exit

$ ls -l

コンテナ内では Dir が mount されており、Permission は Root User。

Host に戻ると、存在しない。

Docker volume を確認すると named volume が生成されている。

$ docker volume ls
DRIVER              VOLUME NAME
local               test_file.txt

絶対パスで実行してみると、

$ ls -l
$ docker run -it --rm \
    -v $PWD/test_file.txt:$PWD/test_file.txt \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 07:19 test_file.txt
# exit

$ ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 16:19 test_file.txt

Dir が生成されて mount される。Permission は Root User。Host 側にも生成されている。

ココらへんの挙動の理由としては、GitHub - moby/issue - 4830 にまとめられてある。

There are 2 types of volumes in Docker: "bind mount" and "managed".

Bind mount volume syntax:

-v <host_abs_path>:<abs_path_mount_point> = bind mount volume. You provide absolute path of location on host system and where it should be mounted in the container. Use it when you want to share something from the host system into the container; downside is it creates a dependency of the container on the host it runs on.

Managed volume syntax:

-v <abs_path_mount_point> = unnamed managed volume. Docker will create a volume on the host system at a location owned by the docker daemon and mount it in the container at abs_path_mount_point. To find out where docker created the volume on host: docker inspect -f "{{.Mounts}}" ContainerName.

-v <name>:<abs_path_mount_point> = named managed volume. Same as previous, only instead of volume being assigned a hash, you can provide it with a meaningful name.

named managed volume の syntax とぶつかるため、host_abs_path しか想定していないらしい。

This is because of named volumes... the syntax has just gotten to overloaded and on top of that auto-creation of volumes makes it impossible to know user intent. docker service create already has a new syntax (--mount) that's a lot more precise and can catch these kinds of things early. We'll be bringing that to docker run soon.

今後、mount のために --mount という新しい syntax を追加する予定だとのこと。

File が存在する場合

$ touch test_file.txt
$ ls -l
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Jul 21 15:55 test_file.txt
$ docker run -it --rm \
    -v test_file.txt:$PWD/test_file.txt \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 07:27 test_file.txt
# exit

$ ls -l
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Jul 21 16:27 test_file.txt
$ docker volume ls
DRIVER              VOLUME NAME
local               test_file.txt

named volume が生成されて、コンテナ側に mount されている。

Host に戻ると、File がそのまま残っている。


絶対パスで実行してみると、

$ touch test_file.txt
$ ls -l
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Jul 21 15:55 test_file.txt
$ docker run -it --rm \
    -v $PWD/test_file.txt:$PWD/test_file.txt \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 0
-rw-rw-r-- 1 1000 1000 0 Jul 21 06:58 test_file.txt
# exit

$ ls -l
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Jul 21 06:58 test_file.txt

一般ユーザの Permission のまま mount されている。

Dir が存在しない場合

$ ls -l
$ docker run -it --rm \
    -v test_dir:$PWD/test_dir \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 07:31 test_dir
# exit

$ ls -l
total 0
$ docker volume ls
DRIVER              VOLUME NAME
local               test_dir

named volume が生成されて、コンテナ側に mount されている。

Host に戻ると、何も存在しない。


絶対パスで実行してみると、

$ ls -l
$ docker run -it --rm \
    -v $PWD/test_dir:$PWD/test_dir \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 07:33 test_dir
# exit

$ ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 16:33 test_dir

Dir が生成されて mount される。Permission は Root User。Host 側にも生成されている。

Dir が存在する場合

$ mkdir test_dir
$ ls -l
total 4
drwxrwxr-x 2 ubuntu ubuntu 4096 Jul 21 16:37 test_dir
$ docker run -it --rm \
    -v test_dir:$PWD/test_dir \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 21 07:37 test_dir
# touch test_dir/test_file
# exit

$ ls -l
total 4
drwxrwxr-x 2 ubuntu ubuntu 4096 Jul 21 16:37 test_dir
$ ls test_dir
$ docker volume ls
DRIVER              VOLUME NAME
local               test_dir

named volume が生成され mount されている。

Host 側は変更なし、


絶対パスで実行してみると、

$ mkdir test_dir
$ ls -l
total 4
drwxrwxr-x 2 ubuntu ubuntu 4096 Jul 21 16:37 test_dir
$ docker run -it --rm \
    -v $PWD/test_dir:$PWD/test_dir \
    --workdir=$PWD \
    ubuntu:18.04 bash

# ls -l
drwxrwxr-x 2 1000 1000 4096 Jul 21 07:39 test_dir
# touch test_dir/test_file
# exit

$ ls -l
total 4
drwxrwxr-x 2 ubuntu ubuntu 4096 Jul 21 16:40 test_dir
$ ls -l test_dir/
total 0
-rw-r--r-- 1 root root 0 Jul 21 16:40 test_file
$ docker volume ls
DRIVER              VOLUME NAME

Host 側の Dir がそのまま mount されている。

結果

まとめると下記の通り、

Type Exist Path Result
File 存在しない 相対 named volume が生成されて mount される
File 存在しない 絶対 Root Permission の Dir が生成されて mount される
File 存在する 相対 named volume が生成されて mount され、Host 側の File は変更なし
File 存在する 絶対 Host 側の File がそのままの Permission で mount される
Dir 存在しない 相対 named volume が生成されて mount される
Dir 存在しない 絶対 Root Permission の Dir が生成されて mount される
Dir 存在する 相対 named volume が生成されて mount され、Host 側の Dir は変更なし
Dir 存在する 絶対 Host 側の Dir がそのままの Permission で mount される
  • 相対 path で指定すると、named volume が生成されて mount される。Host 側は変更なし
  • File や Dir が存在しない場合は、Root Permission の Dir が生成されて、mount される
  • 絶対 path で指定し、File や Dir が存在する場合は、Host 側の Permission で mount される