数据持久化
- 一、数据持久化简介
- 二、data volume介绍
- 三、Bind mount介绍
- 四、Docker Manager Volume介绍
一、数据持久化简介
1.Storage Driver
数据存储
CentOS7版本的docker
[root@docker ~]
...
Storage Driver: overlay2
Backing Filesystem: xfs
...
正常情况下,只有很少量的数据被写入到容器最上层的写入层,并且通过volume来写数据,然而也会遇到一些情况需要我们可以直接写入到容器的写入层,这时就需要storage driver来完成此项任务。
Docker使用一系列不同的storage driver来管理镜像层和容器层,这些storage driver不同于volume。
一个镜像是由若干镜像层组成;Dockerfile中的每条指令都会生成一个镜像层,除了最上面的一层之外,其他的都是只读的;最上一层主要是镜像运行时的一些命令;每一层只是与它之前的层有一些不同,层层堆叠在一起;创建容器时,只是在底层上添加一个新的可写层,这一层通常称为“容器层”;
Docker支持多种storage driver,有AUFS、Device Mapper、Btrfs、OverlayFS、VFS和ZFS。
它们都能实现分层的架构,同时又有各自的特性。
对于Docker用户来说,具体选择使用哪个storage driver是一个难题,主要是因为:
(1)没有哪个driver能够适应所有的场景;(2)driver本身在快速发展和迭代;
2.优先使用Linux发行版默认的storage driver
Docker安装时会根据当前系统的配置选择默认的driver。默认driver具有最好的稳定性,因为默认driver在发行版上经过了严格的测试。
Ubuntu用的AUFS,底层文件系统是extfs,各层数据存放在/var/lib/docker/aufs下。
Redhat/CentOS的默认driver是Device Mapper,SUSE则是Btrfs。
对于某些容器,直接将数据放在由storage driver维护的层中是很好的选择,比如那些无状态的应用。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建。
比如busybox,它是一个工具箱,启动busybox是为了执行诸如wget,ping之类的命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除,下次再启动新容器即可。
但对于另一类应用就不合适了,它们有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,这类容器是有状态的。这就要用到Docker的另一种存储机制:Data Volume。
二、data volume介绍
1.简介
本质上是Docker Host文件系统中的目录或文件,能够直接被mount到容器的文件系统中。
有以下特点:
(1)Data Volume是目录或文件,而非没有格式化的磁盘(块设备);(2)容器可以读写volume中的数据;(3)volume数据可以被永久的保存,即使使用它的容器已经销毁;
现在有数据层(镜像层和容器层)和volume都可以用来存放数据,具体使用时要怎样选择呢?
考虑下面几个场景:
Database软件 vs Database数据Web应用 vs 应用产生的日志数据分析软件 vs input/output数据Apache Server vs 静态HTML文件
前者放在数据层中,因为这部分内容是无状态的,应该作为镜像的一部分;后者放在Data Volume中,这是需要持久化的数据,并且应该与镜像分开存放。
关于如何设置volume的容量?
因为volume实际上是docker host文件系统的一部分,所以volume的容量取决于文件系统当前未使用的空间,目前还没有方法设置volume的容量。
三、Bind mount介绍
1.简介
持久化存储:本质上是Docker Host文件系统中的目录或文件,能够直接被Mount到容器的文件系统中。在运行容器时,可以通过-v实现。
2.示例
运行一个nginx服务,做数据持久化。
[root@docker ~]
[root@docker ~]
[root@docker html]
this is testfile.
[root@docker html]
[root@docker html]"SecondaryIPAddresses": null,"IPAddress": "172.17.0.2","IPAddress": "172.17.0.2",
[root@docker html]
this is testfile.
注意:Docker Host上需要被挂载的源文件或目录,必须是已经存在,否则当做一个目录挂载到容器中。
host中的修改确实生效了,bind mount可以让host与容器共享数据。这在管理上非常方便。
[root@docker html]
root@6e3827be6c51:/
root@6e3827be6c51:/
123
root@6e3827be6c51:/
exit
[root@docker html]
123
即使容器没有了,bind mount也还在。bind mount是host文件系统中的数据,只是借给容器使用。
默认挂载到容器内的文件,容器是有读写权限。可以在运行容器是-v后加“:ro”限制容器的写入权限。
[root@docker html]
并且还可以挂载单独的文件到容器内部,一般它的使用场景是:如果不想对整个目录进行覆盖,而只希望添加某个文件,就可以使用挂载单个文件。
[root@docker html]
mount point有很多应用场景,比如可以将源代码目录mount到容器中,在host中修改代码就能看到应用的实时效果。再比如将mysql容器的数据放在bind mount里,这样host可以方便地备份和迁移数据。
bind mount的使用直观高效,易于理解,但它也有不足的地方:bind mount需要指定host文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其它host,而该host没有要mount的数据或者数据不在相同的路径时,操作会失败。
四、Docker Manager Volume介绍
1.简介
docker manager volume与bind mount在使用上的最大区别是不需要指定mount源,指明mount point就行。
[root@docker html]
通过-v告诉docker需要一个data volume,并将其mount到/usr/share/nginx/html。
这个data volume可以在容器的配置信息中找到,执行docker inspect命令即可。
[root@docker html]
..."Mounts": [{"Type": "volume","Name": "fd8381b019f90f9e86509bf6fb3e43ccaebab09df2d1f3743dd8c63880ae9475","Source": "/var/lib/docker/volumes/fd8381b019f90f9e86509bf6fb3e43ccaebab09df2d1f3743dd8c63880ae9475/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "","RW": true,"Propagation": ""}],
...
每当容器申请mount docker manger volume时,docker都会在/var/lib/docker/volumes下生成一个目录,这个目录就是mount源。删除容器的操作,默认不会对dockerHost上的源文件操作,如果想要在删除容器时把源文件也删除,可以在删除容器时添加-v选项(一般不推荐使用这种方式,因为文件有可能被其他容器使用)。
2.手动创建volume
[root@docker html]
testweb
[root@docker html]
DRIVER VOLUME NAME
local fd8381b019f90f9e86509bf6fb3e43ccaebab09df2d1f3743dd8c63880ae9475
local testweb
[root@docker html]
[{"CreatedAt": "2020-09-08T04:18:33-04:00","Driver": "local","Labels": {},"Mountpoint": "/var/lib/docker/volumes/testweb/_data","Name": "testweb","Options": {},"Scope": "local"}
]
[root@docker html]
[root@docker html]
..."Mounts": [{"Type": "volume","Name": "testweb","Source": "/var/lib/docker/volumes/testweb/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "z","RW": true,"Propagation": ""}],
...
注意:运行容器时使用手动创建的volume,在书写格式上和bind mount一样,但查看容器的详细信息,其实它仍然使用的是docker manager volume这种方式。
3.总结
Bind Mount和Docker Manager Volume的特点
| bind mount | docker manager volume |
---|
volume位置 | 可任意指定 | /var/lib/docker/volumes/… |
有mount point影响 | 隐藏并替换为volume | 原有数据复制到volume |
是否支持单个文件 | 支持 | 不支持,只能是目录 |
权限控制 | 可设置为只读,默认为读写权限 | 无控制,均为读写权限 |
移植性 | 移植性弱,与host path绑定 | 移植性强,无需指定host目录 |
五、容器与容器的数据共享
1.简介
volume container:给其他容器提供volume存储卷的容器。并且它可以提供bind mount,也可以提供docker manager volume。
2.创建一个vc_data容器
[root@docker ~]
3.使用vc容器
[root@docker ~]
4.容器的跨主机数据共享
docker1 | docker2 | docker3 |
---|
httpd | httpd | nfs |
要求:docker1和docker2上基于httpd镜像运行2个或多个容器,保证主目录(默认访问界面内容)是一样的。
5.docker3上的操作
[root@docker3 ~]
[root@docker3 ~]
[root@docker3 ~]
/datashare *(rw,sync,no_root_squash)
[root@docker3 ~]
[root@docker3 ~]
[root@docker3 ~]
[root@docker3 ~]
[root@docker3 ~]
snow-webshare
6.docker1上的操作
[root@docker1 ~]
[root@docker1 ~]
[root@docker1 ~]
[root@docker1 ~]
[root@docker1 ~]
snow-webshare
7.docker2的操作与docker1上一样
这里先不考虑将代码写入镜像,先以这种方式,分别在docker1和docker2部署httpd服务。
docker1
[root@docker1 ~]
docker2
[root@docker2 ~]
用浏览器访问,两个WEB服务的主界面是一样。如果NFS服务器上的源文件丢失,则两个web服务都会异常。
想办法将源数据写入镜像内,再基于镜像做一个vc_data容器。在docker1和docker2上先手动创建镜像。
docker1
[root@docker1 htdocs]
FROM busybox
COPY index.html /usr/local/apache2/htdocs/index.html
VOLUME /usr/local/apache2/htdocs
[root@docker1 htdocs]
[root@docker1 htdocs]
8.总结
(1)解决容器跨主机数据共享的方案:NFS;(2)容器与容器的数据共享:基于某个容器而来(--volumes-from选项),意味着这些容器和vc容器的数据存储是一样的;