绑定挂载 | 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
:由三个由冒号(:
)分隔的字段组成。这些字段必须按正确的顺序排列,每个字段的含义并不明显。- 在绑定挂载的情况下,第一个字段是主机上文件或目录的路径。
- 第二个字段是文件或目录将被安装在容器中的路径。
- 第三个字段是可选的,并且是用逗号分隔的选项,诸如列表
ro
,consistent
,delegated
,cached
,z
,和Z
。这些选项在下面讨论。
--mount
:由多个键值对组成,由逗号分隔,每个由一个<key>=<value>
元组组成。--mount
语法比更详细的-v
或--volume
,但按键的顺序并不显著,并且标志的价值更容易理解。type
安装件,其可以是bind
,volume
,或tmpfs
。本主题讨论绑定挂载,因此类型将始终如此bind
。source
安装的。对于绑定挂载,这是 Docker 守护程序主机上文件或目录的路径。可能被指定为source
或src
。destination
作为其值,其中的文件或目录将被安装在容器的路径。可以指定为destination
,dst
或target
。readonly
选项(如果存在)将导致绑定挂载以只读方式挂载到容器中。bind-propagation
选项(如果存在)会更改绑定传播。可以是一个rprivate
,private
,rshared
,shared
,rslave
,slave
。consistency
选项,如果存在,可以是一种consistent
,delegated
或cached
。此设置仅适用于 Docker for Mac,并在所有其他平台上被忽略。--mount
标志不支持z
或Z
修改 selinux 标签的选项。
以下示例在可能的地方显示了语法--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
-v
$ 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
-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
的实例有同样的结果。
--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
实例有同样的结果。
--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
,您可以添加z
或Z
选项来修改正在装入容器的主机文件或目录的 selinux 标签。这会影响主机本身的文件或目录,并可能导致 Docker 范围之外的后果。
- 该
z
选项指示绑定安装内容在多个容器之间共享。 - 该
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
:完全一致的默认设置,如上所述。delegated
:容器运行时的挂载视图是权威的。在容器中进行的更新在主机上可见之前可能会有延迟。cached
:macOS 主机的挂载视图是权威的。在主机上进行的更新在容器内可见之前可能会有延迟。
这些选项在除 macOS 之外的所有主机操作系统上完全忽略。
--mount
和-v
实例有同样的结果。
--mount
-v
$ 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
下一步
- 了解卷。
- 了解 tmpfs mounts。
- 了解存储驱动程序。
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com