当前位置:   article > 正文

数据卷的相关命令_本关的任务是学习删除数据卷,要求学习这参照示例,将container1容器对应的数据卷删

本关的任务是学习删除数据卷,要求学习这参照示例,将container1容器对应的数据卷删

数据卷的相关命令

数据卷背景

在介绍VOLUME指令之前,我们来看下如下场景需求:

1)容器是基于镜像创建的,最后的容器文件系统包括镜像的只读层+可写层,容器中的进程操作的数据持久化都是保存在容器的可写层上。一旦容器删除后,这些数据就没了,除非我们人工备份下来(或者基于容器创建新的镜像)。能否可以让容器进程持久化的数据保存在主机上呢?这样即使容器删除了,数据还在。

2)当我们在开发一个web应用时,开发环境是在主机本地,但运行测试环境是放在docker容器上。

这样的话,我在主机上修改文件(如htmljs等)后,需要再同步到容器中。这显然比较麻烦。

3)多个容器运行一组相关联的服务,如果他们要共享一些数据怎么办?

对于这些问题,我们当然能想到各种解决方案。而docker本身提供了一种机制,可以将主机上的某个目录与容器的某个目录(称为挂载点、或者叫卷)关联起来,容器上的挂载点下的内容就是主机的这个目录下的内容,这类似linux系统下mount的机制。 这样的话,我们修改主机上该目录的内容时,不需要同步容器,对容器来说是立即生效的。 挂载点可以让多个容器共享。

 

