Docker 17
引擎: 管理员指南 | Engine: Admin Guide

绑定挂载 | Bind mounts (Engine)

使用绑定挂载

绑定挂载从 Docker 早期开始就已经存在。与卷相比,绑定安装具有有限的功能。当您使用绑定挂载时,主机上的文件或目录被挂载到容器中。文件或目录由主机上的完整路径或相对路径引用。相比之下,当您使用卷时,会在主机上的 Docker 存储目录中创建一个新目录,并且 Docker 会管理该目录的内容。

文件或目录不需要已经存在于 Docker 主机上。如果它尚不存在,它会根据需求创建。绑定挂载非常高效,但它们依赖于具有特定目录结构的主机的文件系统。如果您正在开发新的 Docker 应用程序,请考虑使用命名卷。您不能使用 Docker CLI 命令直接管理绑定挂载。

选择-v 或-mount 标志

最初,-v--volume用标志独立的容器和--mount用于群服务标志。但是,从 Docker 17.06开始,您也可以使用--mount独立容器。一般来说,--mount更明确和详细。最大的区别在于,-v语法将所有选项组合在一个字段中,而--mount语法将它们分开。这是每个标志的语法比较。

提示:新用户应使用--mount语法。有经验的用户可能更熟悉这个语法-v--volume语法,但鼓励使用--mount,因为研究表明它更易于使用。

  • -v 或者 --volume:由三个由冒号(:)分隔的字段组成。这些字段必须按正确的顺序排列,每个字段的含义并不明显。

以下示例在可能的地方显示了语法--mount-v语法,并且--mount首先给出。

-v与--mount行为之间的差异

由于-v--volume标志长期以来一直是 Docker 的一部分,它们的行为不能改变。这意味着-v和** --mount之间有一个不同的行为

如果您使用-v--volume绑定 Docker 主机上尚不存在的文件或目录,-v将为您创建端点。它始终创建为一个目录。

如果您使用--mount绑定贴装Docker主机上尚不存在的文件或目录,Docker也不会自动为您创建它,但会产生一个错误。

使用绑定安装启动容器

考虑一个你有source目录的情况,并且当你构建源代码时,工件被保存到另一个目录中source/target/。您希望工件对容器可用/app/,并且您希望容器每次在开发主机上构建源时都可以访问新的构建。使用以下命令将target/目录绑定到您的容器中/app/。从source目录内运行命令。$(pwd)子命令将扩展到 Linux 或者 MacOS 主机的当前工作目录。

--mount-v以下实施例产生相同的结果。除非在运行第一个容器后移除devtest容器,否则无法运行它们。

  • --mount

$ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ nginx:latest

$ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ nginx:latest

使用docker inspect devtest验证绑定安装正确创建。寻找Mounts部分:

"Mounts": [ { "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" } ],

这表明挂载是一个bind挂载,它显示了正确的源和目标,它显示挂载是可读写的,并且传播设置为rprivate

停止容器:

$ docker container stop devtest $ docker container rm devtest

安装到容器上的非空目录中

如果将绑定挂载到容器上的非空目录中,则该目录的现有内容将被绑定挂载隐藏。这可能是有益的,例如,当您想要测试新版本的应用程序而无需构建新映像时。然而,这也可能令人惊讶,并且这种行为不同于docker卷的行为。

这个例子被认为是极端的,但会将容器/usr/目录的内容替换/tmp/为主机上的/tmp/目录。在大多数情况下,这会导致无法正常工作的容器。

--mount-v的示例,最后的结果是一样的。

  • --mount

$ docker run -d \ -it \ --name broken-container \ --mount type=bind,source=/tmp,target=/usr \ nginx:latest docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "exec: \"nginx\": executable file not found in $PATH".

$ docker run -d \ -it \ --name broken-container \ -v /tmp:/usr \ nginx:latest docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "exec: \"nginx\": executable file not found in $PATH".

该容器已创建但未启动。去掉它:

$ docker container rm broken-container

使用只读绑定安装

对于某些开发应用程序,容器能够写入绑定安装非常有用,以便将更改传播回 Docker 主机。在其他时候,容器应该只能读取数据而不能修改它。

