四、Docker存储管理

一、介绍

如果把数据存在容器内,可能会出现如下两个问题:

1.当容器不再运行时,我们无法使用数据,并且容器被删除时,数据并不会被保存。

2.数据保存在容器中的可写层中,我们无法轻松的将数据移动到其他地方。

 

针对上面的问题,Docker提供了三种解决方法:

volumes, 卷存储在 Docker 管理的主机文件系统的一部分中(/var/lib/docker/volumes/) 中。完全由 Docker 管理

bind mounts, 绑定挂载,可以将主机上的文件或目录挂载到容器中

tmpfs, 仅存储在主机系统的内存中,而不会写入主机的文件系统

 

 

二、各种解决方法

1.Volume是由Docker进行管理的,可以使用Docker CLI来管理卷。

①列出所有的卷的列表

[root@TBEARZ206458 ~]# docker volume ls
DRIVER              VOLUME NAME

②上面列表是空的,因为本地还没有创建,可以使用 docker volume create 创建卷

[root@TBEARZ206458 ~]# docker volume create
13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113
[root@TBEARZ206458 ~]# docker volume ls
DRIVER              VOLUME NAME
local               13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113

这种方式没有指定卷的名称,称为创建匿名卷

如果想要创建一个自定义名称的卷,可以在create后指定名称。

[root@TBEARZ206458 ~]# docker volume create myvolume
myvolume
[root@TBEARZ206458 ~]# docker volume ls
DRIVER              VOLUME NAME
local               13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113
local               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,指定挂载类型,可以指定为 bindvolumetmpfs

source,当类型为 volume 时,指定卷名称,匿名卷时省略该字段。当类型为 bind,指定路径。可以使用缩写 src

destination,挂载到容器中的路径。可以使用缩写 dst  target

ro 为配置项,多个配置项直接由逗号分隔一般使用 true  false

举例:

[root@TBEARZ206458 ~]# docker run -v myvolume:/myvolume:ro,z -p 8080:80 -d centosdotent:1.0.0
dd73b7c10ca6865a21a3092e245589e3a4bcbbd3e4401f83632858cfaf4f0e6c 

进入到容器内,可以看到myvolume

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

 然后会自动创建一个volume

[root@TBEARZ206458 ~]# docker volume  ls
DRIVER              VOLUME NAME
local               13c0ce66e1dae1cbe5df3c6881e35b575ea26508ecaa0b2b54e2502d25ce5113
local               myvolume
local               myvolume22222

如果进入到这个文件夹,然后做一些操作,因为我现在是只读模式,它会报错

[root@TBEARZ206458 ~]# docker exec -it elated_tu /bin/bash
root@6d3f37ae1b65:/home/DotnetWebDemo# cd /
root@6d3f37ae1b65:/# ls
bin  boot  dev	etc  home  lib	lib64  media  mnt  myvolumex  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@6d3f37ae1b65:/# cd myvolumex/
root@6d3f37ae1b65:/myvolumex# ls
root@6d3f37ae1b65:/myvolumex# mkdir testdir
mkdir: cannot create directory 'testdir': Read-only file system
root@6d3f37ae1b65:/myvolumex# 

