我前面介绍容器命令的时候,最后说过一个cp命令,可以把容器和宿主机之间的文件互相拷贝,保证数据的持久化,但是这种持久化偏向于比较独立完整的文件,大家有没有想过如果遇到成体系的数据保存,比如我整个数据库的落盘,这些我直接cp命令,可能会出现问题的文件,那怎么办?就算不出现问题,一个数据库的数据就靠cp命令,现实吗?此时就用到了数据卷。或者说它可以让容器自己把数据在生成的同时持久化到宿主机上。同样的既然数据可以从容器直接进入宿主机,同理其他容器之间也可以通过这样的机制共享某个数据。
总结的说,数据卷就是让某个目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
因此数据卷的特点如下:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接生效
3;数据卷中的更改不会包含在镜像的更新中,就是不会被commit打包进去,因为它也属于运行数据的一种,上一篇知识点的用例也体现了,commit不受运行数据的影响
4:数据卷的生命周期一直持续到没有容器使用它为止,当没有容器使用时,也不会消失,只是再次的成为了宿主机的一个普通路径
5:容器对数据卷的任何操作,都只是一个参数者而已,数据本身还属于数据卷本身所有,这一点很重要,不要以为某个容器和数据卷断开后该容器操作的数据会消失
容器添加数据卷有两种方式。
方式一:在创建容器的时候,你可以用-v
参数添加容器卷
docker run -it -v 宿主机路径:容器路径 镜像名
比如我将我先前安装Oracle的包共享到容器去
[root@hdp3 opt] cd wy/
[root@hdp3 wy] ll
总用量 2295604
drwxr-xr-x. 8 root root 4096 8月 21 2009 database
-rw-r--r--. 1 root root 1239269270 10月 6 19:05 linux.x64_11gR2_database_1of2.zip
-rw-r--r--. 1 root root 1111416131 10月 6 20:27 linux.x64_11gR2_database_2of2.zip
[root@hdp3 wy] docker run -it -v /opt/wy:/opt/wy centos
[root@6f1543b2044e /] ls -l
total 48
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 360 Dec 6 10:31 dev
drwxr-xr-x 1 root root 4096 Dec 6 10:31 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 4096 Sep 15 2021 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 2020 media
drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt
drwxr-xr-x 1 root root 4096 Dec 6 10:31 opt
dr-xr-xr-x 142 root root 0 Dec 6 10:31 proc
dr-xr-x--- 2 root root 4096 Sep 15 2021 root
drwxr-xr-x 11 root root 4096 Sep 15 2021 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Dec 6 10:31 sys
drwxrwxrwt 7 root root 4096 Sep 15 2021 tmp
drwxr-xr-x 12 root root 4096 Sep 15 2021 usr
drwxr-xr-x 20 root root 4096 Sep 15 2021 var
[root@6f1543b2044e /] cd /opt/
[root@6f1543b2044e opt] ls
wy
[root@6f1543b2044e opt] cd wy/
[root@6f1543b2044e wy] ls
database linux.x64_11gR2_database_2of2.zip
linux.x64_11gR2_database_1of2.zip
添加共享卷的时候并不一定需要容器内部和宿主机两者存在对应的路径,其实就和插进去一块盘一样,且默认对数据卷拥有读写权限。
你还可以通过查看容器结构,来确定数据卷。
这里说一个注意点,老版本的docker中,容器拥有数据卷的写权限时,主路径是可以删除的,就比如本例中的/opt/wy
这个文件夹的本身是可以删除的,但是在新版本的docker中最多只能删除其内部的所有文件,而不能删除主路径本身
[root@6f1543b2044e opt] cd wy/
[root@6f1543b2044e wy] ls
database linux.x64_11gR2_database_2of2.zip
linux.x64_11gR2_database_1of2.zip
[root@6f1543b2044e wy] cd /opt/
[root@6f1543b2044e opt] ls
wy
[root@6f1543b2044e opt] rm -rf *
rm: cannot remove 'wy': Device or resource busy ###不让你删除主路径###
[root@6f1543b2044e opt] ls
wy
[root@6f1543b2044e opt] cd wy/
[root@6f1543b2044e wy] ls -l
total 0
言归正传,有的时候,数据卷对应的宿主机路径不会让你有写的权限,因此可以运行如下命令,:ro
表示只读,默认:rw
docker run -it -v 宿主机路径:容器路径:ro 镜像名
如果你需要挂载多个数据卷,则要输入多个-v
,而不是在一个-v
后写
说明老版本docker,极端的时候,run命令-v
挂载数据卷后访问会报错cannot open directory:Permission denied
,这就需要加上--privileged=true
这个参数,但新版本我还没有遇到出现这个问题。
方式二:DockerFile方式添加数据卷,这里先声明,DockerFile是一个完整的docker知识点,后面会开单章介绍,这里就先知道怎么用它添加数据卷就行。
特别说明!!!!!!DockerFile方式添加数据卷有个很鬼畜的事情,后面会说
你要改DockerFile,你总要知道它什么样吧?你就需要在官网上找到你下载的镜像,https://hub.docker.com/
,比如我之前下载的tomcat镜像,随后在详情中你就可以看到官方的帮助文档,根据下载的镜像中含有的tomcat版本去找一个相近的DockerFile帮助,因为并不一定每个版本单独建一个。
随后会跳转到github上,内容看不懂没关系,后面会开一个单章介绍这里面的东西,你现在最多只需要知道每一个docker镜像一定有它对应的DockerFile,DockerFile中的内容是对该镜像的描述,它就和JAVA的class文件一样,在docker中DockerFile从逻辑上来说不可能单独存在,因为它的目的就是用来描述一个要生成的镜像,如果没有对应的镜像,则它本身也就没有了存在的价值。
当然上面这些只是让你找到这是个什么东西,下面我们准备一个文件,名字随意,不一定非要叫DockerFile,比如叫myfile
[root@hdp3 wy] vi myfile
FROM centos
VOLUME ["/opt/myfile/test01","/opt/myfile/test02"]
CMD echo "OK!!!!"
CMD /bin/bash
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
"myfile" [New] 4L, 95C written
[root@hdp3 wy] ll
总用量 4
-rw-r--r-- 1 root root 95 12月 6 21:02 myfile
这里由于已经用到了,所以先说两个VOLUME
用来描述镜像中数据卷路径的,它不涉及宿主机的,应为宿主机存在可变性。FROM
用来描述镜像的基础镜像是谁。CMD
可以用来执行一个命令。就先知道这么多即可。
现在我们就用这个文件build生成
一个镜像,用到的命令如下,注意末尾有个.
,而且如你的DockerFile
文件名就叫DockerFile
,且你处于它所在的路径下,则可以不用-f
参数,但不推荐这样用,保不住会出意外
docker build -f 你自己的DockerFile -t 镜像名 .
[root@hdp3 wy] docker build -f /opt/wy/myfile -t wy/centos .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : VOLUME ["/opt/myfile/test01","/opt/myfile/test02"]
---> Running in 4b6880c91d0f
Removing intermediate container 4b6880c91d0f
---> 4bffb4a9ad2c
Step 3/4 : CMD echo "OK!!!!"
---> Running in 44edd9f7322e
Removing intermediate container 44edd9f7322e
---> 51a76bdc475f
Step 4/4 : CMD /bin/bash
---> Running in 8295fe0b4243
Removing intermediate container 8295fe0b4243
---> f605952bf91a
Successfully built f605952bf91a
Successfully tagged wy/centos:latest
[root@hdp3 wy] docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wy/centos latest f605952bf91a 34 seconds ago 231MB
atguigu/mytomcat 1.2 4f6fc450f49c 4 hours ago 680MB
tomcat latest fb5657adc892 11 months ago 680MB
centos latest 5d0da3dc9764 14 months ago 231MB
此时就可以再提一嘴前面知识点的内容,在镜像命令的时候,search一个镜像结果最后一项的AUTOMATED
就表示该镜像是否是被build出来的。
现在我们就需要用这个build出来的镜像生成一个容器,看一下它是否自带我们指定的VOLUME ["/opt/myfile/test01","/opt/myfile/test02"]
这两个数据卷路径
[root@hdp3 wy] docker run -it wy/centos
[root@4ad2a19c71db /] cd /opt
[root@4ad2a19c71db opt] ls
myfile
[root@4ad2a19c71db opt] cd myfile/
[root@4ad2a19c71db myfile] ls
test01 test02
但是此时就出现一个问题,我们-v
添加数据卷的时候就可以指定宿主机对应的路径,但是DockerFile由于官方考虑到镜像的宿主机有不确定因素,所以只能只能镜像中的数据卷路径,那宿主机上的路径怎么办呢?这个不要慌,因为docker会给一个默认路径,我们查看容器的结构信息就行
这个时候我上面说的很鬼畜的事情就要发生了 ----------------
当你想要打开容器中的数据卷的时候,会提示你,该目录打不开,由于我本人,在工作中使用docker挂载数据卷的时候一般都是直接-v,基本不用dockerfile,所以写本篇博文的时候,我用的docker版本较新,我有印象的用dockerfile做数据卷还是2018年,所以我在网上查了一下,才发现较新的docker中已经不再是直接生成数据卷,并挂载一个宿主机默认路径了,而是只生成一个挂载点,你想用它,只能是在run
的时候-v
所以最后的总结一下,你就当做添加数据卷只能-v
,DockerFile是除了commit第二种生成镜像方式中添加默认挂载点的就行。其实个人的看法想一想dockerfile,它的主体功能导致他确实不适合用来直接挂载数据卷这个操作,因为它本身是用来生成镜像的,而老版本的不足加上网上有好多通过它操作添加数据卷的文献,抛开会不会出问题,单说这种操作就和它存在的意义相背驰。
一定有人疑惑,run是新生成一个容器,那怎么给已有的容器添加数据卷,我很抱歉的告诉你,截至我目前操作的最新版,也就是20.10.21版本,通通不支持给已有容器添加数据卷,但是你可以试一试在已有的数据卷中,操作宿主机这一侧的路径,在里面直接挂载新磁盘
至于已有的容器添加数据卷,我尝试去改容器的配置文件,发现行不通,随着容器的重启,配置文件的相关内容就复原了。
除非某天你遇到了实在没办法的情况,在深思熟虑后,确保不会影响其他的东西,你再通过dockerfile把当前容器整体打包成一个新的镜像去新增挂载点的方式,把你所需要的数据卷挂载上去。但是这种情况即使真的发生了,也完全用不到doctorfile,因为docker file是直接操作基础镜像,没有容器的事,所以真的发生这种情况,你完全可以在容器里commit。
末尾补充一个概念拥有数据卷的容器,被称作是数据卷容器
。
有个使用技巧,如果你在run容器的时候,对应同一镜像的多个容器都是同样的配置时,你不需要每个run都使用相同的配置相关的参数,其他的容器在run的时候使用--volumes-from 容器
参数继承第一个就行了,该参数可以有多个容器用空格隔开