数据放 volume 还是 bind mount?它们在生命周期、初始内容、速度和写错路径时的行为上差别不小。这篇在 macOS 的 Docker Desktop 上逐项实测。
容器退出后:命名卷 bwlab-c22-named、匿名卷 5d2bd555e402…(64 位随机名)都存在?True / True docker rm(不带 -v)之后:命名卷在?True;匿名卷在?True 新容器挂上命名卷,读到 /data/f.txt = keep docker rm -v 之后:匿名卷在?False
命名卷在容器删除后还在,新容器可以再挂载读到数据。匿名卷也是:docker rm 不带 -v 时它成了没人引用的孤儿,要用 docker rm -v 才会随容器删除。
镜像的 /app 里有 hello.txt;空的命名卷挂到 /app:ls = hello.txt(卷第一次挂载时,镜像该目录的内容被复制进去)
空的宿主机目录 bind mount 到 /app:ls = (空)(镜像里的内容被盖住了)
宿主机目录里事后有文件吗?[]
重建镜像(hello.txt 内容改成 from-image-v2)后,再挂同一个已有内容的卷:
cat /app/hello.txt = from-image(卷里已有第一次复制进去的 from-image,新镜像里的 from-image-v2 不会覆盖它)空的命名卷第一次挂载到镜像里有内容的目录时,docker 会把镜像该目录的内容复制进去;bind mount 不会,宿主机目录会把镜像里的内容整个盖住。卷里已有内容之后,新镜像的内容不会覆盖它。
容器可写层:写 64 MiB 含 fsync 62 ms;建 1000 个小文件 42 ms;顺序读 64 MiB 21 ms;listdir 20 次 4 ms(3 轮取中位数) 命名卷:写 64 MiB 含 fsync 36 ms;建 1000 个小文件 20 ms;顺序读 64 MiB 18 ms;listdir 20 次 4 ms(3 轮取中位数) bind mount(宿主机目录):写 64 MiB 含 fsync 167 ms;建 1000 个小文件 361 ms;顺序读 64 MiB 51 ms;listdir 20 次 57 ms(3 轮取中位数)
这是 macOS 上的数字:命名卷在 Docker Desktop 虚拟机自己的磁盘上(我的理解,没有在虚拟机里核对路径),速度和容器可写层同一量级;bind mount 要经过宿主机与虚拟机之间的文件共享,大文件顺序读写慢约 3~5 倍,小文件创建慢约 18 倍(361 ms 对 20 ms),目录遍历慢约 14 倍。Linux 宿主机上的 bind mount 不一定是这样,我没有测。每个场景只有 3 轮,数字有抖动,看量级。
-v c22-missing-v:/x → 退出码 0;宿主机上现在有这个目录吗?True --mount type=bind,source=c22-missing-m → 退出码 125;docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /host_mnt<dtmp>/c22-missing-m;宿主机上有这个目录吗?False
-v /不存在的路径:/x 会在宿主机上悄悄创建这个目录;--mount type=bind,source=… 则直接报错。路径拼错时,后者更容易发现。