创建一个使用同一个volume的容器,修改它的权限是可读可写(去掉了ro

[root@TBEARZ206458 ~]# docker run -v myvolume:/myvolumey:z -p 8084:80 -d centosdotent:1.0.0
219e4183b6aa0639a8454ed10d4048c12571ae2851d4b27f1f99e2837bda29b4 

然后在里面创建一个目录和文件

[root@TBEARZ206458 ~]# docker exec -it 219e4183b6aa0639a8454ed10d4048c12571ae2851d4b27f1f99e2837bda29b4  /bin/bash
root@219e4183b6aa:/home/DotnetWebDemo# cd /
root@219e4183b6aa:/# cd myvolumey/
root@219e4183b6aa:/myvolumey# mkdir test
root@219e4183b6aa:/myvolumey# cd test/
root@219e4183b6aa:/myvolumey/test# touch file1.txt 

然后退出,进入上一个容器,可以看到共享的volume里面的内容  

[root@TBEARZ206458 ~]# docker exec -it elated_tu /bin/bash
root@6d3f37ae1b65:/home/DotnetWebDemo# cd /myvolumex/
root@6d3f37ae1b65:/myvolumex# ls
test
root@6d3f37ae1b65:/myvolumex# cd test/
root@6d3f37ae1b65:/myvolumex/test# ls
file1.txt 

2. bind-mounts

对于volume来说,其优点在于方便管理。而对于绑定挂载(bind-mounts)来说,通过将主机上的目录绑定到容器中,容器就可以操作和修改主机上该目录的内容。这既是其优点也是其缺点。

 

举例:例如把本地主机上的一个目录挂在到容器当中,可以使用如下的操作:  

[root@TBEARZ206458 ~]# cd /home/
[root@TBEARZ206458 home]# mkdir test
[root@TBEARZ206458 home]# ls
lic  test
[root@TBEARZ206458 home]# docker run -v /home/test:/home/mytest:z -p 8085:80 -d centosdotent:1.0.0
37c6ce742548956a8619b42a2da56b9342b49be634761ce6e369abf96452b03e 

和上面一样,只要把 -v 后面的 HOST-DIR 的换成本地刚刚创建好的目录(/home/test)就行

如果绑定挂载时指定的容器目录是非空的,则该目录中的内容将会被覆盖。并且如果主机上的目录不存在,会自动创建该目录。

注意:对于挂载文件(一定是文件!)来说,可能会出现一些特殊情况,涉及到绑定挂载使用卷的区别。

首先在/home/test 下创建一个文件  

[root@TBEARZ206458 home]# cd test/
[root@TBEARZ206458 test]# ls
[root@TBEARZ206458 test]# touch filehello.txt 

创建一个容器,并将该文件挂载到容器内

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/bash
root@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/              
root@5175c06e34de:/home/mytest# ls
filehello.txt 

退出容器,现在在外层通过 echo 写入内容到 filehello.txt当中

[root@TBEARZ206458 test]# echo "hello world" > filehello.txt 
[root@TBEARZ206458 test]# cat filehello.txt 
hello world 

进入docker内部查看一下,发现也存在了刚刚输入的文字,顺便看下文件的inode1315091 )  

[root@TBEARZ206458 test]# docker exec -it loving_einstein /bin/bash  
root@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/
root@5175c06e34de:/home/mytest# cat filehello.txt 
hello world
root@5175c06e34de:/home/mytest# stat filehello.txt               
  File: filehello.txt
  Size: 12        	Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d	Inode: 1315091     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-03-09 08:52:00.112634707 +0000
Modify: 2020-03-09 08:51:52.612701048 +0000
Change: 2020-03-09 08:51:52.612701048 +0000
 Birth: - 

现在退出容器,查看下外部的文件的indoe,使用Vim编辑文件,修改文件,发现inode 1315091  -> 1315097  

[root@TBEARZ206458 test]# stat filehello.txt 
  File: ‘filehello.txt’
  Size: 12        	Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d	Inode: 1315091     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-03-09 16:52:00.112634707 +0800
Modify: 2020-03-09 16:51:52.612701048 +0800
Change: 2020-03-09 16:51:52.612701048 +0800
 Birth: -
[root@TBEARZ206458 test]# vim filehello.txt 
[root@TBEARZ206458 test]# cat filehello.txt 
hello world
lalala
hehehe
[root@TBEARZ206458 test]# stat filehello.txt 
  File: ‘filehello.txt’
  Size: 26        	Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d	Inode: 1315097     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-03-09 16:56:02.736480509 +0800
Modify: 2020-03-09 16:55:56.144539240 +0800
Change: 2020-03-09 16:55:56.156539134 +0800
 Birth: - 

再次进入容器,查看一下该文件, 发现容器内的文件 inode和内容全都不变。

