四、Docker存储管理
转载自:https://www.cnblogs.com/dcz2015/p/12458005.html
一、介绍
如果把数据存在容器内,可能会出现如下两个问题:
1.当容器不再运行时,我们无法使用数据,并且容器被删除时,数据并不会被保存。
2.数据保存在容器中的可写层中,我们无法轻松的将数据移动到其他地方。
针对上面的问题,Docker提供了三种解决方法:
volumes, 卷存储在 Docker 管理的主机文件系统的一部分中(/var/lib/docker/volumes/) 中。完全由 Docker 管理
bind mounts, 绑定挂载,可以将主机上的文件或目录挂载到容器中
tmpfs, 仅存储在主机系统的内存中,而不会写入主机的文件系统

二、各种解决方法
1.Volume是由Docker进行管理的,可以使用Docker CLI来管理卷。
①列出所有的卷的列表
|
1
2
|
[root@TBEARZ206458 ~]# docker volume lsDRIVER VOLUME NAME |
②上面列表是空的,因为本地还没有创建,可以使用 docker volume create 创建卷
|
1
2
3
4
5
|
[root@TBEARZ206458 ~]# docker volume create13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113[root@TBEARZ206458 ~]# docker volume lsDRIVER VOLUME NAMElocal 13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113 |
这种方式没有指定卷的名称,称为创建匿名卷。
如果想要创建一个自定义名称的卷,可以在create后指定名称。
|
1
2
3
4
5
6
7
|
[root@TBEARZ206458 ~]# docker volume create myvolumemyvolume[root@TBEARZ206458 ~]# docker volume lsDRIVER VOLUME NAMElocal 13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113local myvolume[root@TBEARZ206458 ~]# |
③卷创建好之后,可以用它来启动一个容器,这里主要是在 docker container run命令中使用如下的参数:
-v 或 --volume
由三个由冒号(:)分隔的字段组成,[HOST-DIR:]CONTAINER-DIR[:OPTIONS]。
HOST-DIR 代表主机上的目录或数据卷的名字。省略该部分时,会自动创建一个匿名卷。如果是指定主机上的目录,需要使用绝对路径。
CONTAINER-DIR 代表将要挂载到容器中的目录或文件,即表现为容器中的某个目录或文件
OPTIONS 代表配置,例如设置为只读权限(ro),此卷仅能被该容器使用(大写Z),或者可以被多个容器使用 (小写z)。多个配置项由逗号分隔。
例如,我们使用 -v volume1:/volume1:ro,z。代表的是意思是将卷 volume1 挂载到容器中的 /volume1 目录。ro,z 代表该卷被设置为只读(ro),并且可以多个容器使用该卷(z)
--mount
由多个键值对组成,键值对之间由逗号分隔。例如: type=volume,source=volume1,destination=/volume1,ro=true。
type,指定挂载类型,可以指定为 bind,volume,tmpfs。
source,当类型为 volume 时,指定卷名称,匿名卷时省略该字段。当类型为 bind,指定路径。可以使用缩写 src。
destination,挂载到容器中的路径。可以使用缩写 dst 或 target。
ro 为配置项,多个配置项直接由逗号分隔一般使用 true 或 false。
举例:
|
1
2
|
[root@TBEARZ206458 ~]# docker run -v myvolume:/myvolume:ro,z -p 8080:80 -d centosdotent:1.0.0dd73b7c10ca6865a21a3092e245589e3a4bcbbd3e4401f83632858cfaf4f0e6c |
进入到容器内,可以看到myvolume

这里我也实验了一下 如果volume没有创建,那么run一个容器也会成功

