专栏首页VVcblogDocker 基础知识 - 使用绑定挂载(bind mounts)管理应用程序数据

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), 第一个字段是主机上文件或目录的路径。
    • 第二个字段是容器中文件或目录挂载的路径。
    • 第三个字段是可选的,是一个逗号分隔的选项列表,比如 roconsistentdelegatedcachedzZ。这些选项会在本文下面讨论。
  • --mount:由多个键-值对组成,以逗号分隔,每个键-值对由一个 <key>=<value> 元组组成。--mount 语法比 -v--volume 更冗长,但是键的顺序并不重要,标记的值也更容易理解。
    • 挂载的类型(type),可以是 bindvolume 或者 tmpfs。本主题讨论绑定挂载(bind mounts),因此类型(type)始终为绑定挂载(bind)。
    • 挂载的源(source),对于绑定挂载,这是 Docker 守护进程主机上的文件或目录的路径。可以用 source 或者 src 来指定。
    • 目标(destination),将容器中文件或目录挂载的路径作为其值。可以用 destinationdst 或者 target 来指定。
    • readonly 选项(如果存在),则会将绑定挂载以只读形式挂载到容器中。
    • bind-propagation 选项(如果存在),则更改绑定传播。 可能的值是 rprivateprivatersharedsharedrslaveslave 之一。
    • consistency 选项(如果存在), 可能的值是 consistentdelegatedcached 之一。 这个设置只适用于 Docker Desktop for Mac,在其他平台上被忽略。
    • --mount 标记不支持用于修改 selinux 标签的 zZ选项。

下面的示例尽可能同时展示 --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 ,则可以添加 zZ 选项,以修改挂载到容器中的主机文件或目录的 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及更高版本引入了一些选项,在每个挂载、每个容器的基础上调整一致性设置。以下选项可供选择:

  • consistentdefault: 完全一致性的默认设置,如上所述。
  • 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

原文链接:https://www.cnblogs.com/ittranslator/p/13352727.html

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Docker 基础知识 - 使用 tmpfs 挂载(tmpfs mounts)管理应用程序数据

    卷(volumes) 和 绑定挂载(bind mounts) 允许您在主机和容器之间共享文件,这样即使在容器停止后也可以持久存储数据。

    用户8803964
  • Docker实践(三):数据持久化及共享

     在Linux上运行的Docker有三种不同的方式将数据从 Docker Host挂载到 Docker 容器,并实现数据的读取和存储:volumes、bind ...

    loong576
  • 详解Docker——你需要知道的Docker进阶知识三

    针对上述的缺点,有些数据,例如数据库文件,我们不应该将其保存在镜像或者容器的可写层中。Docker 提供三种不同的方式将数据从 Docker 主机挂载到容器中,...

    云原生
  • Docker学习笔记之docker volume 容器卷的那些事(一)

    接触 docker 的朋友都知道,docker 镜像是以 layer 概念存在的,一层一层的叠加,最终成为我们需要的镜像。但该镜像的每一层都是 ReadOnly...

    Jetpropelledsnake21
  • 你必须知道的Docker数据卷(Volume)

    本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

    Edison Zhou
  • Docker-Volume

    存储卷(volume)是容器上的一个或多个目录,此类目录可绕过联合文件系统,与宿主机上的某个目录绑定(关联)。

    懒人的小脑
  • Docker学习——数据管理、使用网络(三)

    这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

    wuweixiang
  • Docker 基础知识 - 使用卷(volume)管理应用程序数据

    卷(volumes)是 Docker 容器生产和使用持久化数据的首选机制。绑定挂载(bind mounts)依赖于主机的目录结构,卷(volumes)完全由 D...

    用户8803964
  • Docker速学(二) Dockerfile和数据卷

    在前文,我们介绍了Docker学习的基本方法和原理,以及基础三大件:镜像、容器、仓库。

    w9
  • Docker数据共享与持久化

    本文介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

    Cyylog
  • docker数据管理

    用户在使用Docker的过程中,往往需要能查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间进行数据共享,这必然涉及到容器的数据管理操作...

    yuezhimi
  • Docker 数据管理介绍

    默认容器的数据是保存在容器的可读写层,当容器被删除时其上的数据也会丢失,所以为了实现数据的持久性则需要选择一种数据持久技术来保存数据。官方提供了三种存储方式:V...

    民工哥
  • Docker | Docker技术基础梳理(六) - 为啥容器里数据总是缺失?

    方便宿主机直接访问容器中的文件,容器中的文件没有持久化,当容器删除后,文件数据也会随之消失,且没有使用数据卷的容器,其他容器也无法直接访问相互的文件,如果你容器...

    咸鱼学Python
  • docker storage driver

    使用docker目录创建一个volume,并将该volume挂载到容器的/my_Cvol目录下

    charlieroro
  • 拒绝删库跑路!上手 Docker 容器数据管理

    数据是一切应用和服务的核心,特别是目睹了一次次“删库跑路”引发的惨剧之后,我们更能深入体会到数据存储与备份的重要性。Docker 也为我们提供了方便且强大的方式...

    一只图雀
  • docker 单机配置redis主从集群 集群 前置准备

    该文是docker redis主从配置 正式部署的前言。如下会简要列出目录,需要了解的前置知识,以防配置时出错。 如果你还不够了解,就阅读正文的相应章节。

    平凡的学生族
  • Docker数据管理与挂载管理

    数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

    踏歌行
  • n1.Docker命令参数一览表

    描述:利用 docker info 命令 Docker Client && Docker Server 信息一览:

    WeiyiGeek
  • docker 数据管理

    docker镜像被存储在一系列的只读层,当我们开启一个容器,docker读取只读镜像并添加一个读写层在顶部,如果正在运行的容器修改了现有的文件,该文件将被拷贝出...

    dogfei

扫码关注云+社区

领取腾讯云代金券