[root@TBEARZ206458 test]# docker exec -it loving_einstein /bin/bash
root@5175c06e34de:/home/DotnetWebDemo# cd /home/mytest/
root@5175c06e34de:/home/mytest# stat  filehello.txt 
  File: filehello.txt
  Size: 12        	Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d	Inode: 1315091     Links: 0
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-03-09 08:52:00.112634707 +0000
Modify: 2020-03-09 08:51:52.612701048 +0000
Change: 2020-03-09 08:55:56.156539134 +0000
 Birth: -
root@5175c06e34de:/home/mytest# cat filehello.txt 
hello world

Vim是采用先备份,后修改替换的方式修改文件,所以每次Vim操作完之后文件的inode会变化。如果修改的文件正好是挂载在容器里面的文件,那么容器内的文件还是旧文件。

对于数据卷来说,由 docker 完全管理,而绑定挂载,则需要我们自己去维护。我们需要自己手动去处理这些问题,这些问题并不仅仅是上面演示的内容,还可能有用户权限,SELINUX 等问题。 

3. tmpfs 

tmpfs 只存储在主机的内存中。当容器停止时,相应的数据就会被移除。不举例了。 

  

三、数据卷容器

如果容器之间需要共享一些持续更新的数据,最简单的方式就是使用用户数据卷容器

其他容器通过挂载这个容器实现数据共享,这个挂载数据卷的容器就叫做数据卷容器

数据卷容器就是一种普通容器,它专门提供数据卷供其它容器挂载使用。

 

I.使用数据卷容器

创建数据卷容器,并在卷文件夹下创建一个文件  

[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]# ls
file.txt
[root@efdbc9a25138 sharedata]# cat file.txt 
I'm a VolumeContainer 

创建新的容器,使用刚刚创建的数据卷容器,需要使用的run参数是  --volumes-from 继承数据卷容器 IamVolumeContainer 挂载的数据卷  

[root@TBEARZ206458 ~]# docker run -it --volumes-from IamVolumeContainer --name shareContainer  centos /bin/bash
[root@d087086ada1a /]# cd sharedata/
[root@d087086ada1a sharedata]# ls
file.txt
[root@d087086ada1a sharedata]# echo "I'm sharecontainer1" > file2.txt 
[root@d087086ada1a sharedata]# ls
file.txt  file2.txt 

和上面一样创建新容器,查看是否有上两次创建的文件

[root@TBEARZ206458 ~]# docker run -it --volumes-from IamVolumeContainer --name shareContainer2  centos /bin/bash   
[root@d26d32b26060 /]# cd sharedata/
[root@d26d32b26060 sharedata]# ls
file.txt  file2.txt
[root@d26d32b26060 sharedata]# cat file2.txt 
I'm sharecontainer1
[root@d26d32b26060 sharedata]# echo "I'm sharecontainer2" > file3.txt
[root@d26d32b26060 sharedata]# ls
file.txt  file2.txt  file3.txt 

再回到原来的数据卷容器,可以发现文件被共享了

[root@TBEARZ206458 ~]# docker exec -it IamVolumeContainer /bin/bash   
[root@efdbc9a25138 /]# cd /sharedata/
[root@efdbc9a25138 sharedata]# ls
file.txt  file2.txt  file3.txt 

II.数据备份和还原

使用备份容器,备份数据

[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文件

 

[root@TBEARZ206458 ~]# cd /home/share/backup/
[root@TBEARZ206458 backup]# ls
backup.tar
[root@TBEARZ206458 backup]#  

使用恢复容器恢复数据

例如创建这样一个文件

[root@TBEARZ206458 recover]# pwd /home/share/recover 
[root@TBEARZ206458 recover]# ls recover.tar

创建一个恢复容器 

[root@TBEARZ206458 recover]# docker container run \
--volumes-from IamVolumeContainer \
-v /home/share/recover:/recover \
centos \
tar xvf /recover/recover.tar 
以下是执行
recover/
recover/readme.txt

 

posted @ 2020-03-10 19:20  奋斗的大橙子  阅读(255)  评论(0编辑  收藏  举报