docker-bind挂载
使用绑定挂载
自Docker早期以来,绑定挂载一直存在。与卷相比,绑定装载具有有限的功能。使用绑定装入时,主机上的文件或目录将装入容器中。文件或目录由其在主机上的完整路径或相对路径引用。相反,当您使用卷时,会在主机上的Docker存储目录中创建一个新目录,Docker会管理该目录的内容。
该文件或目录不需要已存在于Docker主机上。如果它尚不存在,则按需创建。绑定挂载非常高效,但它们依赖于具有特定目录结构的主机文件系统。如果正在开发新的Docker应用程序,请考虑使用命名卷。无法使用Docker CLI命令直接管理绑定装入。
-v
和--mount
行为之间的差异
因为-v
和--volume
flags一直是Docker的一部分,所以它们的行为无法改变。这意味着在-v
和之间存在一种不同的行为--mount
。
如果使用-v
或--volume
绑定装载Docker主机上尚不存在的文件或目录,请-v
为您创建端点。它始终作为目录创建。
如果使用--mount
绑定docker主机上存在的文件或目录,Docker 容器也不会自动为创建它,但会产生一个错误。
使用绑定装载启动容器
考虑一个具有目录的情况,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"
}
],
这表明mount是一个bind
mount,它显示了正确的源和目标,它表明mount是读写的,并且传播设置为rprivate
。
停止容器:
$ docker container stop devtest
$ docker container rm devtest
挂载到容器上的非空目录中
如果将bind-mount绑定到容器上的非空目录中,则绑定装置会隐藏目录的现有内容。这可能是有益的,例如当想要测试新版本的应用程序而不构建新图像时。但是,它也可能令人惊讶,并且此行为与docker卷的行为不同。
此示例设计为极端,但将容器/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
通过在容器中的挂载点之后添加(默认情况下为空)选项列表,将目录挂载为只读绑定挂载。如果存在多个选项,请用逗号分隔。
$ 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 |
默认值。与private相同,意味着原始或副本装入点中任何位置的装载点都不会沿任一方向传播。 |
在可以在挂载点上设置绑定传播之前,主机文件系统需要已经支持绑定传播。
有关绑定传播的更多信息,请参阅共享子树的 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/
也存在。