参考:https://docs.docker.com/storage/
默认情况下,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目录中的原始内容将被遮蔽,当解决挂载时则自动恢复。