bigywater.tech
Docker · 27

volume 与 bind mount:权限、性能和生命周期

数据放 volume 还是 bind mount?它们在生命周期、初始内容、速度和写错路径时的行为上差别不小。这篇在 macOS 的 Docker Desktop 上逐项实测。

361 ms vs 20 ms
建 1000 个小文件:宿主机 bind mount 与命名卷
匿名卷还在
docker rm 不带 -v 时,匿名卷不会被删
退出码 125
--mount type=bind 指向不存在的宿主机路径时直接报错

生命周期

实测 · 本机执行输出
  容器退出后:命名卷 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=… 则直接报错。路径拼错时,后者更容易发现。

分步演示

volume 与 bind mount
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。性能测试在 python:3.12-alpine 容器里用 time.perf_counter 计时:写 64 MiB(含 fsync)、建 1000 个 1 字节文件、顺序读 64 MiB、listdir 20 次;三种位置各 3 轮取中位数;bind mount 的宿主机目录在本项目的临时目录下(位于 macOS 的 APFS 上);实验后已删除容器、卷、镜像和宿主机上的临时目录
    • 没有验证:Linux 宿主机上的 bind mount 速度、Docker Desktop 的其它文件共享实现、bind mount 的权限映射(见后面的挂载卷权限一篇)、NFS 或远程卷驱动、卷的备份与迁移
    京ICP备2026067502号-1京公网安备11010502063487号