TOC

存储卷

    对于Docker来讲,容器运行的底层引擎,在组织和运行其容器时,每个容器内只运行一个程序及其子程序,对于这个容器来说,启动是依赖于底层联合挂载启动而成,它底层能够实现分层构建以及联合挂载镜像的文件系统,包含AUFS以及DEVMAPPER等,并且只有在最上层是读写的,其他层都是只读的。所有在容器内部执行的数据修改操作,事实上都保存在最上层之上的,对于下层类型的操作,假如说要删除一个文件,那么就需要使用写时复制的机制来实现;
写时复制
    Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层;
    如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层中复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,标记为已删除,此即为“写时复制”机制;

存储卷(Volume)的实现
    所谓存储卷,在宿主机当中创建一个目录,而后把这个目录直接与容器内部文件系统之上的某一目录,建立绑定关系,就像挂载一样,可以把容器的内部的/data/web挂载为宿主机下面的/container/data/web,这样我们容器内的进程向/data/web这个目录写数据的时候,是直接写到/container/data/web这个目录下面的,所以这样就使得我们容器内的进程,在实现数据保存时,能绕过容器内部文件系统的限制,从而与宿主机的文件系统建立关联关系,使得我们可以在宿主机和容器内共享数据,同样的,可以让容器直接访问宿主机的内容也可以让宿主机直接向容器供给内容。
    对于我们的mount这个名称空间本来是隔离的,但是通过数据卷的功能能够实现在容器内的某个子目录上和宿主机建立绑定关系,从而使得在多个容器之间的文件系统的某个子目录上不再是隔离的,并且能够实现数据共享的效果。而在宿主机上的这个目录,就是和容器内文件系统建立绑定关系的一个目录,相对于容器来讲我们称之为卷(Volume)。
    如果容器内的进程的所有有效数据都是保存在存储卷,从而脱离了容器自身的文件系统以后,那它带来的好处就是,当容器关闭甚至删除的时候我们都不用担心数据会丢失,只要不删除与之绑定的了在宿主机存储的这个一个目录就可以,因此我们就能够实现数据脱离容器生命周期的数据持久。
    进程本身不保存任何数据,数据应该都在进程之外的文件系统之上,我们的docker容器也一样,docker run有一个参数--rm这个命令的意义就是容器关闭之后删除所有有关容器的信息,刚好在运行容器产生的数据也会随之删除,所以Volume会是一个很好的数据持久解决方案,容器停止之后即便容器被删除,我们的数据还依然存在,那么此时我们只需要run一个一样的容器并且指定之前的Volume即可。
    那么这就有一个问题,假如我们的容器删除了之后,数据依然存在,我们可以给予原有镜像创建的新的容器,那么我怎么能够和原来被删除的那一个容器创建得一模一样,因为不一样,即使我们的数据存在,也可能会出现各种兼容性的问题,就必须我们的数据目录挂载了三个,但是后来我们忘记了,在创建新的容器的时候,我们只挂在了一个导致容器启动失败,那么就是我们编排工具的重要性了,将容器的创建到运行所有的轨迹记录下次,下次基于这个编排文件进行容器创建。
    那么就说明我们的容器可以在单台机器上随意创建与销毁,这样没有什么问题,那么我们如果这台宿主机因为某种原因导致系统崩溃,我们该如何解决呢。Volume还带给我们另一个好处,我们有了编排文件,有了数据,假设我们的Volume数据存储在NFS等分布式文件系统之上,我们就可以实现多主机容器编排或者说实现应用程序水平扩展,有两台宿主机,每台宿主机都挂载我们的NFS共享文件,这个共享文件里面有我们容器内部应用程序运行所需的数据,那么就说明我们可以在多台主机之上基于一套数据来运行应用程序实现多容器之间的协同工作,实现全局调度,这种计算我们称之为云计算。这样的话容器就不限于启动于哪台主机之上了。
    对于Docker来讲,它的存储卷,默认情况下是使用其所在的宿主机之上的本地文件系统目录,容器所使用的目录就是关联到这个宿主机磁盘上的一个目录而已,也就意味着这个容器在当前的一个宿主机之上停止删除再创建,只要关联到宿主机磁盘的数据还存在,我们就可以基于这个数据在这台宿主机之上再创建一个相同的容器,并加载该数据,但是这个数据就不能共享给其他的用户了,这是docker本身没有解决问题。所以docker默认存储卷就是docker Host本地。
Docker默认数据存储方式
关闭并重启容器,其数据不受影响,但删除Docker容器,则其更改将会全部丢失;
存储于联合文件系统中,不易于宿主机访问;
容器间数据共享不便;
删除容器其数据会丢失;
数据卷
卷是容器上的一个或多个目录,此类目录可绕过联合联合文件系统,与宿主机上的某个目录绑定关系;

Data Volumes

    在docker之上,如果我们要用到存储卷,我们不必要手动去创建,当我们需要用到存储卷的时候,只需要在启动或创建docker容器的时候,在容器初始化时自动被创建,启动容器之后自动建立绑定关联关系,所以说存储卷是独立于容器的生命周期实现数据持久化,因此默认情况下,删除容器时不会删除数据。
    有了存储卷以后,docker容器内部的程序,在实现读写数据时,如果写在根上,依然保存在联合挂载文件系统之中,如果写在卷的目录上,那就写到宿主机的关联目录之上。

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

Bind mount volume
    绑定挂载卷:在宿主机上的路径,需要人工制定一个特定的路径,在容器内的路径也需要指定一个特定的路径,让二者两个已知路径,建立关联关系;
    管理命令:[root@node1 ~]# docker run -it --name c1 -v /dockerHost/data:/container/data busybox
    查看信息:[root@node1 ~]# docker inspect -f {{.Mounts}} c1
Docker-managerd volume
    docker管理的卷:我们只需要在容器内指定容器内的挂载点是什么,而被绑定的是宿主机的那个目录下的目录无需管理,容器引擎会自定创建一个空目录,自动与容器内部的挂载点建立关联关系,这种卷的缺点是我们无法指定到底要挂载哪个目录,但是一旦把容器删除了这个数据就会丢失;
    管理命令:[root@node1 ~]# docker run -it --name c2 -v /container/data busybox
    查看信息:[root@node1 ~]# docker inspect -f {{.Mounts}} c2
多容器共享volume
    如果用户需要在容器之间共享一些持续更新的数据,最简单的方式就是使用数据卷容器,数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载的一个容器,并且可以多次使用--volumes-from参数来从多个容器挂载多个数据卷;
    如果删除了挂载的容器,数据卷并不会自动被删除,如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显示使用docker rm -v命令来指定同事删除关联的容器;
# 第一个容器
[root@node1 ~]# docker run -it --rm --name c1 -v /data/storage1:/storage1 -v /data/storage2:/storage2 -v /data busybox /bin/sh
# 第二个容器,创建的时候指定--volumes-from为第一个容器的名字
[root@node1 ~]# docker run -it --rm --name c2 --volumes-from c1 busybox /bin/sh

附件列表

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注