zoukankan      html  css  js  c++  java
  • 四、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
    

  • 相关阅读:
    UNIX网络编程--简介(一)【转】
    linux网络编程--网络编程的基本函数介绍与使用【转】
    微内核VS宏内核【转】
    Linux内核同步机制--自旋锁【转】
    多线程中的信号机制--signwait()函数【转】
    线程同步--递归锁和非递归锁【转】
    linux中线程池【转】
    多进程多线程优先级理解--优先级反转【转】
    【转】如何检测wifi信号强度? -- 不错
    【转】安卓手机有安全模式?安卓4.1安全模式介绍
  • 原文地址:https://www.cnblogs.com/dcz2015/p/12458005.html
Copyright © 2011-2022 走看看