然后会自动创建一个volume
|
1
2
3
4
5
|
[root@TBEARZ206458 ~]# docker volume lsDRIVER VOLUME NAMElocal 13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113local myvolumelocal myvolume22222 |
如果进入到这个文件夹,然后做一些操作,因为我现在是只读模式,它会报错
|
1
2
3
4
5
6
7
8
9
|
[root@TBEARZ206458 ~]# docker exec -it elated_tu /bin/bashroot@6d3f37ae1b65:/home/DotnetWebDemo# cd /root@6d3f37ae1b65:/# lsbin boot dev etc home lib lib64 media mnt myvolumex opt proc root run sbin srv sys tmp usr varroot@6d3f37ae1b65:/# cd myvolumex/root@6d3f37ae1b65:/myvolumex# lsroot@6d3f37ae1b65:/myvolumex# mkdir testdirmkdir: cannot create directory 'testdir': Read-only file systemroot@6d3f37ae1b65:/myvolumex# |
创建一个使用同一个volume的容器,修改它的权限是可读可写(去掉了ro)
|
1
2
|
[root@TBEARZ206458 ~]# docker run -v myvolume:/myvolumey:z -p 8084:80 -d centosdotent:1.0.0219e4183b6aa0639a8454ed10d4048c12571ae2851d4b27f1f99e2837bda29b4 |
然后在里面创建一个目录和文件
|
1
2
3
4
5
6
|
[root@TBEARZ206458 ~]# docker exec -it 219e4183b6aa0639a8454ed10d4048c12571ae2851d4b27f1f99e2837bda29b4 /bin/bashroot@219e4183b6aa:/home/DotnetWebDemo# cd /root@219e4183b6aa:/# cd myvolumey/root@219e4183b6aa:/myvolumey# mkdir testroot@219e4183b6aa:/myvolumey# cd test/root@219e4183b6aa:/myvolumey/test# touch file1.txt |
然后退出,进入上一个容器,可以看到共享的volume里面的内容
|
1
2
3
4
5
6
7
|
[root@TBEARZ206458 ~]# docker exec -it elated_tu /bin/bashroot@6d3f37ae1b65:/home/DotnetWebDemo# cd /myvolumex/root@6d3f37ae1b65:/myvolumex# lstestroot@6d3f37ae1b65:/myvolumex# cd test/root@6d3f37ae1b65:/myvolumex/test# lsfile1.txt |
2. bind-mounts
对于volume来说,其优点在于方便管理。而对于绑定挂载(bind-mounts)来说,通过将主机上的目录绑定到容器中,容器就可以操作和修改主机上该目录的内容。这既是其优点也是其缺点。
举例:例如把本地主机上的一个目录挂在到容器当中,可以使用如下的操作:
|
1
2
3
4
5
6
|
[root@TBEARZ206458 ~]# cd /home/[root@TBEARZ206458 home]# mkdir test[root@TBEARZ206458 home]# lslic test[root@TBEARZ206458 home]# docker run -v /home/test:/home/mytest:z -p 8085:80 -d centosdotent:1.0.037c6ce742548956a8619b42a2da56b9342b49be634761ce6e369abf96452b03e |
和上面一样,只要把 -v 后面的 HOST-DIR 的换成本地刚刚创建好的目录(/home/test)就行
如果绑定挂载时指定的容器目录是非空的,则该目录中的内容将会被覆盖。并且如果主机上的目录不存在,会自动创建该目录。
注意:对于挂载文件(一定是文件!)来说,可能会出现一些特殊情况,涉及到绑定挂载和使用卷的区别。
①首先在/home/test 下创建一个文件
|
1
2
3
|
[root@TBEARZ206458 home]# cd test/[root@TBEARZ206458 test]# ls[root@TBEARZ206458 test]# touch filehello.txt |
②创建一个容器,并将该文件挂载到容器内
|
1
2
3
4
5
6
|
docker run -v /home/test/filehello.txt:/home/mytest/filehello.txt:z -p 8086:80 -d centosdotent:1.0.0检查一下[root@TBEARZ206458 test]# docker exec -it loving_einstein /bin/bashroot@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/ root@5175c06e34de:/home/mytest# lsfilehello.txt |
③退出容器,现在在外层通过 echo 写入内容到 filehello.txt当中
|
1
2
3
|
[root@TBEARZ206458 test]# echo "hello world" > filehello.txt[root@TBEARZ206458 test]# cat filehello.txthello world |
④ 进入docker内部查看一下,发现也存在了刚刚输入的文字,顺便看下文件的inode(1315091 )
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@TBEARZ206458 test]# docker exec -it loving_einstein /bin/bash root@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/root@5175c06e34de:/home/mytest# cat filehello.txthello worldroot@5175c06e34de:/home/mytest# stat filehello.txt File: filehello.txt Size: 12 Blocks: 8 IO Block: 4096 regular fileDevice: 801h/2049d Inode: 1315091 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2020-03-09 08:52:00.112634707 +0000Modify: 2020-03-09 08:51:52.612701048 +0000Change: 2020-03-09 08:51:52.612701048 +0000 Birth: - |
⑤现在退出容器,查看下外部的文件的indoe,使用Vim编辑文件,修改文件,发现inode 从 1315091 -> 1315097
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[root@TBEARZ206458 test]# stat filehello.txt File: ‘filehello.txt’ Size: 12 Blocks: 8 IO Block: 4096 regular fileDevice: 801h/2049d Inode: 1315091 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2020-03-09 16:52:00.112634707 +0800Modify: 2020-03-09 16:51:52.612701048 +0800Change: 2020-03-09 16:51:52.612701048 +0800 Birth: -[root@TBEARZ206458 test]# vim filehello.txt[root@TBEARZ206458 test]# cat filehello.txthello worldlalalahehehe[root@TBEARZ206458 test]# stat filehello.txt File: ‘filehello.txt’ Size: 26 Blocks: 8 IO Block: 4096 regular fileDevice: 801h/2049d Inode: 1315097 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2020-03-09 16:56:02.736480509 +0800Modify: 2020-03-09 16:55:56.144539240 +0800Change: 2020-03-09 16:55:56.156539134 +0800 Birth: - |
⑥再次进入容器,查看一下该文件, 发现容器内的文件 inode和内容全都不变。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@TBEARZ206458 test]# docker exec -it loving_einstein /bin/bashroot@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/root@5175c06e34de:/home/mytest# stat filehello.txt File: filehello.txt Size: 12 Blocks: 8 IO Block: 4096 regular fileDevice: 801h/2049d Inode: 1315091 Links: 0Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2020-03-09 08:52:00.112634707 +0000Modify: 2020-03-09 08:51:52.612701048 +0000Change: 2020-03-09 08:55:56.156539134 +0000 Birth: -root@5175c06e34de:/home/mytest# cat filehello.txthello world |
Vim是采用先备份,后修改替换的方式修改文件,所以每次Vim操作完之后文件的inode会变化。如果修改的文件正好是挂载在容器里面的文件,那么容器内的文件还是旧文件。
对于数据卷来说,由 docker 完全管理,而绑定挂载,则需要我们自己去维护。我们需要自己手动去处理这些问题,这些问题并不仅仅是上面演示的内容,还可能有用户权限,SELINUX 等问题。
3. tmpfs
tmpfs 只存储在主机的内存中。当容器停止时,相应的数据就会被移除。不举例了。
三、数据卷容器
如果容器之间需要共享一些持续更新的数据,最简单的方式就是使用用户数据卷容器。
其他容器通过挂载这个容器实现数据共享,这个挂载数据卷的容器就叫做数据卷容器。
数据卷容器就是一种普通容器,它专门提供数据卷供其它容器挂载使用。
I.使用数据卷容器
①创建数据卷容器,并在卷文件夹下创建一个文件
|
1
2
3
4
5
6
7
8
|
[root@TBEARZ206458 ~]# docker container run -it -v vdata:/sharedata --name IamVolumeContainer centos /bin/bash[root@TBEARZ206458 ~]# docker exec -it IamVolumeContainer /bin/bash[root@efdbc9a25138 /]# cd sharedata/[root@efdbc9a25138 sharedata]# echo "I'm a VolumeContainer" > file.txt //写入文件[root@efdbc9a25138 sharedata]# lsfile.txt[root@efdbc9a25138 sharedata]# cat file.txtI'm a VolumeContainer |
②创建新的容器,使用刚刚创建的数据卷容器,需要使用的run参数是 --volumes-from 继承数据卷容器IamVolumeContainer 挂载的数据卷
|
1
2
3
4
5
6
7
|
[root@TBEARZ206458 ~]# docker run -it --volumes-from IamVolumeContainer --name shareContainer centos /bin/bash[root@d087086ada1a /]# cd sharedata/[root@d087086ada1a sharedata]# lsfile.txt[root@d087086ada1a sharedata]# echo "I'm sharecontainer1" > file2.txt[root@d087086ada1a sharedata]# lsfile.txt file2.txt |
③和上面一样创建新容器,查看是否有上两次创建的文件
|
1
2
3
4
5
6
7
8
9
|
[root@TBEARZ206458 ~]# docker run -it --volumes-from IamVolumeContainer --name shareContainer2 centos /bin/bash [root@d26d32b26060 /]# cd sharedata/[root@d26d32b26060 sharedata]# lsfile.txt file2.txt[root@d26d32b26060 sharedata]# cat file2.txtI'm sharecontainer1[root@d26d32b26060 sharedata]# echo "I'm sharecontainer2" > file3.txt[root@d26d32b26060 sharedata]# lsfile.txt file2.txt file3.txt |
④再回到原来的数据卷容器,可以发现文件被共享了
|
1
2
3
4
|
[root@TBEARZ206458 ~]# docker exec -it IamVolumeContainer /bin/bash [root@efdbc9a25138 /]# cd /sharedata/[root@efdbc9a25138 sharedata]# lsfile.txt file2.txt file3.txt |
II.数据备份和还原
①使用备份容器,备份数据
|
1
2
3
4
5
6
7
8
9
10
11
|
[root@TBEARZ206458 ~]# docker container run \--volumes-from IamVolumeContainer \-v /home/share/backup:/backup \centos \tar cvf /backup/backup.tar /sharedata/以下是执行tar: Removing leading `/' from member names/sharedata//sharedata/file2.txt/sharedata/file3.txt[root@TBEARZ206458 ~]# |
命令解析
--volumes-from IamVolumeContainer 代表继承自IamVolumeContainer这个容器的卷启动新容器
-v /home/share/backup:/backup 代表把 /home/share/backup 挂载到容器的 /backup 目录
centos 镜像名称
tar cvf /backup/backup.tar /sharedata/ 代表把 /sharedata/ 的内容全部压缩打包到 /backup/backup.tar文件

执行之后可以看到,本地主机已经有了对应的tar文件
|
1
2
3
4
|
[root@TBEARZ206458 ~]# cd /home/share/backup/[root@TBEARZ206458 backup]# lsbackup.tar[root@TBEARZ206458 backup]# |
②使用恢复容器恢复数据
例如创建这样一个文件
|
1
2
|
[root@TBEARZ206458 recover]# pwd /home/share/recover[root@TBEARZ206458 recover]# ls recover.tar<em id="__mceDel"><br></em> |
创建一个恢复容器
|
1
2
3
4
5
6
7
8
|
[root@TBEARZ206458 recover]# docker container run \--volumes-from IamVolumeContainer \-v /home/share/recover:/recover \centos \tar xvf /recover/recover.tar以下是执行recover/recover/readme.txt |


浙公网安备 33010602011771号