使用绑定安装

预计阅读时间:13分钟

自Docker诞生以来,绑定挂载就已经存在。与相比,绑定安装的功能有限。使用绑定安装时,主机上的文件或目录将安装到容器中。该文件或目录由其在主机上的绝对路径引用。相比之下,当您使用卷时,将在主机上的Docker的存储目录中创建一个新目录,并且Docker管理该目录的内容。

该文件或目录不需要在Docker主机上已经存在。如果尚不存在,则按需创建。绑定挂载性能很高,但是它们依赖于主机的文件系统,该文件系统具有可用的特定目录结构。如果要开发新的Docker应用程序,请考虑使用 命名卷。您不能使用Docker CLI命令直接管理绑定安装。

在Docker主机上绑定挂载

选择-v或--mount标志

总的来说,--mount是更明确和冗长的。最大的区别是该-v语法在一个字段中将所有选项组合在一起,而--mount 语法将它们分开。这是每个标志的语法比较。

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

  • -v--volume:由三个字段组成,以冒号(:)分隔。这些字段必须以正确的顺序排列,并且每个字段的含义不是立即显而易见的。
    • 对于绑定安装,第一个字段是主机上文件或目录的路径。
    • 第二个字段是文件或目录在容器中的安装路径。
    • 第三个字段是可选的,并且是用逗号分隔的选项,诸如列表rozZ。这些选项将在下面讨论。
  • --mount:包含多个键值对,以逗号分隔,每个键值对都由一个<key>=<value>元组组成。该--mount语法是更详细的比-v--volume,但按键的顺序并不显著,并且标志的价值更容易理解。
    • type安装件,其可以是bindvolume,或tmpfs。本主题讨论绑定安装,因此类型始终为bind
    • source的安装。对于绑定安装,这是Docker守护程序主机上文件或目录的路径。可以指定为sourcesrc
    • destination作为其值,其中的文件或目录被安装在容器的路径。可以指定为destinationdsttarget
    • readonly选项(如果存在)会使绑定安装以只读方式安装到容器中
    • bind-propagation选项(如果存在)将更改 绑定传播。可以是一个rprivateprivatersharedsharedrslaveslave
    • --mount标志不支持z或没有Z用于修改selinux标签的选项。

下面的示例在可能的地方同时显示--mount-v语法,并 --mount首先展示。

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

由于-vand--volume标志已经很长时间成为Docker的一部分,因此它们的行为无法更改。这意味着之间存在一种不同的行为。-v--mount

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

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

使用绑定安装启动容器

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

下面的--mount-v示例产生相同的结果。您不能同时运行它们,除非devtest在运行第一个容器后将其删除。

$ 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 volume的行为。

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

--mount-v实施例具有相同的最终结果。

$ 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实例有同样的结果。

$ 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实例有同样的结果。

$ 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选项指示绑定安装内容在多个容器之间共享。
  • Z选项指示绑定安装内容是私有的且未共享。

这些选项请格外小心。绑定安装系统目录(例如/home/usr带有该Z选项)会使您的主机无法操作,并且您可能需要手动重新标记主机文件。

重要说明:将绑定安装与服务一起使用时,selinux标签(:Z:z)以及将:ro被忽略。有关详细信息,请参见 moby / moby#32579

本示例设置z选项以指定多个容器可以共享绑定安装的内容:

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

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

下一步

存储持久性数据持久性挂载绑定挂载