Docker的持久化存储和数据共享

docker持久化数据的方案

默认情况下,container内部新创建文件或者修改文件,结果会保存在container的可读写层中,这意味着:

当container消失时,与container一体的可读写层也一并消失,数据并没有持久化。并且,当一个container需要其它container中可读写层的数据时,取出操作非常困难。

container的可读写层与宿主机的文件系统紧密结合,很难将它从一台宿主机迁移到其它宿主机。

container的可读写层,低下需要一个实现联合文件系统的storage driver,与直接在宿主机文件系统中读写数据相比效率要低。

如果打算将数据持久化在宿主机的文件系统中,docker提供至少两个选项:volumes与bind mounts,如果docker运行在Linux操作系统中,还可以使用tmpfs .mount。

选择正确的mount类型

无论你选择那种mount类型,从container内部看没有区别,它们都是目录或者文件。数据都是寄存在宿主机上,只不过具体位置有所区别,如下图:

 bind mount:将宿主机中的文件、目录mount到容器上。其上的数据可以被宿主机读写,可以被mount它的所有容器读写。

volume:volume由docker管理,比如创建、删除什么的。默认情况下,volume的存储空间来自于宿主机文件系统中的某个目录,如/var/lib/docker/volumes/,docker系统这外的程序不应该修改其中的数据。volume是官方推荐的持久化方案。

tmpfs mount:tmpfs类型文件与普通文件的区别是只存在于宿主机内存中,不会持久化。

有关挂载类型的更多详细信息

volumes:由docker负责创建、管理。用户可以显式的调用命令docker volume create创建volume,也可以通过container、service的启动隐式创建。

默认情况下创建的volume本质上还是宿主机文件系统中的一个目录,与普通目录无本质区别。一个volume可以同时供多个container使用,如果没有container使用volume,它不会自动删除,用户需运行docker volume prune明确删除它。

如果用户显式创建volume则需要给它指定一个名称,如果是隐式创建volume则docker会自动为它分配一个在宿主机范围内唯一的名字。

通过使用第三方提供的volume driver,用户可以将数据持久到远程主机或者云存储中,也就是说存储空间可以不由宿主机提供。

bind mount:本质上是宿主机、container之间共享宿主机文件系统。这种持久化方法更导致container与宿主机的耦合过于紧密,所以不推荐使用。

tmpfs mount:有特定的应用场景。比如docker可将用户名与密码等敏感数据保存在某个数据库中,当启动需要访问这些敏感数据的container或者service时,docker会在宿主机上创建一个tmpfs,然后将敏感数据从数据库读出写到tmpfs中,再将tmpfs mount到container中,安样能保证数据安全。当容器停止运行时,则相应的tmpfs也从系统中删除。

在创建容器时,bind mount与volume两种方式使用的选项相同,都是-v或者--volume,而实际上在语法上有明显的区别。tmpfs通过--tmpfs选项实现。总之在旧版本的docker中,这一块的语法有点混乱,从docker17.0.6开始,推荐使用新选项--mount,它要清晰的多。

volume适用场景

  • 多个容器这间共享数据
  • 宿主机不保证存在固定的目录结构
  • 持久化数据到远程主机或者云存储而非本地
  • 需要备份、迁移、合并数据时。停止container,将volume整体复制,用于备份、迁移、合并等。

bind mount适用场景

container共享宿主机配置文件。比如docker会将宿主机文件/etc/resov.conf文件bind mount到容器上,两者会使用相同的DNS服务器。

开发环境中宿主机与container之间共享源代码、构建构件等。比如将整个build过程container化,将宿主机上的源代码文件夹bind mount到build container中。修改代码后,运行build container的build命令,build container则将build结构写入另一个bind mount的文件夹中。

一些监控类container,通过读取宿主机固定文件中的数据实现监控等。

使用bind mount与volume的提示

如果将空volume挂载到container上的某个目录,此目录下原来的文件与子目录会复制到空volume中。

如果bind mount一个非空目录或者文件,或者非空volume,则container目录中的原始内容将被遮蔽,当解决挂载时则自动恢复。

eg:1 

创建mysql1容器,在启动的时候给volume设置别名

[root@docker ~]# sudo docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
[root@docker ~]# docker volume ls
DRIVER              VOLUME NAME
local               mysql
[root@docker ~]# docker volume inspect mysql
[
    {
        "CreatedAt": "2018-06-07T09:30:33Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/mysql/_data",
        "Name": "mysql",
        "Options": null,
        "Scope": "local"
    }
]
[root@docker ~]# 

这种方式volume中的数据并不会因为容器的删除而消失,实现了数据持久化的目标。但是这种方式的volume需要在Dockerfile中使用VOLUME来预先指定容器中的数据存放路径。

Bind Mounting

Bind Mounting跟上面的方式不一样,可以动态的指定容器内文件存放路径和宿主机上的数据库卷目录。

采用Bind Mounting的方式实现volume的话,容器内外的数据是同步的,只需要修改一个地方,容器内或者容器外都会同步修改,非常的方便快捷。

  采用Bind Mounting的方式,将docker作为开发环境可以使我们的开发环境和生产环境保持一致,这也是实现DevOps的第一步。(很多开发使用的都是Windows的系统,但是服务器一般都是Linux的,无法保持环境的一致性,影响开发效率。)

默认情况下,container内部新创建文件或者修改文件,结果会保存在container的可读写层中,这意味着:
当container消失时,与container一体的可读写层也一并消失,数据并没有持久化。并且,当一个container需要其它container中可读写层的数据时,取出操作非常困难。container的可读写层与宿主机的文件系统紧密结合,很难将它从一台宿主机迁移到其它宿主机。container的可读写层,低下需要一个实现联合文件系统的storage driver,与直接在宿主机文件系统中读写数据相比效率要低。如果打算将数据持久化在宿主机的文件系统中,docker提供至少两个选项:volumes与bind mounts,如果docker运行在Linux操作系统中,还可以使用tmpfs .mount。————————————————版权声明:本文为CSDN博主「五星上炕」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/dkfajsldfsdfsd/article/details/88789360

原文地址:https://www.cnblogs.com/sunlong88/p/15020961.html