在日常的docker使用情况中,我们可能有这样的一些需求:

  1. 是否可以在宿主机上,不启动容器,便能够直接访问甚至修改容器中的某些文件?
  2. 容器与容器之间是否可以数据共享?
  3. 可以使容器中的某些数据不随着容器的删除而随之删除吗?

    在Docker中提供了数据卷(Volume)机制,通过它可以完美地解决上述的问题。数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,并且有一些有用的特性。

    数据卷有以下的一些有用的特性:

  4. 数据卷可以在容器之间共享和重用
  5. 对数据卷的修改会立马生效
  6. 对数据卷的更新,不会影响镜像
  7. 数据卷的生命周期独立于容器的生命周期,它默认会一直存在,即使容器被删除。

    数据卷的实现原理

    在介绍数据卷的原理之前,我们先介绍Linux的挂载与特殊的"绑定挂载"。

    在Linux中,挂载通常是指将一个设备(通常是存储设备,例如光盘、U盘或者某个分区等)作为挂载点,挂载到某个目录上去。在Linux中,如果想要访问存储设备中的文件,那么必须先将存储设备挂载到Linux文件系统的某个目录上,然后才能通过访问这个目录来访问存储设备。

    "绑定挂载"是一种特殊的挂载方式,首先它与挂载不同,"绑定挂载"是将一个目录挂载到另外一个目录上。然后绑定挂载后的两个目录会在内容上保持完全一致,也就是说,对其中一个目录做出修改,也相当于对另外一个目录看做出了同样的修改。我们可以通过以下链接加深一下绑定挂载的理解:http://www.codeweblog.com/%E5%85%B3%E4%BA%8Emount-bind%E7%9A%84%E7%90%86%E8%A7%A3

    而Docker的数据卷机制其实是通过Linux系统的"绑定挂载"实现的。数据卷volume的本质是在容器的创建过程中,将宿主机的一个指定目录("数据卷"的内容将会保存在宿主机的这个目录)挂载到容器中某个目录(容器的这个目录也称之为"挂载点"),而这里用到挂载方法就是"绑定挂载"。

    从数据卷的原理看数据卷的应用场景

    由于在容器的创建过程中,可以一个宿主机的指定目录"绑定挂载"到指定容器的某个目录。而且"绑定挂载"之后容器内的目录会和宿主机的指定目录始终保持完全一致,所以上面的应用场景就很容易实现了。

    如果想要不启动容器,就访问或者修改容器中的某个目录,只需要创建一个数据卷,然后将数据卷挂载到容器的该目录即可了。由于数据卷的内容会和容器中该目录的内容始终保持一致,那么就可以访问或者修改"数据卷"其实也就是访问或修改"容器的对应目录"了。

    同理,如果想要实现容器间数据的共享,只要把"数据卷"挂载到不同容器的某个目录就行了,这样不同容器的指定目录的内容就会保持完全一致了。

    容器在删除的时候,只会将容器对应的可写层删除掉,而不会将"数据卷"删除掉。所以如果想在容器中删除时,某些数据能够保留下来,那么只需事先将"数据卷"挂载到容器的某个目录,然后将需要保留的数据复制到该目录中就可以了。这样这些数据就不会随着容器的删除而随之删除,它会保留在"数据卷"之中了。

     

    创建一个数据卷

    创建一个名为vo1的数据卷,并将该数据卷挂载到container1容器的/dir1目录。

    相关知识

    在阅读相关知识之前,请先阅读背景知识对数据卷有一定的了解。如果您能够看明白数据卷的原理,那么我相信接下来的学习会非常地轻松。如果看不懂也没有关系,让我们在学习中慢慢地加深理解。希望学习完这个实训,能让你对数据卷有一个全新的理解。

    创建一个数据卷

    Docker1.9版本以后,docker提供了一条新的命令:docker volume,用来创建、查看、删除数据卷。而传统的docker run -v创建一个数据卷的方式也仍然保留了下来。

    可以使用docker volume create创建一个数据卷,并指定数据卷的名字,如下所示:下面这条命令将创建了一个名为vo1的数据卷。

    (1)docker volume create --name vo1

    除此以外,还可以在创建新容器的时候,通过添加-v标签创建一个数据卷,如下所示:下面这条命令基于ubuntu进行创建并启动了一个容器,然后创建了一个"随机名字"的volume,并挂载到容器的/data目录。

    (2)docker run -itd -v /data ubuntu /bin/bash

    当然也可以在创建新容器的时候,指定数据卷的名字,如下所示:这个命令就创建了一个名为vo2的数据卷,并挂载到了容器的/data目录。

    (3)docker run -itd -v vo2:/data ubuntu /bin/bash

    之前我们说过,"数据卷"的内容会保存在宿主机的一个指定的目录上,默认情况下,在创建数据卷时,会在宿主机中的/var/lib/docker/volume/下创建一个以"数据卷名"为名的目录,并将数据卷的内容保存在该目录下的/_data目录下(也就是将数据卷的内容保存在/var/lib/docker/volume/数据卷名/_data/中)。

    在日常的工作中,我们一般不会用第一种方式来创建一个数据卷,因为一个没有被容器使用的数据卷显然意义是不大的。如果需要指定数据卷的名字,用第三种方式来创建就比较好了。

    前面说过,数据卷的内容会与容器的挂载点内容完全保持一致,大家可以在右侧命令行进行,加深对绑定挂载的理解。

    任务要求

    本关的编程任务是补全step1/createvolume.sh脚本文件的内容,要求实现创建一个数据卷。具体要求如下:

  • 创建一个名为vo1的数据卷,并将该数据卷挂载到container1容器的/dir1目录。

    本关涉及的代码文件step1/createvolume.sh的代码框架如下:

    #!/bin/bash

    #创建一个名为vo1的数据卷,并将该数据卷挂载到container1容器的/dir1目录。

    #********** Begin *********#

     

    docker run --name container1 -itd -v vo1:/dir1 ubuntu /bin/bash

     

    详细介绍

    一、通过docker run命令

    1、运行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash

    其中的 -v 标记 在容器中设置了一个挂载点 /data(就是容器中的一个目录),并将主机上的 /home/xqh/myimage 目录中的内容关联到 /data下。

    这样在容器中对/data目录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个目录实际都是指向主机目录。

    2、运行命令:docker run --name test1 -it -v /data ubuntu /bin/bash

    上面-v的标记只设置了容器的挂载点,并没有指定关联的主机目录。这时docker会自动绑定主机上的一个目录。通过docker inspect 命令可以查看到。

    xqh@ubuntu:~/myimage$ docker inspect test1

    [

    {

    "Id": "1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c",

    .............................

    "Mounts": [

    {

    "Name": "0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01",

    "Source": "/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data",

    "Destination": "/data",

    "Driver": "local",

    "Mode": "",

    "RW": true

    }

    ],

    ...........................

    上面 Mounts下的每条信息记录了容器上一个挂载点的信息,"Destination" 值是容器的挂载点,"Source"值是对应的主机目录。

    可以看出这种方式对应的主机目录是自动创建的,其目的不是让在主机上修改,而是让多个容器共享。

    二、通过dockerfile创建挂载点

    上面介绍的通过docker run命令的-v标识创建的挂载点只能对创建的容器有效。

    通过dockerfile VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。

    还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。

    #test

    FROM ubuntu

    MAINTAINER hello1

    VOLUME ["/data1","/data2"]

    上面的dockfile文件通过VOLUME指令指定了两个挂载点 /data1 /data2.

    我们通过docker inspect 查看通过该dockerfile创建的镜像生成的容器,可以看到如下信息

       

    "Mounts": [

    {

    "Name": "d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21",

    "Source": "/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data",

    "Destination": "/data1",

    "Driver": "local",

    "Mode": "",

    "RW": true

    },

    {

    "Name": "6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36",

    "Source": "/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data",

    "Destination": "/data2",

    "Driver": "local",

    "Mode": "",

    "RW": true

    }

    ],

    可以看到两个挂载点的信息。

    三、容器共享卷(挂载点)

    docker run --name test1 -it myimage /bin/bash

    上面命令中的 myimage是用前面的dockerfile文件构建的镜像。 这样容器test1就有了 /data1 /data2两个挂载点。

    下面我们创建另一个容器可以和test1共享 /data1 /data2 ,这是在 docker run中使用 --volumes-from标记,如:

    可以是来源不同镜像,如:

    docker run --name test2 -it --volumes-from test1  ubuntu  /bin/bash

    也可以是同一镜像,如:

    docker run --name test3 -it --volumes-from test1  myimage  /bin/bash

    上面的三个容器 test1 , test2 , test3 均有 /data1 /data2 两个目录,且目录中内容是共享的,任何一个容器修改了内容,别的容器都能获取到。

       

    四、最佳实践:数据容器

    如果多个容器需要共享数据(如持久化数据库、配置文件或者数据文件等),可以考虑创建一个特定的数据容器,该容器有1个或多个卷。

    其它容器通过--volumes-from 来共享这个数据容器的卷。

    因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。

    如: docker run --name dbdata myimage echo "data container"

       

    说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。这些内容后续文章介绍。

    五、特别说明

    挂载宿主机目录

    当然用户也可以指定宿主机具体目录作为数据卷的内容,挂载到容器的"挂载点"。如下所示:下面将宿主机的/host/dir挂载到了容器的/container/dir目录。

  1. docker run --name vocotainer1 -v /host/dir:/container/dir ubuntu
    							

    但是需要注意的是,宿主机的目录和容器的目录必须使用绝对路径。如果宿主机不存在/host/dir目录,则会创建一个空文件夹。在/host/dir下的所有文件和文件夹都可以在容器中在/container/dir下被访问。如果镜像中本来就存在/container/dir文件夹,那么该文件夹下所有内容都会被删除,保证与宿主机中文件夹一致

    同时创建多个数据卷

    当然在挂载的时候也可以同时创建多个数据卷,例如下面的命令就创建了两个数据卷:
    docker run --name vocotainer2 -v co2vo1:/data -v co21vo2:/dir1 ubuntu。同理一次指定多个宿主机的目录挂载到容器中也是可行的。

    与其他容器共享数据卷(--volumes-from)

    在使用docker run创建并启动一个新容器时,也可以使用--volumes-from标签使容器与已有的容器共享数据卷。

    如下所示,下面的命令创建了一个名为vocotainer3的容器,并与vocontainer1共享数据卷。因为vocontainer1的挂载点在/container/dir上,所以如果vocotainer3的挂载点也将会是/container/dir。

  2. docker run --name vocotainer3 -- volumes-from vocontainer1 ubuntu
    							

    通常如果有一些文件如果需要被多个容器共享,一种常见的做法就是创建一个数据容器(该容器仅仅用来共享数据而不做其他用途),其他容器与之共享数据卷。

    查看数据卷

    想象一下这样的场景,假设事先执行了docker run -v /data --name vocontainer1 ubuntu,由于-v标签没有指定"数据卷名",那么为数据卷会随机生成一个"数据卷名"。那我们如何知道vocontainer1对应的数据卷名是什么呢??

    本关任务是学习查看一个数据卷的信息,要求学习者参照示例,输出容器container1创建的数据卷的名字。

    相关知识

    查看数据卷的具体信息

    在Docker中可以通过docker inspect查看容器、镜像、数据卷等的具体信息,为了区分,所以最好指定具体类型为容器。通过--type参数可以指定具体类型,而--type container就是声明具体类型为容器。

    执行docker inspect --type container vocontainer1,执行结果如下所示(已经省略很多无关信息)

    从上图中我们可以了解到,vocontainer1的数据卷名为b892ce74e55fe1672ec0af69b93661384bbb8334922e1a47c42b122b5885cf0e,数据卷的内容保存在/var/lib/docker/volumes/b892ce74e55fe1672ec0af69b93661384bbb8334922e1a47c42b122b5885cf0e/_data中,挂载点为/data。数据卷内容可读写。

    仅查看数据卷的名字

    当然如果仅仅只想查看容器对应的volumeName可以通过以下命令获得,其中--format用来解析docker inspect输出的json串,具体在这就不展开了。有兴趣的同学可以深入研究。

    1. docker inspect --type container --format='{{range .Mounts}}{{.Name}}{{end}}' containerName|containerId

    例如,如果我想查看vocontainer1的数据卷名字,我可以执行以下命令:

    1. docker inspect --type container --format='{{range .Mounts}}{{.Name}}{{end}}' vocontainer1

    任务要求

    本关的编程任务是补全step3/infovolume.sh脚本文件的内容,要求实现查看一个数据卷的信息。具体要求如下:

  • 输出容器container1创建的数据卷的名字

    本关涉及的代码文件step3/infovolume.sh的代码框架如下:

    #创建一个容器,并创建一个随机名字的数据卷挂载到容器的/data目录

    docker run --name container1 -v /data ubuntu

    #输出容器container1创建的数据卷的名字

    #********** Begin *********#

    docker inspect --type container --format='{{range .Mounts}}{{.Name}}{{end}}' container1

    #********** End **********#

     

    删除数据卷

    数据卷是被设计用来持久化数据的,它的生命周期独立于容器,如果在创建容器时挂载了数据卷,执行docker rm删除容器时,并不会自动地将容器对应的数据卷删除掉。在Docker中也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。

    本关的任务是学习删除数据卷,要求学习这参照示例,将container1容器对应的数据卷删除掉。

    相关知识

    删除数据卷的三种方式

    第一种方式:docker volume rm volumeName

    如果知道想要删除的数据卷的名字,那么可以直接使用这种方式去删除一个数据卷,但是只会尝试地去删除数据卷,如果该数据卷还被容器使用,那么将删除不成功,但是如果这个数据卷已经不被任何容器所使用了,那么数据卷将会被删除。

    第二种方式:docker rm -v containerId|containerName

    在删除容器时如果想要将容器对应的数据卷也同时删除掉,可以使用指定-v标签,但是值得注意的是,这种方法也只会尝试地去删除容器对应的数据卷,如果该数据卷还被其他容器使用,那么将删除不成功,但是如果这个数据卷已经不被任何其他容器所使用了,那么数据卷将会被删除。

    如果是docker run -v /data --name container1 ubuntu创建的数据卷(没有显示指定数据卷名),如果该数据卷没有被其他任何容器使用,那么在使用docker rm -v container1尝试删除container1容器以及对应的数据卷时,会把数据卷删除掉。

    但是如果用docker run -v vo1:/data --name container1 ubuntu创建的数据卷(显示指定数据卷名),也就是创建时指定了"数据卷名",那么在使用docker rm -v container1尝试删除容器以及对应的数据卷时,不会将数据卷删除,只是解除了数据卷和容器的联系。如果要删除数据卷,还得在上述基础上,继续使用docker volume rm vo1

    第三种方式:在创建容器时指定--rm标签

    如果在创建容器时指定了--rm标签,那么在容器处于"终止状态"时就会删除容器以及尝试删除容器所对应的数据卷。当然在删除容器对应的数据卷时,如果没有指定了数据卷名,那么将删除对应的数据卷。如果指定了数据卷名,也只是解除了数据卷和容器的联系,真正要删除,还得执行docker volume rm

    删除无用的数据卷

    在我们的工作中难免在删除容器时忘记删除了数据卷,当然我们可以通过docker volume rm一条条地尝试的去删除。但是docker提供了更加简便的方法。也就是:docker volume prune,如果执行这条命令,那么会将所有没有被容器使用的数据卷删除掉。

    docker volume prune

    任务要求

    本关的编程任务是补全step4/rmvolume.sh脚本文件的内容,要求实现删除一个数据卷。具体要求如下:

  • 将container1容器对应的数据卷删除掉。

    本关涉及的代码文件step4/rmvolume.sh的代码框架如下:

    #!/bin/bash

    #创建一个名为container1的容器,创建一个数据卷挂载到容器的/data目录

    docker run -v vo4:/data --name container1 ubuntu

    #删除container1对应的数据卷

    #********** Begin *********#

    docker rm -v container1

    docker volume rm vo4

     

    #********** End **********#

     

    备份与恢复数据卷

    备份一个数据卷

    首先创建一个容器vocontainer1,并创建了一个名为db1的数据卷,将数据卷挂在到容器的/dbdate目录

  1. docker run -v db1:/dbdate --name vocontainer1 ubuntu
    							

    下面开始备份一个数据卷。首先进入一个空白目录,使用--volumes-from创建一个新容器,这样新容器与dbcontainer1容器共享dbdata挂载目录,同时把主机上的当前目录挂载到容器的 /backup 目录。命令如下:

  2. docker run --volumes-from dbcontainer1 -v $(pwd):/backup ubuntu tar -cvf /backup/backup.tar /dbdata
    							

    容器启动后,使用了tar 命令来将 dbdata目录压缩,并保存在 /backup/backup.tar文件中,由于主机的当前目录挂载在容器的/backup目录下,而绑定挂载的两个目录的内容完全保持一致,所以相当于将dbcontainer1数据卷的内容压缩后备份到了宿主机的当前目录了

    恢复一个数据卷

    假设一不小心名为db1的数据卷给删除掉了,可以这么恢复:

    首先创建一个带有空数据卷的容器dbcontainer2,挂载目录为/dbdata,数据卷名为db1。命令如下所示:

  3. docker run -v db1:/dbdata --name dbcontainer2 ubuntu /bin/bash
    							

    然后进入之前保存backup.tar的宿主机目录,在该目录下执行下面命令,该命令创建一个新容器,新容器与dbcontainer2容器共享dbdata挂载目录,同时将主机的当前目录挂载的容器的/backup中。

  4. docker run --volumes-from dbcontainer2 -v $(pwd):/backup busybox tar -xvf /backup/backup.tar -C /dbdata
    							

    启动容器时,使用tar命令将数据卷的备份文件backup.tar解压到/dbdata目录,由于该容器与dbcontainer2容器共享一个数据卷,也就相当于将backup.tar解压到了dbcontainer2/dbdata目录。
    又因为
    dbcontainer2将名为db1的数据卷挂载到了/dbdata上,所以实质上就将db1的数据卷内容完全恢复了!

    任务要求

    本关的编程任务是补全step5/reback.sh脚本文件的内容,要求实现备份和恢复数据卷。具体要求如下:

  • 将名为vo1的数据卷备份
  • 使用备份文件恢复vo1数据卷

    本关涉及的代码文件step5/reback.sh的代码框架如下:

     

    #!/bin/bash

    # 创建一个vo1的数据卷,并在数据卷中添加1.txt文件

    docker run --name vocontainer1 -v vo1:/dir1 ubuntu touch /dir1/1.txt

    #1.将vo1数据卷的数据备份到宿主机的/newback中,将容器的/backup路径挂载上去,并将容器内/dir1文件夹打包至/backup/backup.tar

    #********** Begin *********#

    docker run --volumes-from vocontainer1 -v /newback:/backup ubuntu tar -cvf /backup/backup.tar /dir1

     

    #********** End **********#

    #删除所有的容器以及它使用的数据卷

    docker rm -vf $(docker ps -aq)

    docker volume rm vo1

    #在次创建一个vo1的数据卷

    docker run -itd --name vocontainer2 -v vo1:/dir1 ubuntu /bin/bash

    #2.将保存在宿主机中备份文件的数据恢复到vocontainer2的/中

    #********** Begin *********#

    docker run --volumes-from vocontainer2 -v /newback:/backup ubuntu tar -xvf /backup/backup.tar -C /

     

     

    #********** End **********#

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/284017
推荐阅读
相关标签
  

闽ICP备14008679号