Docker 基础知识 - 使用绑定挂载(bind mounts)管理应用程序数据
绑定挂载(bind mounts)在 Docker 的早期就已经出现了。与卷相比,绑定挂载的功能有限。当您使用绑定挂载时,主机上的文件或目录将挂载到容器中。文件或目录由其在主机上的完整或相对路径引用。相反地,当您使用卷时,在主机上 Docker 的存储目录中创建一个新目录,Docker 管理该目录的内容。
该文件或目录不需要已经存在于 Docker 主机上。如果还不存在,则按需创建。绑定挂载的性能非常好,但它们依赖于主机的文件系统,该文件系统具有特定的可用目录结构。如果您正在开发新的 Docker 应用程序,请考虑改用命名卷。不能使用 Docker CLI 命令直接管理绑定挂载。
选择 -v
或者 --mount
标记
最初,-v
或 --volume
标记用于独立容器,--mount
标记用于集群服务。但是,从 Docker 17.06 开始,您也可以将 --mount
用于独立容器。通常,--mount
标记表达更加明确和冗长。最大的区别是 -v
语法将所有选项组合在一个字段中,而 --mount
语法将选项分离。下面是每个标记的语法比较。
新用户推荐使用
--mount
语法,有经验的用户可能更熟悉-v
or--volume
语法,但是更鼓励使用--mount
语法,因为研究表明它更易于使用。
-v
或--volume
: 由三个字段组成,以冒号(:)分隔。字段必须按照正确的顺序排列,且每个字段的含义不够直观明显。- 对于绑定挂载(bind mounts), 第一个字段是主机上文件或目录的路径。
- 第二个字段是容器中文件或目录挂载的路径。
- 第三个字段是可选的,是一个逗号分隔的选项列表,比如
ro
、consistent
、delegated
、cached
、z
和Z
。这些选项会在本文下面讨论。
--mount
:由多个键-值对组成,以逗号分隔,每个键-值对由一个<key>=<value>
元组组成。--mount
语法比-v
或--volume
更冗长,但是键的顺序并不重要,标记的值也更容易理解。- 挂载的类型(
type
),可以是bind
、volume
或者tmpfs
。本主题讨论绑定挂载(bind mounts),因此类型(type
)始终为绑定挂载(bind
)。 - 挂载的源(
source
),对于绑定挂载,这是 Docker 守护进程主机上的文件或目录的路径。可以用source
或者src
来指定。 - 目标(
destination
),将容器中文件或目录挂载的路径作为其值。可以用destination
、dst
或者target
来指定。 readonly
选项(如果存在),则会将绑定挂载以只读形式挂载到容器中。bind-propagation
选项(如果存在),则更改绑定传播。 可能的值是rprivate
、private
、rshared
、shared
、rslave
或slave
之一.consistency
选项(如果存在), 可能的值是consistent
、delegated
或cached
之一。 这个设置只适用于 Docker Desktop for Mac,在其他平台上被忽略。--mount
标记不支持用于修改 selinux 标签的z
或Z
选项。
- 挂载的类型(
下面的示例尽可能同时展示 --mount
和 -v
两种语法,并且先展示 --mount
。
-v
和 --mount
行为之间的差异
由于 -v
和 -volume
标记长期以来一直是 Docker 的一部分,它们的行为无法改变。这意味着 -v
和 -mount
之间有一个不同的行为。
如果您使用 -v
或 -volume
来绑定挂载 Docker 主机上还不存在的文件或目录,则 -v
将为您创建它。它总是作为目录创建的。
如果使用 --mount
绑定挂载 Docker 主机上还不存在的文件或目录,Docker 不会自动为您创建它,而是产生一个错误。
启动带有绑定挂载的容器
考虑这样一个情况:您有一个目录 source
,当您构建源代码时,工件被保存到另一个目录 source/target/
中。您希望工件在容器的 /app/
目录可用,并希望每次在开发主机上构建源代码时,容器能访问新的构建。使用以下命令将 target/
目录绑定挂载到容器的 /app/
。在 source
目录中运行命令。在 Linux 或 macOS 主机上,$(pwd)
子命令扩展到当前工作目录。
下面的 --mount
和 -v
示例会产生相同的结果。除非在运行第一个示例之后删除了 devtest
容器,否则不能同时运行它们。
--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"
}
],
这表明挂载是一个 bind
挂载,它显示了正确的源和目标,也显示了挂载是可读写的,并且传播设置为 rprivate
。
停止容器:
$ docker container stop devtest
$ docker container rm devtest
挂载到容器上的非空目录
如果您将其绑定挂载到容器上的一个非空目录中,则该目录的现有内容会被绑定挂载覆盖。这可能是有益的,例如当您想测试应用程序的新版本而不构建新镜像时。然而,它也可能是令人惊讶的,这种行为不同于 docker volumes。
这个例子被设计成极端的,仅仅使用主机上的 /tmp/
目录替换容器的 /usr/
目录的内容。在大多数情况下,这将导致容器无法正常工作。
--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
和 -v
示例有相同的结果。
--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 | 类似于共享(shared)挂载,但仅在一个方向上。如果原始挂载公开子挂载,副本挂载可以看到它。但是,如果副本挂载公开子挂载,则原始挂载无法看到它。 |
private | 该挂载是私有的。原始挂载的子挂载不公开给副本挂载,副本挂载的子挂载也不公开给原始挂载。 |
rshared | 与 shared 相同,但传播也扩展到嵌套在任何原始或副本挂载点中的挂载点。 |
rslave | 与 slave 相同,但传播也扩展到嵌套在任何原始或副本挂载点中的挂载点。 |
rprivate | 默认值。与 private 相同,这意味着原始或副本挂载点中的任何位置的挂载点都不会在任何方向传播。 |
当你在挂载点上设置绑定传播之前,主机文件系统需要已经支持绑定传播。
有关绑定传播的更多信息,请参见 Linux 内核共享子树文档。
下面的示例两次将 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/
也存在。
配置 selinux 标签
如果使用 selinux
,则可以添加 z
或 Z
选项,以修改挂载到容器中的主机文件或目录的 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
为 macOS 配置挂载一致性
Docker Desktop for Mac 使用 osxfs
将从 macOS 共享的目录和文件传播到 Linux VM。这种传播使运行在 Docker Desktop for Mac 上的 Docker 容器可以使用这些目录和文件。
默认情况下,这些共享是完全一致的,这意味着每次在 macOS 主机上或通过容器中的挂载发生写操作时,更改都会刷新到磁盘上,以便共享中的所有参与者都拥有完全一致的视图。在某些情况下,完全一致性会严重影响性能。Docker 17.05及更高版本引入了一些选项,在每个挂载、每个容器的基础上调整一致性设置。以下选项可供选择:
consistent
或default
: 完全一致性的默认设置,如上所述。delegated
: 容器运行时的挂载视图是权威的。在容器中所做的更新,在主机上可见之前,可能会有延迟。cached
: macOS 主机的挂载视图是权威的。在主机上所做的更新,在容器中可见之前,可能会有延迟。
这些选项在除 macOS 之外的所有主机操作系统上都被完全忽略。
--mount
和 -v
示例有相同的结果。
--mount
:
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,destination=/app,consistency=cached \
nginx:latest
-v
:
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:cached \
nginx:latest
Docker 基础知识 - 使用绑定挂载(bind mounts)管理应用程序数据的更多相关文章
- Docker 基础知识 - 使用 tmpfs 挂载(tmpfs mounts)管理应用程序数据
卷(volumes) 和 绑定挂载(bind mounts) 允许您在主机和容器之间共享文件,这样即使在容器停止后也可以持久存储数据. 如果在 Linux 上运行 Docker,那么还有第三种选择:t ...
- docker从零开始 存储(三)bind mounts
使用bind mounts 自Docker早期以来bind mounts 一直存在.与volumes相比,绑定挂载具有有限的功能.使用bind mounts时,主机上的文件或目录将装入容器中.文件或目 ...
- Docker03 Docker基础知识、Docker实战
1 Docker基础知识 1.1 什么是Docker Docker是一个可以装应用的容器,就像杯子可以装水.书包可以装书一样:docker官网 Docker是Docker公司开发的,并开源到GitHu ...
- Docker进阶之七:管理应用程序数据
管理应用程序数据:Volume Docker提供三种不同的方式将数据从宿主机挂载到容器中:volumes,bind mounts和tmpfs. volumes:Docker管理宿主机文件系统的一部分( ...
- [转] docker基础知识之挂载本地目录
[From] https://blog.csdn.net/huludan/article/details/52641090 https://my.oschina.net/piorcn/blog/324 ...
- Docker 基础知识 - 使用卷(volume)管理应用程序数据
卷(volumes)是 Docker 容器生产和使用持久化数据的首选机制.绑定挂载(bind mounts)依赖于主机的目录结构,卷(volumes)完全由 Docker 管理.卷与绑定挂载相比有几个 ...
- docker学习---docker基础知识
目录 docker的基础 1.安装docker 2.使用镜像 3.镜像迁移|导入和导出 4.docker Hub介绍 5.搭建私有镜像仓库 5.1.docker开源的镜像分发工具--docker Re ...
- Docker 基础知识 - Docker 概述
Docker 是一个开发.发布和运行应用程序的开放平台.Docker使您能够将应用程序与基础架构分离,以便快速交付软件.有了 Docker,你可以像管理应用程序一样管理你的基础设施.通过利用 Dock ...
- Docker基础知识及入门
什么是Docker? Docker是由dotcloud公司使用golang语言进行开发的,基于Linux内核的 cgroup,namespace,以及OverlayFS类的Union FS等技术,对进 ...
随机推荐
- 提交代码到gitbub.com
提交代码到gitbub.com touch README.md //新建说明文件 git init //在当前项目目录中生成本地git管理,并建立一个隐藏.git目录 git add . //添加当前 ...
- Cannot instantiate the type Map
今天在使用Map中犯了个低级错误,记录一下: 打算使用map为一个视频List观看记录的统计标识,key为vid,value默认为false,当该key已经统计,标识value为true,初始实例化M ...
- 尚学堂 217 java中的字节码操作2
package com.bjsxt.test; @Author(name="gaoqi", year=2014) public class Emp { private int em ...
- 用Map+函数式接口来实现策略模式
用Map+函数式接口来实现策略模式 目前在魔都,贝壳找房是我的雇主,平时关注一些 java 领域相关的技术,希望你们能在这篇文章中找到些有用的东西.个人水平有限,如果文章有错误还请指出,在留言区一起交 ...
- 华为云—环境安装(jdk安装,tomcat安装)
前言 在前面咱们讲到华为云的购买以及一些配置,通过上一文即可获得一个可以直接访问使用的云服务器.但是对于不同的人群服务器的使用用途可能不同,对于咱们大部分的java程序员来说,jdk.tomcat.m ...
- win10 麦克风无法使用,可能是设置了权限
驱动什么的都正常,平白无故麦克风不好用了,原来是之前自己设置了麦克风权限: 把这个开关打开就可以了. (完)
- Python数据结构(二)
array固定类型的数据序列,与list类似,只不过成员必须是相同的基本类型 array.typecodes #包含所有可用类型代码的字符串bBuhHiIlLqQfd 输入代码 C型 Python类型 ...
- Alink漫谈(十) :特征工程 之 特征哈希/标准化缩放
Alink漫谈(十) :特征工程之特征哈希/标准化缩放 目录 Alink漫谈(十) :特征工程之特征哈希/标准化缩放 0x00 摘要 0x01 相关概念 1.1 特征工程 1.2 特征缩放(Scali ...
- python 中去除空格的方法
python 中去除空格的方法: def trim(s): l=[] for i in s: if i!=' ': l.append(i) return ''.join(l) 其中可以使用下面的 '' ...
- 线程基础知识01-Thread类,Runnable接口
常见面试题:创建一个线程的常用方法有哪些?Thread创建线程和Runnable创建线程有什么区别? 答案通常集中在,继承类和实现接口的差别上面: 如果深入问一些问题:1.要执行的任务写在run()方 ...