文章目录:
1.容器数据卷是什么?
先来看看Docker的理念:
* 将运用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的。
* 容器之间希望有可能共享数据。Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。
为了能保存数据在docker中我们使用卷。(一句话:就是想在docker和宿主机之间实现数据共享,数据持久化。类似于redis中的RDB、AOF)
2.容器数据卷能干嘛?
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。(实现容器的持久化、容器之间的继承 + 数据共享)
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接生效
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
3.容器内添加数据卷
在容器内添加数据卷有两种方式:①直接使用命令添加;②使用DockerFile添加。
3.1 直接使用命令添加
docker run -it -v/宿主机绝对路径目录:/容器内目录镜像名
此时,宿主机上的myDataVolume和docker特定容器中的dataVolumeContainer,这两个目录就实现了数据共享。
在docker中的这个共享目录就可以称为容器卷目录。
可以使用docker inspect 容器ID,查看容器内部细节,可以看到这两个目录已经绑定成功,并且RW(read/write,即读写权限)为true。
下面,首先在宿主机的 myDataVolume 目录下touch创建一个文件host.txt,然后到docker的centos容器中的 dataVolumeContainer 目录下,ls看到host.txt已经存在了,这说明读权限是共享的。之后vim host.txt向其中写内容,然后touch创建container.txt。再回到宿主机中查看,一样可以cat读取到目录中的文件,当然vim也一样可以,这里忘记写这个命令了。
总之,此时就通过命令创建容器数据卷,进而实现了宿主机与docker容器之间的数据持久化与数据共享。
下面,我们将docker中的容器停止退出(exit是容器停止退出,ctrl + P + Q是容器不停止退出),再看看是否依然是数据共享。
首先exit,然后docker ps可以看到此时已经没有容器实例运行了。
然后到宿主机中,touch创建一个文件,然后vim这个文件向其中写内容。
上面在宿主机中已经添加并且向文件中写了内容,这里先使用docker ps -l查看最近创建运行的容器(也就是刚刚停止的那个centos),然后docker start再次进入这个centos容器实例中,可以看到在共享目录下仍然存在刚刚宿主机中添加的host.txt。
结论:容器停止退出之后,宿主机仍然和docker容器保持着数据持久化、数据共享。
下面这张截图写反了,应该先执行第二步,再执行第一步。
首先这个命令与上面的docker run的区别就是,它的后面多了个 :ro,这个ro的意思就是 read only 只读,也就是说此时docker容器中那个共享数据的目录只有读权限,将不再享有写权限了。
这里执行完docker run,先在宿主机中vim host.txt,然后cat可以读取到。回到docker的centos容器实例中,cat依然可以读取到,但是想要touch创建就不行了,因为ro限制你的docker容器只有读权限,没有写权限了。
通过上面的 :ro,只读权限,也可以使用docker inspect 容器ID,查看此时容器内部的细节,RW已经为false了,也就是双方不再共享读取权限。
3.2 使用DockerFile添加
上面说完了使用命令添加容器数据卷的方法,这里再来说一下使用DockerFile添加。
出于可移植和分享的考虑,用上面的docker run -it -v 主机目录:容器目录这种方法不能够直接在Dockerfile中实现。由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。
首先在宿主机根目录下创建一个mydocker用作测试,在mydocker目录下vim一个Dockerfile,并添加下面第一个红色框中的内容。
然后执行docker build,该命令是从特定的Dockerfile中创建一个新的镜像。执行完毕,可以在最后看到该镜像的ID。
docker images就可以看到我们刚刚build的那个新镜像了,此时直接run,使这个新镜像生产一个容器实例来运行。
在上面使用命令添加的时候,我们可以显式的指定出宿主机和docker容器中具体的共享目录。
而此时使用Dockerfile添加,并没有显式的指定出共享目录,那么就使用docker inspect 容器ID,查看该容器的内部细节,进而看到双方的共享目录。
得到宿主机与docker容器各自的共享目录之后,分别cd进入这两个目录,在其中touch创建文件,可以看到同样能够读取到,即实现了数据持久化、数据共享。
在docker中的这个共享目录就可以称为容器卷目录。
4.数据卷容器
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器。
下面测试仍然以Dockerfile文件build的那个镜像为模板,生产三个容器实例运行。
首先以szh/centos为镜像模板,run生产一个dc01容器实例运行,然后进入到dataVolumeContainer2这个容器卷目录,touch一个dc01_add.txt文件。
之后ctrl + P + Q,当前dc01容器不停止退出。
再次以szh/centos为镜像模板(本是同根生),run生产一个dc02容器实例,与dc01不同的是:此时的dc02是从dc01这个容器中挂在了数据卷。
可以理解为redis中的主从复制,或者是Java中的继承。
dc02容器实例运行之后,也进入到dataVolumeContainer2这个容器卷目录中,touch一个dc02_add.txt文件。
之后ctrl + P + Q,当前dc02容器不停止退出。
下面是dc03,和上面的dc02完全一样,我就不再多说了。
由于我们上面的步骤已经以同一个镜像模板生产了3个容器实例来运行,并且都ctrl + P + Q,这三个容器还未停止运行。
此时我们docker attach再次进入dc01这个容器的数据卷目录下,ls可以看到刚刚在dc02、dc03的数据卷目录中创建的那个文件,此时在dc01中也可以读取到。
也即实现了dc01、dc02、dc03三个容器之间的数据持久化、数据共享,这就是数据卷容器。
下面,我docker rm -f将dc01这个容器删除,docker ps可以看到正在运行的容器中已经没有dc01了。
然后我们docker attach进入dc02的数据卷目录中,touch一个dc02_update.txt,然后再进入docker attach进入dc03的数据卷目录中,可以看到刚刚在dc02中创建的那个dc02_update.txt文件,在dc03的数据卷目录中,也读取到了
结论:数据卷容器之间信息的传递,数据卷的生命周期会一直持续到没有容器使用它为止。
也就是上面删除了dc01,但是还有dc02在使用数据卷目录,所以仍然可以和dc03实现数据持久化、数据共享。