docker数据持久化的相关介绍

数据持久化

  • 一、数据持久化简介
    • 二、data volume介绍
      • 三、Bind mount介绍
        • 四、Docker Manager Volume介绍
          • 五、容器与容器的数据共享

一、数据持久化简介

docker数据持久化的相关介绍_第1张图片
1.Storage Driver
数据存储
CentOS7版本的docker

[root@docker ~]# docker info
...
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 ~]# mkdir html
[root@docker ~]# cd html
[root@docker html]# vim index.html
this is testfile.
[root@docker html]# docker run -itd --name testweb -p 80 --restart always -v /root/html:/usr/share/nginx/html nginx
[root@docker html]# docker inspect testweb | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
[root@docker html]# curl 172.17.0.2
this is testfile.

注意:Docker Host上需要被挂载的源文件或目录,必须是已经存在,否则当做一个目录挂载到容器中。
host中的修改确实生效了,bind mount可以让host与容器共享数据。这在管理上非常方便。

[root@docker html]# docker exec -it testweb bash
root@6e3827be6c51:/# echo 123 > /usr/share/nginx/html/index.html
root@6e3827be6c51:/# cat /usr/share/nginx/html/index.html
123
root@6e3827be6c51:/# exit
exit
[root@docker html]# cat index.html
123

即使容器没有了,bind mount也还在。bind mount是host文件系统中的数据,只是借给容器使用。
默认挂载到容器内的文件,容器是有读写权限。可以在运行容器是-v后加“:ro”限制容器的写入权限。

[root@docker html]# docker run -itd --name testweb -p 80 --restart always -v /root/html:/usr/share/nginx/html:ro nginx

并且还可以挂载单独的文件到容器内部,一般它的使用场景是:如果不想对整个目录进行覆盖,而只希望添加某个文件,就可以使用挂载单个文件。

[root@docker html]# docker run -itd --name testweb -p 80 --restart always -v /root/html/index.html:/usr/share/nginx/html/index.html:ro nginx

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]# docker run -itd --name t1 -p 80 --restart always -v /usr/share/nginx/html nginx

通过-v告诉docker需要一个data volume,并将其mount到/usr/share/nginx/html。
这个data volume可以在容器的配置信息中找到,执行docker inspect命令即可。

[root@docker html]# docker inspect t1
...
        "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]# docker volume create testweb
testweb
[root@docker html]# docker volume ls
DRIVER              VOLUME NAME
local               fd8381b019f90f9e86509bf6fb3e43ccaebab09df2d1f3743dd8c63880ae9475
local               testweb
[root@docker html]# docker volume inspect testweb
[
    {
        "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]# docker run -itd --name t2 -p 80 --restart always -v testweb:/usr/share/nginx/html nginx
[root@docker html]# docker inspect t2
...
        "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 ~]# docker create --name vc_data -v ~/html:/usr/share/nginx/html -v /other/useful/tools busybox

3.使用vc容器

[root@docker ~]# docker run -itd --name t3 -P --volumes-from vc_data nginx

4.容器的跨主机数据共享

docker1 docker2 docker3
httpd httpd nfs

要求:docker1和docker2上基于httpd镜像运行2个或多个容器,保证主目录(默认访问界面内容)是一样的。
5.docker3上的操作

[root@docker3 ~]# yum -y install nfs-utils
[root@docker3 ~]# mkdir /datashare
[root@docker3 ~]# vim /etc/exports
/datashare *(rw,sync,no_root_squash)
[root@docker3 ~]# systemctl start rpcbind
[root@docker3 ~]# systemctl enable rpcbind
[root@docker3 ~]# systemctl start nfs-server
[root@docker3 ~]# systemctl enable nfs-server
[root@docker3 ~]# vim /datashare/index.html
snow-webshare

6.docker1上的操作

[root@docker1 ~]# yum -y install nfs-utils
[root@docker1 ~]# showmount -e 192.168.229.50
[root@docker1 ~]# mkdir /htdocs
[root@docker1 ~]# mount -t nfs 192.168.229.50:/datashare /htdocs
[root@docker1 ~]# cat /htdocs/index.html
snow-webshare

7.docker2的操作与docker1上一样
这里先不考虑将代码写入镜像,先以这种方式,分别在docker1和docker2部署httpd服务。
docker1

[root@docker1 ~]# docker run -itd --name snow-web1 -P -v /htdocs:/usr/local/apache2/htdocs httpd:latest

docker2

[root@docker2 ~]# docker run -itd --name snow-web2 -P -v /htdocs:/usr/local/apache2/htdocs httpd:latest

用浏览器访问,两个WEB服务的主界面是一样。如果NFS服务器上的源文件丢失,则两个web服务都会异常。
想办法将源数据写入镜像内,再基于镜像做一个vc_data容器。在docker1和docker2上先手动创建镜像。
docker1

[root@docker1 htdocs]# vim Dockerfile
FROM busybox
COPY index.html /usr/local/apache2/htdocs/index.html
VOLUME /usr/local/apache2/htdocs
[root@docker1 htdocs]# docker build -t back_data .
[root@docker1 htdocs]# docker create --name back_container1 back_data

8.总结

(1)解决容器跨主机数据共享的方案:NFS;

(2)容器与容器的数据共享:基于某个容器而来(--volumes-from选项),意味着这些容器和vc容器的数据存储是一样的;

你可能感兴趣的:(docker,docker,数据持久化,数据卷,volume)