此示例修改上面的示例,但通过在容器中的装入点之后添加ro选项列表(默认为空),将目录装载为只读绑定装入。如果存在多个选项,请用逗号分隔它们。

--mount-v的实例有同样的结果。

  • --mount

$ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app,readonly \ nginx:latest

$ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app:ro \ nginx:latest

使用docker inspect devtest验证绑定安装正确创建。寻找Mounts部分:

"Mounts": [ { "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "ro", "RW": false, "Propagation": "rprivate" } ],

停止容器:

$ docker container stop devtest $ docker container rm devtest

配置绑定传播

绑定传播默认rprivate为绑定安装和卷。它只能配置绑定挂载,并且只能在 Linux 主机上配置。绑定传播是一个高级话题,许多用户从不需要配置它。

绑定传播是指在给定的绑定挂载或命名卷中创建的挂载是否可以传播到该挂载的副本。考虑一个挂载点/mnt,它也被挂载/tmp。传播设置控制是否挂载/tmp/a也可用/mnt/a。每个传播设置都有一个递归对应点。在递归的情况下,考虑/tmp/a也被挂载为/foo。传播设置控制是否/mnt/a和/或/tmp/a将存在。

传播设置描述
shared原始安装的子安装会暴露给副本安装,并且副安装的子安装也会传播到原始安装。
slave类似于共享安装,但仅限于一个方向。如果原始安装展示了一个子安装,则副本安装可以看到它。但是,如果副本安装公开了子安装,则原始安装无法看到它。
private该挂载是私人的。其中的子安装不会暴露给副本安装,并且副安装的子安装不会暴露给原始安装。
rshared与共享相同,但传播也扩展到嵌套在任何原始或副本装入点内的挂载点。
rslave与从属设备相同,但传播还扩展到嵌套在任何原始或副本安装点内的挂载点。
rprivate默认值。与私有相同,这意味着原始或副本安装点内的任何位置的安装点都不会沿任一方向传播。

在可以在安装点上设置绑定传播之前,主机文件系统需要已经支持绑定传播。

有关绑定传播的更多信息,请参阅共享子树Linux 内核文档

以下示例将target/目录装入容器两次,第二个装入设置ro选项和rslave绑定传播选项。

--mount-v实例有同样的结果。

  • --mount

$ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ --mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \ nginx:latest

$ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ -v "$(pwd)"/target:/app2:ro,rslave \ nginx:latest

现在如果你创建/app/foo//app2/foo/也会存在。

配置 selinux 标签

如果您使用selinux,您可以添加zZ选项来修改正在装入容器的主机文件或目录selinux 标签。这会影响主机本身的文件或目录,并可能导致 Docker 范围之外的后果。

  • z选项指示绑定安装内容在多个容器之间共享。

使用极端谨慎使用这些选项。绑定系统目录(例如/home/usr带有Z选项)会导致主机无法操作,您可能需要手动重新标记主机文件。

此示例设置z选项以指定多个容器可以共享绑定挂载的内容:

使用--mount标志不可能修改 selinux 标签。

$ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app:z \ nginx:latest

配置 macOS 的安装一致性

Docker for Mac 用于osxfs将从macOS共享的目录和文件传播到 Linux VM。这种传播使这些目录和文件可用于在 Docker for Mac 上运行的 Docker 容器。

默认情况下,这些共享是完全一致的,这意味着每次在 macOS 主机上发生写入或通过容器中的挂载时,都会将更改刷新到磁盘,以便共享中的所有参与者都具有完全一致的视图。在某些情况下,完全一致可能会严重影响性能。Docker 17.05 和更高版本引入了选项来调整每个安装,每个容器的一致性设置。以下选项可用:

  • consistent或者default:完全一致的默认设置,如上所述。

这些选项在除 macOS 之外的所有主机操作系统上完全忽略。

--mount-v实例有同样的结果。

  • --mount

$ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,destination=/app,consistency=cached \ nginx:latest

$ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app:cached \ nginx:latest

下一步

  • 了解卷。

storage, persistence, data persistence, mounts, bind mounts