Use bind mounts

预计阅读时间:14分钟

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

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

bind mounts on the Docker host

Choose the -v or --mount flag

通常, --mount更加明确和详细. 最大的区别是-v语法将所有选项组合在一个字段中,而--mount语法将它们分开. 这是每个标志的语法比较.

Tip

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

  • -v--volume :由三个字段组成,由冒号字符 ( : ) 分隔. 字段必须按正确的顺序排列,每个字段的含义不是很明显.
    • 在绑定挂载的情况下,第一个字段是主机上文件或目录的路径.
    • 第二个字段是文件或目录在容器中挂载的路径.
    • 第三个字段是可选的,是以逗号分隔的选项列表,例如rozZ . 这些选项将在下面讨论.
  • --mount :由多个键值对组成,以逗号分隔,每个由<key>=<value>元组组成. --mount语法比-v--volume更冗长,但键的顺序并不重要,标志的值更容易理解.
    • 挂载type ,可以是bindvolumetmpfs . 本主题讨论绑定挂载,因此类型始终为bind .
    • 坐骑的source . 对于绑定挂载,这是 Docker 守护程序主机上文件或目录的路径. 可以指定为sourcesrc .
    • destination将文件或目录安装在容器中的路径作为其值. 可以指定为destinationdsttarget .
    • readonly选项(如果存在)会导致绑定挂载以只读方式挂载到容器中.
    • bind-propagation选项(如果存在)会更改绑定传播. 可能是rprivateprivatersharedsharedrslaveslave之一.
    • --mount标志不支持用于修改 selinux 标签的zZ选项.

下面的示例在可能的情况下同时显示了--mount-v语法,并且首先显示了--mount .

Differences between -v and --mount behavior

因为-v--volume标志长期以来一直是 Docker 的一部分,所以它们的行为无法更改. 这意味着-v--mount之间存在一种不同的行为.

如果您使用-v--volume绑定挂载 Docker 主机上尚不存在的文件或目录,则-v会为您创建端点. 它始终创建为目录.

如果您使用--mount绑定挂载 Docker 主机上尚不存在的文件或目录,Docker不会自动为您创建它,但会生成错误.

Start a container with a bind mount

考虑这样一种情况,您有一个目录source ,并且当您构建源代码时,工件被保存到另一个目录source/target/中. 您希望工件在/app/处可用于容器,并且您希望每次在开发主机上构建源代码时容器都能访问新构建. 使用以下命令将target/目录绑定到/app/的容器中. 从source目录中运行命令. $(pwd)子命令扩展到 Linux 或 macOS 主机上的当前工作目录. 如果您使用的是 Windows,另请参阅 Windows上的路径转换.

下面的--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 .

Stop the container:

$ docker container stop devtest

$ docker container rm devtest

Mount into a non-empty directory on the container

如果您绑定挂载到容器上的非空目录,则该目录的现有内容会被绑定挂载遮盖. 这可能是有益的,例如当您想在不构建新映像的情况下测试应用程序的新版本时. 然而,它也可能令人惊讶,并且这种行为与docker volumes不同.

此示例被设计为极端,但将容器的/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

Use a read-only bind mount

对于某些开发应用程序,容器需要写入绑定挂载,因此更改会传播回 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

Configure bind propagation

对于绑定挂载和卷,绑定传播默认为rprivate . 它只能针对绑定挂载进行配置,并且只能在 Linux 主机上进行配置. 绑定传播是一个高级主题,许多用户从不需要配置它.

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

Warning

装载传播不适用于 Docker Desktop.

传播设置 Description
shared 原始挂载的子挂载暴露给副本挂载,并且副本挂载的子挂载也传播到原始挂载.
slave 类似于共享坐骑,但仅限于一个方向. 如果原始挂载暴露了子挂载,则副本挂载可以看到它. 但是,如果副本挂载暴露了子挂载,则原始挂载无法看到它.
private 坐骑是私人的. 其中的子挂载不暴露给副本挂载,副本挂载的子挂载不暴露给原始挂载.
rshared 与共享相同,但传播也延伸到嵌套在任何原始或副本安装点内的安装点.
rslave 与从属相同,但传播也延伸到嵌套在任何原始或副本安装点内的安装点.
rprivate 默认. 与私有相同,这意味着原始或副本安装点内的任何安装点都不会在任一方向传播.

Before you can set bind propagation on a mount point, the host filesystem needs to already support bind propagation.

有关绑定传播的更多信息,请参阅共享子树的 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/也存在.

Configure the selinux label

如果您使用selinux ,您可以添加zZ选项来修改要挂载到容器中的主机文件或目录的 selinux 标签. 这会影响主机本身的文件或目录,并可能产生 Docker 范围之外的后果.

  • z选项表示绑定挂载内容在多个容器之间共享.
  • Z选项表示绑定挂载内容是私有的和非共享的.

使用这些选项时要格外小心. 使用Z选项绑定挂载系统目录(例如/home/usr )会使您的主机无法运行,您可能需要手动重新标记主机文件.

重要提示:当使用绑定挂载服务时,selinux 标签( :Z:z )以及:ro将被忽略. 有关详细信息,请参阅moby/moby #32579 .

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

无法使用--mount标志修改 selinux 标签.

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

Use a bind mount with compose

带有绑定挂载的单个 Docker Compose 服务如下所示:

version: "3.9"
services:
  frontend:
    image: node:lts
    volumes:
      - type: bind
        source: ./static
        target: /opt/app/staticvolumes:
  myapp:

有关将bind类型的卷与 Compose 一起使用的更多信息,请参阅Compose 卷上的参考. 并撰写有关卷配置的参考.

Next steps

storage, persistence, 数据持久化, mounts, 绑定坐骑

by  icopy.site