Docker 之管理应用数据—绑定挂载(三)

参考:https://docs.docker.com/storage/bind-mounts/

绑定挂载在Docker早期就已经出现了。与卷相比,绑定挂载的功能有限。使用绑定挂载时,将主机上的文件或目录挂载到容器中。文件或目录由其在主机上的完整或相对路径引用。相反,当您使用卷时,将在主机上Docker的存储目录中创建一个新目录,Docker将管理该目录的内容。

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

bind mounts on the Docker host

一、选择-v 或 --mount 标识

最初,-v或--volume标志用于独立容器,而--mount标志用于swarm服务。但是,从Docker 17.06开始,您还可以使用--mount  处理独立容器 。通常,--mount更显式、更详细。最大的区别是-v语法将所有选项组合在一个字段中,而--mount语法将它们分开。下面是每个标记的语法比较。

1、-v or --volume: 由三个字段组成,用冒号(:)分隔。字段必须按正确的顺序排列,而且每个字段的含义并不是马上就能看出来的。   

  •  在绑定挂载的情况下,第一个字段是到主机上的文件或目录的路径
  • 第二个字段是文件或目录挂载在容器中的路径。
  • 第三个字段是可选的,它是一个用逗号分隔的选项列表,比如ro、consistency、、cached、z 和 Z。下面将讨论这些选项。

2、--mount: 由多个键值对组成,用逗号分隔,每个键值对由一个<key>=<value>元组组成。--mount语法比-v或--volume更详细,但是键的顺序不重要,而且标记的值更容易理解。

  • 挂载的type,可以是bind、volume或tmpfs。本主题讨论绑定挂载,因此类型总是bind。
  • 挂载的源头(source),对于绑定挂载,这是到Docker守护进程主机上的文件或目录的路径。可以指定为source或src.
  • destination 将文件或目录挂载在容器中的路径作为其值。可以指定为destinationdst, 或 target .
  • 如果存在readonly选项,则会导致绑定挂载以只读形式挂载到容器中。
  • 如果存在bind-propagation选项,则更改绑定传播。可能是其中一个rprivate, private, rshared, shared, rslave, slave。
  • consistency选项(如果存在)可以是一致的、委托的或缓存的。此设置仅适用于Mac的Docker桌面,在所有其他平台上都被忽略。
  • --mount标记不支持修改selinux标签的z或z选项。

下面的示例展示了--mount和-v语法(如果可能的话),并首先介绍了--mount。

二、 -v 或--mount 行为之间的区别

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

  • 如果使用-v或--volume绑定挂载Docker主机上尚不存在的文件或目录,-v将为您创建端点。它总是被创建为一个目录。
  • 如果使用--mount来绑定挂载Docker主机上尚不存在的文件或目录,Docker不会自动为您创建它,而是生成一个错误

 

三、使用绑定挂载启动一个容器

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

--mount

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

-v

$ 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"
    }
],

这表明挂载是一个绑定挂载,它显示正确的源和目标,它显示挂载是读写的,传播被设置为rprivate。

停止容器

$ docker container stop devtest

$ docker container rm devtest

三、挂载到容器上的非空目录

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

这个示例比较极端,但是将容器的/usr/目录的内容替换为主机上的/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".

-v

$ 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 

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

-v

$ 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类似于共享挂载,但只有一个方向。如果原始挂载公开子挂载,则复制挂载可以看到它。但是,如果复制挂载公开子挂载,则原始挂载无法看到它。
privatemount是私有的。其中的子挂载不公开给副本挂载,并且副本挂载的子挂载不公开给原始挂载。
rshared与shared相同,但是传播也扩展到嵌套在任何原始或复制挂载点内的挂载点,并从这些挂载点进行扩展。
rslave与从挂载相同,但传播也扩展到嵌套在任何原始或复制挂载点内的挂载点,并从这些挂载点进行扩展。
rprivate默认值。与私有相同,这意味着在原始挂载点或复制挂载点内的任何位置都不会向任何方向传播。

在设置挂载点上的绑定传播之前,主机文件系统需要已经支持绑定传播。

有关绑定传播的更多信息,请参阅Linux kernel documentation for shared subtree

下面的示例将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

-v

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

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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值