Docker存储卷

docker镜像由多个只读层叠加完成,启动容器时,docker会加载只读镜像层并在镜像栈顶部添加一个读写层

如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制机制”

Docker存储卷_第1张图片

描述:如果一个文件在最底层是可见的,如果在layer1上标记为删除,最高的层是用户看到的Layer2的层,在layer0上的文件,在layer2上可以删除,但是只是标记删除,用户是不可见的,总之在到达最顶层之前,把它标记来删除,对于最上层的用户是不可见的,当标记一删除,只有用户在最上层建一个同名一样的文件,才是可见的。

为什么要使用存储卷

              存储在联合文件系统中,不易于宿主机访问;

              容器之间数据共享不便

              删除容器其数据会丢失 

  • 对于这类的操作,修改删除等,一般效率非常低,如果对一于I/O要求比较高的应用,如redis在实现持化存储时,是在底层存储时的性能要求比较高。
  •  假设底层运行一个存储库mysql,mysql本来对于I/O的要求就比较高,如果mysql又是运行在容器中自己的文件系统之上时,也就是容器在停止时,就意味着删除,其实现数据存取时效率比较低,要避免这个限制要使用存储卷来实现。
  • 容器存在的问题:

什么是存储卷

    “卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统与宿主机上的某个目录“绑定(关联)”;

  类似于挂载一样,宿主机的/data/web目录与容器中的/container/data/web目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器供集内容,两者是同步的

  mount名称空间本来是隔离的,可以让两个本来是隔离的文件系统,在某个子路径上建立一定程度的绑定关系,从而使得在两个容器之间的文件系统的某个子路径上不再是隔离的,实现一定程度上共享的效果。

  在宿主机上能够被共享的目录(可以是文件)就被称为volume。

存储卷的好处

      如果容器内所有进程的有效数据都是保存在存储卷上的,从而脱离了容器自身的文件系统,那么它的好处就是,当容器关闭甚至删除时我们都不用担心数据丢失了,只要删除与之绑定的宿主机上的存储目录即可,因此我们就可以实现脱离容器的生命周期的数据持久。即使我们删除了容器,后面再次重建容器的时候,如果我们能让它关联到同一个存储卷上,虽然容器变了,但是数据还是原来的数据。特别类似于进程的运行逻辑,进程本身不保存任何的数据,数据都在进程之外的文件系统上,或者是专业的存储服务之上,所以进程每次停止,只是保存程序文件,对于容器也是一样;容器就是一个有生命周期的动态对象来使用,容器关闭就是容器删除的时候,但是它底层的镜像文件还是存在的,可以基于镜像再重新启动容器。

     容器的启动和进程还不太一样,容器的启动需要很多选项,而我们不一定每次都能记得,所以上一次我们启动的时候容器被关联到哪些卷上,我们下次启动的时候很可能会忘记,那这样就很难复现一个一模一样的容器,因此我们最好能用一个文件保存下来是如何启动并创建容器的相关配置,这一般都是容器编排工具的作用

     此外它还有另一个好处,在了解这个好处之前我们先看看什么是NFS?

    

     找一个NFS服务器,共享一个目录,然后将几个docker宿主机挂载到NFS服务器上,这样对于宿主机来说就好像在本地目录一样。在docker宿主机上启动一个容器,将这个容器的目录与宿主机上的某个目录进行关联,而这个目录又是NFS之上的子路径,那么启动容器并保存数据到宿主机上,实际上就是保存到NFS之上了。

    这样的好处就是,删除容器之后,当下次启动的时候就不一定非启动在当时的那台主机了,它可以启动在任意的主机之上。这样就可以实现集群范围内容器的调度和运行了。当再分配存储、计算资源时,就不会再局限于单机之上,可以在集群范围内建立起来,基本各种docker的编排工具都能实现此功能,但是会严重依赖于共享存储的使用,比如NFS。

Docker存储卷_第2张图片

存储卷分类:

Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上位置有所不同;

  • Bind mount volume(绑定挂载卷):在宿主机上的路径要人工的指定一个特定的路径在容器中也需要指定一个特定的路径,然后让这两个已知的路径建立关联关系
  • Docker-managed volume(docker管理卷): 只需要在容器内指定容器的挂载点是什么,而被绑定宿主机下的那个目录,是由容器引擎daemon自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合;

在容器中使用Volumes

为docker run命令使用-v选项即可使用Volume

Docker-managed volume(docker管理卷):

      # docker run -it --name b2 -v  /data  busybox

Bind mount volume(绑定挂载卷):

     # docker run -it --name b2  -v  HOSTDIR:VOLUMEDIR busybox

我们先测试docker管理卷:

Docker存储卷_第3张图片

那这个目录属于哪个路径,与哪个存储卷有关联关系,我们去探测一下这个容器的详细信息。

docker inspect b2

Docker存储卷_第4张图片

Volumes到底与谁建立了关联关系,我们可以在Mounts中看到

Docker存储卷_第5张图片

 我们可以切换到宿主机上的关联路径

cd /var/lib/docker/volumes/b7cc25c3450a1d088b72adc95954a56e8d1c6ccfa76ab40b75abc149a3daf317/_data

然后在容器中我们刚才创建的目录中查看一下,有没有我们创建的文件

Docker存储卷_第6张图片

这样就非常方便的实现了容器与宿主机之间共享数据。而且这个路径也是由宿主机自己自动生成的。

接下来测试绑定挂载卷:

Docker存储卷_第7张图片

Docker存储卷_第8张图片

同样的我们在宿主机上查看详细情况

docker inspect b2

Docker存储卷_第9张图片

我们在使用docker inspect查看具体信息的时候可以使用双大括号进行过滤。

外层的大括号是引用模板,内层的括号代表json格式的数组,key值前面的黑点代表根目录

-f  代表查看的时候引用go模板

Docker存储卷_第10张图片

实际上我们不仅可以做到让一个容器与宿主机共享目录,我们还可以让多个容器与一个宿主机共享同一个目录。

这样就实现了容器之间的文件共享。

我们启动一个容器指定存储卷需要使用-v指定,但是如果我们想要使用和上一个容器相同的存储卷也要指定吗?

其实我们可以复制上一个容器的存储卷配置

复制使用其他容器的存储卷,为docker run命令使用 --volumns-from选项

docker run -it --name b1 -v /docker/volumes/v1:/data busybox

docker run -it --name b2 --volumes-from b1 busybox

 

你可能感兴趣的:(docker)