一、Dokcer容器的数据卷定义
数据卷是一个或多个容器中专门指定的目录,他能够绕过联合文件系统。
卷被设计用作数据持久化,并且是独立于容器的生命周期的。
因此,Docker不会在删除容器时自动删除数据卷,也不会主动“垃圾回收”掉容器不再使用的卷。
当我们在使用docker容器的时候,会产生一系列的数据文件,这些数据文件在我们关闭docker容器时是会消失的。
但是其中产生的部分内容我们是希望能够把它给保存起来另作用途的。
Docker将应用与运行环境打包成容器发布,我们希望在运行过程中产生的部分数据是可以持久化的。而且容器之间我们希望能够实现数据共享。
通俗地说,docker容器数据卷可以看成使我们生活中常用的U盘,它存在一个或多个的容器中由docker挂载到容器,但不属于联合文件系统,Docker不会在容器删除时删除其挂载的数据卷。
数据卷分为三种类型:
(1)宿主机数据卷:直接在宿主机的文件系统中但是容器可以访问(bind mount)
(2)命名的数据卷:磁盘上Docker管理的数据卷,但是这个卷有个名字。
(3)匿名数据卷:磁盘上Docker管理的数据卷,因为没有名字想要找到不容易,Docker来管理这些文件。
备注:
数据卷其实都在(如果没有网络文件系统等情况下)宿主机文件系统里面的,
只是第一种是在宿主机内的特定目录下,而后两种则在docker管理的目录下,这个目录一般是 /var/lib/docker/volumes/。
二、数据卷的特点
- 数据卷可以在容器之间共享或重用数据
- 数据卷中的更改可以直接生效
- 数据卷中的更改
- 数据卷的生命周期一直持续到没有容器使用它为止。
三、如何添加数据卷?
`添加数据卷的方式有两种,第一种是直接通过命令行挂载,第二种是通过dockerfile添加;
- 第一种通过命令行挂载的方式,命令如下:
docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
这个命令会在宿主机和容器内分别建立两个目录,两个目录是对接的,里面的数据可以共享。
如果我们不知道数据卷是否挂载成功时,我们可以通过以下方式来检查数据卷的挂载结果。
dokcer ps -a #查看所有容器的id
docker inspect 容器id
上面的命令可以查看容器的详细情况,命令返回是JSON格式的字符串
运行命令之后我们在返回的JSON字符串中找到Volumes属性
假如挂载成功的话,Volumes里面显示的绑定结果应该是你在挂载时输入的命令参数( /宿主机绝对路径目录:/容器内目录)
如果与我们之前输入的一致的话,证明挂载成功
PS:Volumes里面显示的绑定结果可能有多个,但是只要找到目标结果就可以
挂载之后,当容器停止运行的时候,宿主机上对数据卷做的内容修改的会同步到容器内的,我们再挂载的时候还可以给数据卷加上权限,假如我们要宿主机只能读取容器的数据卷内容不能修改,我们可以添加只读权限
docker run -it -v /宿主机绝对路径目录:/容器内目录 :ro 镜像名
至于只写的话我们一般不会用到,要么就是读写,要么就是只读。
而且我们可以通过docker inspect来查看容器的VolumesRW来查看容器内数据卷的读写权限
- 第二种就是利用dockerFile的形式添加
== dockerFile对于docker镜像而言就如同java中某个类的.class文件对应上该类的.java文件==
首先在linux服务器根目录上新建docker文件夹并建立DockerFile文件
使用volume命令
(出于可移植可分享的的考虑,用以上 -v /宿主机绝对路径目录 : /容器内目录 的这种方式不能够直接在dockerFile中直接实现,
因为宿主机目录是依赖于特定的宿主机的,并不能保证所有的宿主机都存在这样特定的目录)
编写的dockerFile文件如下
FROM 镜像名
VOLUME ["/生成的目录路径"] -- privileged=true
CMD echo "success build"
CMD /bin/bash
相当于命令行:dcoker run -it -v /宿主机目录路径 : /生成的目录路径
然后我们通过命令行docker build执行我们写好的dockerfile文件
(docker build和docker commit两个命令都可以建立docker镜像,docker commit需要在容器内进行,docker build不需要 )
docker build -f /docker/DockerFile -t 命名空间/镜像名
执行后输入docker images就可以发现自己通过DockerFile所建立的镜像,里面有挂载数据卷,那么问题来了宿主机所对应的目录是什呢?
同上,我们可以通过docker inspect来查看当前容器的Volumes,里面会有宿主机的数据卷目录
说了这么多,那么到底什么是docker数据卷容器?
上面介绍了docker容器数据卷,他的作用相当于生活中的活动硬盘
那么数据卷容器就相于把多个活动硬盘在挂载到一个活动硬盘上,实现数据的传递依赖。
官网解析:命令的容器挂载数据卷,其他的容器通过挂载这个容器实现数据共享,挂载数据卷的容器,我们称为数据卷容器。
首先,我们建立父容器
docker run -it - -name parentContainer 镜像名(可以填上面通过dockerFile建立的镜像,里面有挂载容器卷)
然后建立两个子容器继承父容器
docker run -it - -name sonContainer1 --volumes -from parentContainer 镜像名
docker run -it - -name sonContainer2 --volumes -from parentContainer 镜像名
假如我们DockerFile里面定义的容器卷目录为dockerVolume,父容器里面有dockerVolume目录,子容器继承了父容器的dockerVolume,
在子容器中的dockerVolume目录作出的修改会同步到父容器的dockerVolume目录上,达到了继承和数据共享的目的。
官网上有一句话描述的是,容器之间配置信息的传递,数据卷的生命周期会一致持续到没有容器使用它为止,
换言之,只要有一个容器仍在使用该数据卷,该数据卷一直都可以进行数据共享,通俗地来说,如果此时我们把父容器关闭掉,两个字容器之间依旧可以进行数据共享,而且通过继承子容器生成的新容器,一样可以与子容器进行数据共享。
这就是docker容器间的数据传递共享。
四、docker的数据卷
数据卷是目录或文件,不是块设备
容器可以读写volume中的数据
volume数据可以持久化保存
docker提供了两种卷:
- bind mount
是将主机上的目录或文件mount到容器里
使用直观高效,易于理解。
使用 -v 选项路径,格式<host path>:<container path> == 本地目录:容器目录 ;容器没有该目录会自动建立;
bind mount 默认权限是读写rw,可以挂载时指定只读ro.
-v 选项指定的路径,如果不存在,挂载时会自动创建。
挂载会覆盖之前的内容;
- docker managed volume (限制容器权限)
bind mount必须指定host文件系统路径,限制了移植性。
docker managed volume 不需要指定mount源。
- bind mount与docker managed volume对比
相同点:两者都是host文件系统中的某个路径
不同点,下图:
五、bind mount数据卷的演示
1.在宿主机上创建两个目录
[root@server3 tmp]# mkdir data1
[root@server3 tmp]# mkdir data2
2.运行一个容器
[root@server1 tmp]# docker run -it --name vm1 -v /tmp/data1:/data1 -v /tmp/data2:/data2:ro -v /etc/yum.repos.d/yum.repo:/yum.repo:ro ubuntu
data1目录为默认权限,data2和yum.repo为只读
3.测试挂载的目录权限
root@1c3cb3e4521c:/# ls
bin data1 dev home lib64 mnt proc run srv tmp var
boot data2 etc lib media opt root sbin sys usr yum.repo
root@1c3cb3e4521c:/# cat yum.repo
[docker]
name=docker-ce
baseurl=http://172.25.70.250/docker
gpgcheck=0
root@1c3cb3e4521c:/# cd data1
root@1c3cb3e4521c:/data1# ls
root@1c3cb3e4521c:/data1# touch file
root@1c3cb3e4521c:/data1# ls
file
root@1c3cb3e4521c:/data1# cd ../data2
root@1c3cb3e4521c:/data2# touch file1
touch: cannot touch 'file1': Read-only file system
root@1c3cb3e4521c:/data2#
root@1c3cb3e4521c:/data2# cd ../yum.repo
bash: cd: ../yum.repo: Not a directory
root@1c3cb3e4521c:/data2# cd ..
root@1c3cb3e4521c:/# echo 123 >> yum.repo
bash: yum.repo: Read-only file system
root@1c3cb3e4521c:/#
挂载yum源
会自动建立目录;
[root@server1 data2]# docker run -it --name vm2 -v /etc/yum.repos.d/yum.repo:/etc/yum.repos.d/yum.repo:ro(只读模式) rhel7 bash
六、docker managed volume数据卷的演示
1.查看现有的管理卷,现在没有任何数据卷
如何存在以前的数据卷,可以进行删除,发现管理卷仍然存在,这是我们就需要去清理它,不然会占用我们的资源
docker volume prune ##全部清理
[root@server1 ~]# docker volume ls
DRIVER VOLUME NAME
2.使用registry镜像创建一个新的容器
[root@server3 ~]# docker run -d --name registry registry:2.3.1
b147190e066a3da0905085e7b1bcc2ba312f97d50f6e2791cb3c45e8b5c13594
[root@server3 ~]# docker volume ls
DRIVER VOLUME NAME
local 5b9da0795c6abbae4639530c989321c706b53d2c695c54dad55248df4c228089
[root@server3 ~]#
4.查看registry容器的相关信息
[root@server3 ~]# docker inspect registry | grep Source
"Source": "/var/lib/docker/volumes/5b9da0795c6abbae4639530c989321c706b53d2c695c54dad55248df4c228089/_data",
[root@server3 ~]#
source就是volume在host中的目录,是docker自动为容器生成的目录,如果挂载时指向的已有目录,原有数据会被复制到volume中。
注意,即使容器删除了,但是管理卷资源还是存在,重新启动容器,还是存在的;
图中有个vm1的容器,跟这个容器没有任何关系;
我们会发现,docker自动生成的目录名称会很长,不方便书写使用。我们可以在创建容器时自己定义目录名称。
1.首先,需要先创建卷
[root@server3 ~]# docker volume create voll ##创建卷voll
2.接下来,创建新的容器并将管理卷voll挂载到容器内的指定目录
[root@server3 ~]# docker run -d --name registry2 -v voll:/var/lib/registry registry:2.3.1
ba070024c573617a369048a9fcbd061d35851320661d5aeca36d2cb79845d4af
[root@server3 ~]# docker inspect registry2 | grep Source
"Source": "/var/lib/docker/volumes/voll/_data",
[root@server3 ~]#
问题
:数据卷的移植性差
解决办法:
docker管理卷解决了移植性的问题;
七、Docker卷插件(plugins)(跨主机就不能满足,只能是宿主机的满足)
如果想实现跨主机的容器之间的数据共享就要使用卷插件
使用了卷插件才可以使用网络文件系统实现数据共享
convoy卷插件
convoy卷插件支持三种运行方式:devicemapper、NFS、EBS。,我们下面的实验以nfs的运行方式来演示
实验前提:1.准备两台主机server3、server4,并安装好Dokcer服务
2.关闭防火墙
- 首先在server1和server2上搭建nfs文件系统
server3:
[root@server3 ~]# yum install -y nfs-utils.x86_64 #安装
[root@server3 ~]# systemctl start rpcbind
[root@server3 ~]# mkdir /mnt/nfs #创建共享目录
[root@server3 ~]# chmod 777 /mnt/nfs/ #修改共享目录权限
[root@server3 ~]# vim /etc/exports #编辑共享目录文件,否则将不会被共享出去
[root@server3 ~]# cat /etc/exports
/mnt/nfs *(rw,no_root_squash)
[root@server3 ~]# systemctl start nfs
rpcbind服务必须是开启的。
这是因为:他是一个rpc服务,主要是在nfs共享时候负责通知客户端,服务器的nfs端口号的。
简单理解rpc就是一个中介服务。
server4:
[root@server4 ~]# yum install -y nfs-utils
[root@server4 ~]# systemctl start nfs-server.service
[root@server4 ~]# showmount -e 172.25.70.3
Export list for 172.25.70.3:
/mnt/nfs *
[root@server4 ~]# mkdir /mnt/nfs
[root@server4 ~]# mount 172.25.70.3:/mnt/nfs/ /mnt/nfs/
[root@server4 ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 8374272 2085840 6288432 25% /
devtmpfs 239252 0 239252 0% /dev
tmpfs 250224 0 250224 0% /dev/shm
tmpfs 250224 8584 241640 4% /run
tmpfs 250224 0 250224 0% /sys/fs/cgroup
/dev/sda1 1038336 123376 914960 12% /boot
tmpfs 50048 0 50048 0% /run/user/0
172.25.70.3:/mnt/nfs 8374272 4295168 4079104 52% /mnt/nfs
[root@server4 ~]#
测试:
[root@server4 ~]# cd /mnt/nfs/
[root@server4 nfs]# ls
[root@server4 nfs]# touch file #创建的信息,在server3上也可以看到
[root@server4 nfs]# ls
file
[root@server4 nfs]#
[root@server3 ~]# cd /mnt/nfs/
[root@server3 nfs]# ls
file
[root@server3 nfs]#
可以看出nfs实现了数据共享
- 配置convoy环境
docker官方只提供了卷插件的api,开发者可以根据实际需求定制卷插件驱动。
[root@server3 ~]# tar zxf convoy.tar.gz
[root@server3 ~]# cd convoy/
[root@server3 convoy]# ls
convoy convoy-pdata_tools SHA1SUMS
[root@server3 convoy]# cp convoy* /usr/local/bin/ #将二进制文件加入到PATH路径
[root@server3 convoy]# mkdir /etc/docker/plugins ##创建docker的插件目录
[root@server3 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &> /dev/null &
[1] 3780
第一次运行上面的convoy daemon命令的时候,会在/mnt/nfs目录下生成一个config文件,这个文件不能删除,否则客户端的convoy命令就用不了
[root@server3 convoy]# cd /mnt/nfs/
[root@server3 nfs]# ls
config file
[root@server3 nfs]# echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec
#将convoy守护进程开启生成的.sock文件放入/etc/docker/plugins目录下的convoy.spec文件中,dcoker就可以识别(其中convoy.spec文件之前是不存在的)
[root@server3 nfs]# cat /etc/docker/plugins/convoy.spec
unix:///var/run/convoy/convoy.sock
[root@server3 nfs]#
- 创建卷
[root@server3 nfs]# docker volume ls
DRIVER VOLUME NAME
local voll
[root@server3 nfs]# convoy create voll
voll
[root@server3 nfs]# ll
total 0
drwx------ 2 root root 34 Nov 9 17:01 config
-rw-r--r-- 1 root root 0 Nov 9 16:46 file
drwx------ 2 root root 6 Nov 9 17:01 voll
convoy delete vol1 #删除vol1卷,要保障server1和server2处于不是使用中,不然删除会报错;
- 将解压convoy目录给server4复制一份,配置convoy环境
[root@server3 ~]# scp -r convoy server4:
root@server4's password:
convoy-pdata_tools 100% 22MB 22.0MB/s 00:01
convoy 100% 19MB 19.5MB/s 00:01
SHA1SUMS 100% 124 0.1KB/s 00:00
[root@server3 ~]#
[root@server4 ~]# cd convoy/
[root@server4 convoy]# ls
convoy convoy-pdata_tools SHA1SUMS
[root@server4 convoy]# cp convoy* /usr/local/bin/
[root@server4 convoy]# mkdir /etc/docker/plugins
[root@server4 convoy]# echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec
[root@server4 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &> /dev/null & ###daemon:后台运行
[1] 1517
[root@server4 convoy]# cd /mnt/nfs/
[root@server4 nfs]# ls
config file voll
[root@server4 nfs]#
- 操作卷
列出所有卷
使用卷
由上可知server3和server4上看到的内容一致,即不同主机间实现了共享存储。
创建convoy卷的快照
[root@server3 voll]# convoy snapshot create voll --name voll_pic
voll_pic
--name前面的是卷名,加个--name起个名字,不然会是数字
[root@server3 voll]# convoy list
删除快照