Docker で symlink をホストに volume マウントしたら...

# はじめに

意外にも、公式ドキュメント含めどこにも書いてあるのをみつけられなかったので、書いておきます。どこか由緒正しい場所に書いてあるのをご存じの方は、コメントでポインタをいただけましたらありがたいです。

Docker でコンテナ内の symlink をホストに volume マウントしたら、symlink がホスト側のファイルに置き換わるのではなく、symlink 先のファイルが置き換わります。試してみました。

# 準備

テスト用のイメージをビルドします。  

```Dockerfile
$ cat Dockerfile
FROM ubuntu:bionic
RUN \
  mkdir /symlinktest ; \
  echo 'File-A in Container'>/symlinktest/File-A.txt ; \
  ln -s /symlinktest/File-A.txt /symlinktest/Link-A.txt ; \
  mkdir /symlinktest/Dir-B ; \
  echo 'File-B in Container'>/symlinktest/Dir-B/File-B.txt ; \
  ln -s /symlinktest/Dir-B /symlinktest/Link-B

$ docker build -t symlinktest .
```

volume マウントしないで実行してみます。

```console
$ docker run --rm -it symlinktest bash
root@ce96b405c5b4:/# cd /symlinktest
root@ce96b405c5b4:/symlinktest# ls -lR
.:
total 4
drwxr-xr-x 2 root root 24 Jul 15 02:20 Dir-B
-rw-r--r-- 1 root root 20 Jul 15 02:20 File-A.txt
lrwxrwxrwx 1 root root 23 Jul 15 02:20 Link-A.txt -> /symlinktest/File-A.txt
lrwxrwxrwx 1 root root 18 Jul 15 02:20 Link-B -> /symlinktest/Dir-B

./Dir-B:
total 4
-rw-r--r-- 1 root root 20 Jul 15 02:20 File-B.txt
root@24e33c803498:/symlinktest# cat Link-A.txt
File-A in Container
root@24e33c803498:/symlinktest# cat File-A.txt
File-A in Container
root@24e33c803498:/symlinktest# cat Link-B/File-B.txt
File-B in Container
root@24e33c803498:/symlinktest# cat Dir-B/File-B.txt
File-B in Container
```

volume マウント先のファイルをホスト側に作っておきます。

```console
$ echo 'File-A in Host'> ./File-A.txt
$ ln -s ./File-A.txt ./Link-A.txt
$ mkdir Dir-B
$ echo 'File-B in Host'> ./Dir-B/File-B.txt
$ ln -s ./Dir-B ./Link-B
```

# symlink をホストの「ファイル」に volume マウントしてみる

コンテナ内の symlink をホストのファイルに volume マウントして実行してみます。

```console
$ docker run --rm -it \
  -v $(pwd)/File-A.txt:/symlinktest/Link-A.txt \
  -v $(pwd)/Dir-B:/symlinktest/Link-B \
  symlinktest bash
root@b6ee2e7b3f91:/# cd /symlinktest
root@b6ee2e7b3f91:/symlinktest# ls -lR
.:
total 4
drwxrwxr-x 2 1001 1001 23 Jul 15 02:29 Dir-B
-rw-rw-r-- 1 1001 1001 15 Jul 15 02:25 File-A.txt
lrwxrwxrwx 1 root root 23 Jul 15 02:20 Link-A.txt -> /symlinktest/File-A.txt
lrwxrwxrwx 1 root root 18 Jul 15 02:20 Link-B -> /symlinktest/Dir-B

./Dir-B:
total 4
-rw-rw-r-- 1 1001 1001 15 Jul 15 02:29 File-B.txt
root@b6ee2e7b3f91:/symlinktest# cat Link-A.txt
File-A in Host
root@b6ee2e7b3f91:/symlinktest# cat File-A.txt
File-A in Host
root@b6ee2e7b3f91:/symlinktest# cat Link-B/File-B.txt
File-B in Host
root@b6ee2e7b3f91:/symlinktest# cat Dir-B/File-B.txt
File-B in Host
```
symlink は volume マウントする前と同じ symlink のまま、リンク先のファイルやディレクトリがホストにマウントされているのがわかります。

# symlink をホストの「symlink」に volume マウントしてみる

こんどは、コンテナ内の symlink をホストの symlink に volume マウントして実行してみます。

```console
$ docker run --rm -it \
  -v $(pwd)/Link-A.txt:/symlinktest/Link-A.txt \
  -v $(pwd)/Link-B:/symlinktest/Link-B \
  symlinktest bash
root@12da063efba3:/# cd /symlinktest
root@12da063efba3:/symlinktest# ls -lR
.:
total 4
drwxrwxr-x 2 1001 1001 23 Jul 15 02:29 Dir-B
-rw-rw-r-- 1 1001 1001 15 Jul 15 02:25 File-A.txt
lrwxrwxrwx 1 root root 23 Jul 15 02:20 Link-A.txt -> /symlinktest/File-A.txt
lrwxrwxrwx 1 root root 18 Jul 15 02:20 Link-B -> /symlinktest/Dir-B

./Dir-B:
total 4
-rw-rw-r-- 1 1001 1001 15 Jul 15 02:29 File-B.txt
root@12da063efba3:/symlinktest# cat Link-A.txt
File-A in Host
root@12da063efba3:/symlinktest# cat File-A.txt
File-A in Host
root@12da063efba3:/symlinktest# cat Link-B/File-B.txt
File-B in Host
root@12da063efba3:/symlinktest# cat Dir-B/File-B.txt
File-B in Host
root@12da063efba3:/symlinktest#
```

結果は同様でした。
symlink は volume マウントする前と同じ symlink のまま、リンク先のファイルやディレクトリがホストのリンク先のファイルやディレクトリにマウントされています。

# まとめ
どうやら、docker の volume によるホストマウントは、マウント先もマウント元も、symlink を dereference (follow) して、リンク先をマウント対象として扱うようです。

これのおかげで実際ハマった話をこっちに書きました。
[「Docker で /etc/localtime をホストに volume マウントしてハマった話」](https://qiita.com/jeffi7/items/9d4c85cf049644f711b8)