【问题标题】:docker data volume vs mounted host directorydocker 数据量 vs 挂载的主机目录
【发布时间】:2016-03-25 06:13:13
【问题描述】:

我们可以在docker中有一个数据卷:

$ docker run -v /path/to/data/in/container --name test_container debian
$ docker inspect test_container
...
Mounts": [
    {
        "Name": "fac362...80535",
        "Source": "/var/lib/docker/volumes/fac362...80535/_data",
        "Destination": "/path/to/data/in/container",
        "Driver": "local",
        "Mode": "",
        "RW": true
    }
]
...

但是,如果数据卷位于/var/lib/docker/volumes/fac362...80535/_data,与使用-v /path/to/data/in/container:/home/user/a_good_place_to_have_data 挂载的文件夹中的数据有什么不同吗?

【问题讨论】:

    标签: docker


    【解决方案1】:

    是的,这从几个角度来看是完全不同的。就像您在问题标题中所写的那样,它是关于理解为什么我们需要数据卷而不是绑定挂载到主机。

    第 1 部分 - 带有示例的基本场景

    让我们假设 2 个场景。

    案例 1:Web 服务器
    我们希望为我们的 Web 服务器提供一个可能经常更改的配置文件。
    例如:根据当前环境暴露端口。
    我们可以每次使用相关设置重建图像,或者为每个环境创建 2 个不同的图像。这两种解决方案都不是很有效。

    使用绑定挂载 Docker 将给定的源目录挂载到容器内的某个位置。
    (联合文件系统内只读层中的原始目录/文件将被简单地覆盖)。

    例如 - 绑定一个动态端口到 nginx:

    version: "3.7"
    services:
      web:
        image: nginx:alpine
        volumes:
         - type: bind #<-----Notice the type
           source: ./mysite.template
           target: /etc/nginx/conf.d/mysite.template
        ports:
         - "9090:8080"
        environment:
         - PORT=8080
        command: /bin/sh -c "envsubst < /etc/nginx/conf.d/mysite.template > 
            /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
    

    (*) 请注意,这个例子也可以使用 Volumes 来解决。

    案例 2:数据库
    Docker 容器不存储持久数据——一旦容器停止运行,任何将写入容器联合文件系统中可写层的数据都将丢失。

    但是如果我们有一个数据库在容器上运行,而容器停止了——这意味着所有的数据都将丢失?

    来拯救。
    这些是命名的文件系统树,由 Docker 为我们管理。

    例如 - 持久化 Postgres SQL 数据:

    services:    
      db:
        image: postgres:latest
        volumes:
          - "dbdata:/var/lib/postgresql/data"
        volumes:
         - type: volume #<-----Notice the type
           source: dbdata
           target: /var/lib/postgresql/data
    volumes:
      dbdata:
    

    请注意,在这种情况下,对于命名卷,源是卷的名称 (对于匿名卷,此字段被省略)。

    第 2 部分 - 比较

    主机上管理和隔离的区别

    绑定挂载存在于主机文件系统中,并由主机维护者管理。
    Docker 之外的应用程序/进程也可以修改它。

    Volumes也可以在宿主机上实现,但是Docker会替我们管理,不能在Docker外访问。

    卷是一种更广泛的解决方案

    虽然这两种解决方案都帮助我们将数据生命周期与容器分开, 通过使用Volumes,您可以获得比您的系统更多的功能和灵活性。

    通过Volumes,我们可以有效地设计我们的数据并将其与系统的其他部分分离,方法是将其存储在专用的远程位置(例如,在云中),并将其与备份等外部服务集成,监控、加密和硬件管理。

    【讨论】:

    • 感谢您提供使用示例,尤其是 docker-compose ymls
    【解决方案2】:

    虽然使用卷和绑定挂载的感觉相同(唯一的变化是目录的位置),但在行为上存在差异。

    卷与绑定安装

    • 使用绑定挂载,主机上的文件或目录被挂载到容器中。文件或目录由其在主机上的完整路径或相对路径引用。
    • 使用 Volume,在主机上在 Docker 的存储目录中创建一个新目录,Docker 管理该目录的内容。

    相对于绑定安装的卷优势:

    • 卷比绑定挂载更容易备份或迁移。
    • 您可以使用 Docker CLI 命令或 Docker API 管理卷。
    • 卷可在 Linux 和 Windows 容器上运行。
    • 可以在多个容器之间更安全地共享卷。
    • 卷驱动程序允许您将卷存储在远程主机或云提供商上、加密卷的内容或添加其他功能。
    • 新卷的内容可以由容器预先填充。

    编辑(2019 年 9 月 9 日):
    根据@Sebi2020 评论,绑定挂载更容易备份。 Docker 不提供任何命令来备份卷。您必须使用带有绑定挂载的临时容器来创建备份。

    音量

    由 Docker 创建和管理。您可以显式创建卷 使用 docker volume create 命令,或者 Docker 可以创建一个卷 在容器或服务创建期间。

    创建卷时,它会存储在 码头工人主机。当您将卷安装到容器中时,这 目录是挂载到容器中的内容。这类似于 绑定挂载的工作方式,除了卷由 Docker 并与主机的核心功能隔离 机器。

    一个给定的卷可以同时挂载到多个容器中。 当没有正在运行的容器正在使用一个卷时,该卷仍然是 可用于 Docker 并且不会自动删除。你可以删除 使用 docker volume prune 未使用的卷。

    当您挂载一个卷时,它可能是命名的或匿名的。匿名的 卷在首次挂载时没有明确的名称 放入容器中,因此 Docker 给它们一个随机名称,即 保证在给定的 Docker 主机中是唯一的。除了名字, 命名卷和匿名卷的行为方式相同。

    卷还支持使用卷驱动程序,它允许您 将您的数据存储在远程主机或云提供商等 可能性。

    绑定坐骑

    从 Docker 早期就可用。绑定坐骑有限制 与卷相比的功能。当您使用绑定挂载时,文件 或主机上的目录挂载到容器中。文件 或目录由其在主机上的完整路径引用。这 文件或目录不需要已经存在于 Docker 主机上。 如果它尚不存在,则按需创建。绑定坐骑非常 高性能,但它们依赖于主机的文件系统 可用的特定目录结构。如果您正在开发新的 Docker 应用程序,请考虑改用命名卷。你不能 使用 Docker CLI 命令直接管理绑定挂载。

    还有tmpfs mounts
    tmpfs 挂载

    tmpfs 挂载不会持久保存在磁盘上,无论是在 Docker 主机上还是 一个容器内。它可以在生命周期内被容器使用 容器,存储非持久状态或敏感 信息。例如,在内部,swarm 服务使用 tmpfs 挂载 将秘密挂载到服务的容器中。

    参考:
    https://docs.docker.com/storage/

    【讨论】:

    • 绑定挂载更容易备份。遗憾的是,Docker 没有提供任何备份卷的命令。您必须使用带有绑定挂载的临时容器来创建备份
    • 我刚想问为什么卷更容易备份,但@Sebi2020 先问了。我认为编辑答案是公平的。
    • 我第二个@Sebi2020。当我在寻找备份卷的方法时来到这里,发现备份起来不必要地复杂(不像我直觉的想法)。绑定坐骑更容易备份。
    • 我来这里也是为了找同样的东西。我确实认为卷挂载的一个主要缺点是,对于旧版本的 docker,当我想升级它时,我必须先删除当前版本。这也删除了所有 docker 数据(图像、容器、卷)。我不确定升级后不会再发生这种情况。我同意绑定挂载更容易备份。您准确地知道数据在哪里。如果 docker 文档能详细说明卷相对于绑定挂载的所谓优势,那就太好了。
    • 就 windows docker 卷而言:在 windows docker 主机上,有很多关于卷的问题。所以这也不是优势。
    【解决方案3】:

    主机目录和数据卷的区别在于,Docker 通过将其放入$DOCKER-DATA-DIR/volumes 目录并附加对其的引用(名称或随机生成的 ID)来管理后者。那就是你得到一点方便。

    主机目录和数据卷都是主机上的目录。两者都依赖于主机。您不能在 Dockerfile 中引用它们中的任何一个; VOLUME 指令会在您每次启动新容器并且无法引用现有卷时创建一个新的无名(具有随机生成的 id)卷。

    * $DOCKER-DATA-DIR 在此处为 /var/lib/docker,除非您更改了默认值。

    【讨论】:

      【解决方案4】:

      这与使用 -v /path/to/data/in/container:/home/user/a_good_place_to_have_data 挂载文件夹中的数据有什么不同吗?

      这是因为,如“Mount a host directory as a data volume”中所述

      主机目录本质上是依赖于主机的。出于这个原因,您不能从 Dockerfile 挂载主机目录,因为构建的图像应该是可移植的。主机目录不会在所有潜在主机上都可用。

      如果您想要在容器之间共享一些持久性数据,或者想从非持久性容器中使用,最好创建一个命名的数据卷容器,然后从其中挂载数据。

      您可以结合使用这两种方法:

       docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
      

      在这里,我们启动了一个新容器并从 dbdata 容器装载了卷。
      然后,我们将本地主机目录挂载为 /backup
      最后,我们传递了一个命令,该命令使用tardbdata 卷的内容备份到backup.tar 目录中的backup.tar 文件中。当命令完成并且容器停止时,我们将得到 dbdata 卷的备份。

      【讨论】:

      • 您能否澄清一下 Docker 文档中关于主机目录依赖于主机的含义?文件权限是否意味着因为在某些情况下,当您将容器和挂载目录移动到另一台主机时,在另一台主机上复制它们会很痛苦?命名卷和挂载目录之间还有什么区别?我知道,尤其是在多个容器之间共享持久数据是数据卷容器的一个用例。但是对于仅与单个容器相关的持久数据,我有点迷失了:-)。
      • @PermaFrost host-dependent 意味着您不能使用来自主机的卷路径编写 Dockerfile,因为该 Dockerfile 可以在任何主机上构建,每个主机都有自己的特征:在一台主机上有效的路径可能在另一个上不可用。这就是为什么挂载主机文件夹是 runtime 操作(docker run),而不是编译时操作(docker build)
      • @PermaFrost 命名卷是独立于主机的,并且是持久的。即使只有一个容器,这意味着我可以在任何主机上导出和恢复命名卷。见madcoda.com/2016/03/docker-named-volume-explained
      • 感谢您的解释和链接,我会看看那篇文章! :)
      • @VonC:您能澄清一下在主机系统上创建 lvm 并安装在 docker 上与使用 docker 插件创建 lvm 并安装它有什么区别吗?应该优先选择一个吗?
      猜你喜欢
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 1970-01-01
      • 2014-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多