使用绑定挂载(bind mount)
绑定挂载在Docker的早期就已经存在了。与卷相比,绑定挂载的功能非常有限。当您使用绑定挂载时,主机上的文件或目录会被挂载到一个容器中。文件或目录通过主机上的完整或相对路径引用。相比之下,当您使用卷时,将在宿主机的Docker的存储目录中创建一个新目录,并且Docker将管理该目录的内容。
文件或目录不需要在Docker宿主机上存在。如果目录或者文件还不存在,docker会自动创建出来。绑定挂载的性能非常好,但是它们依赖于主机文件系统的特定目录结构。如果您正在开发新的Docker应用程序,请考虑使用命名卷。您不能使用Docker CLI命令直接管理绑定挂载。
选择 -v or –mount 标志
最初,-v或--volume标志用于独立容器,而--mount标志用于群集服务。但是,从Docker 17.06开始,您也可以使用--mount独立的容器。一般来说,--mount更明确和详细。最大的区别在于-v语法将所有选项组合在一个字段中,而--mount语法将它们分开。以下是每个标志的语法比较。
提示:新用户应该使用--mount语法。有经验的用户可能更熟悉-v或--volume语法,但是鼓励使用--mount,因为研究表明它更易于使用。
-
- v或- volume:由三个字段组成,由冒号分隔(:)。字段必须按照正确的顺序书写,并且每个字段的含义都不是立刻确定。
- 在绑定挂载的情况下,第一个字段是到主机上的文件或目录的路径。
- 第二个字段是挂载到容器中的文件或目录的路径。
- 第三个字段是可选的,它是一个逗号分隔的选项列表,如ro、consistent、delegated、cached、z和Z。下面将讨论这些选项。
-
--mount:由多个键-值对组成,由逗号分隔,每一对由< key>= <value> tuple(元组)组成。--mount 语法比- v或—volume 更详细,其中键对的顺序并不重要,而且标记的值更容易理解。
- 挂载的类型(type),可以是绑定(bind)、卷(volume)或tmpfs。本主题讨论bind mount,因此类型将始终是bind mount。
- 挂载源(source)。对于绑定挂载,是指在宿主机上的文件或者目录路径。。可以通过source 或src参数指定。
- 挂在目标(destination),是指将挂载源挂载到docker 容器中的文件或者目录的路径。可以使用destination、dst或target 参数指定。
- 如果存在readonly选项,则绑定挂载为只读。
- 如果指定绑定传播(bind-propagation)选项,则其值可以是rprivate,private,rshared,shared,rslave,slave。
- 一致性选项,如果存在,其值可以是 consistent, delegated, or cached。这个设置只适用于Mac的Docker,在其他平台上都被忽略。
- --mount 参数不支持修改selinux标签的z或Z选项。
- v和- mount行为之间的差异
如果您使用- v或- volume来绑定在Docker宿主机上尚不存在的文件或目录,则- v将为您创建该端点(endpoint)。它总是创建为一个目录。
如果您使用 --mount 来绑定一个在Docker宿主机上尚不存在的文件或目录,Docker不会自动为您创建它,而是生成一个错误。
启动带卷参数的容器
假设有一个叫做source的目录,当您构建源代码时,生成的artifacts 被保存到source/target中。您希望这些生成的artifacts,在容器中被挂载到 /app 目录下,并且您希望每次在宿主机上重新构建之后,在容器中都能生效。使用以下命令将target目录绑定到/ app /中。从在source 目录中运行该命令。$(pwd)子命令表示Linux或macOS主机上的当前工作目录。
$ 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": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
删除容器
$ docker container stop devtest
$ docker container rm devtest
挂载到容器中的一个非空目录
如果将绑定挂载到容器上的非空目录中,则该目录的现有内容将被绑定挂载隐藏。这在有些时候是有好处的,例如,当您想要测试新版本的应用程序而无需构建新映像时。然而,这也可能是令人惊讶的,这种行为不同于docker volume。
本例的设计是极端的,但是将用宿主主机上的/ tmp 目录替换容器/usr 目录的内容。在大多数情况下,这将导致一个无用的容器。
$ 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选项(默认为空)。在这里可以有多个选项,用逗号分隔。
$ 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来验证bind mount 是否正确创建
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
],
删除镜像
$ docker container stop devtest
$ docker container rm devtest
配置绑定传播
对于绑定挂载(bind mount)和卷,绑定传播默认为 rprivate
。它只能配置绑定挂载,并且只能在Linux主机上配置。绑定传播是一个高级话题,大多数用户不需要配置它。
Propagation 是指在给定的挂载卷或命名卷中创建的挂载是否可以传播到该挂载的副本。考虑一个挂载点 /mnt
,它被挂载在 /tmp
。传播设置控制是否挂载 /tmp/a
也可用 /mnt/a
.每个 Propagation 设置都有一个递归对应点。在递归的情况下,考虑 /tml/a
被挂载为 /foo
。传播设置控制是否 /mnt/a
或 /tmp/a
将存在。
传播设定(Propagation setting) | 描述 |
---|---|
shared |
原始挂载的子挂载被暴露在复制挂载上,复制挂载的子挂载也会传播到原来的挂载。 |
slave |
类似于共享(share)挂载,但仅在一个方向上。如果原始挂载暴露一个子挂载,副本挂载可以看到它。但是,如果副本挂载公开了子挂载,则原始挂载无法看到它。 |
private |
私有,子挂载不暴露给副本挂载,副本挂在的子挂载也不暴露给原始挂载 |
rshared |
和共享(share)传播类似,但是传播扩展到原始或者副本挂载点的嵌套挂载点 |
rslave |
和slave 设置相同,但是传播扩展到原始和副本挂载点所嵌套挂载点 |
rprivate |
默认设置, 与私有相同,这意味着在原始或复制挂载点内的任何地方都不会向任意方向传播 |
在挂载点上设置绑定传播之前,主机文件系统需要支持绑定传播。
有关绑定传播的更多信息,请参见 共享子树的Linux内核文档。
下面的示例将 target/ 目录装载到容器中两次,第二个挂载设置ro选项和rslave绑定传播选项。
$ 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 /也会存在。