Docker学习笔记十三:数据持久化-数据卷操作

在实际的生产环境中,数据的持久化是常见的操作。那么使用Docker如何实现数据持久化呢?数据卷是Docker容器对数据进行共享和持久化的方式之一。数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,其生命周期独立于容器本身。

dockerfile

FROM centos:7
VOLUME ["/usr/local"]

注意:在dockerfile里设置volume是无法修改宿主机的挂载路径的

创建一个数据卷

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/中)。

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

挂载数据卷

默认情况下,在创建数据卷时,会在宿主机中的/var/lib/docker/volume/下创建一个以“数据卷名”为名的目录,并将数据卷的内容保存在该目录下的/_data目录下。(也就是将数据卷的内容保存在/var/lib/docker/volume/数据卷名/_data/中),数据卷的内容会和容器的挂载点始终保持一致。“数据卷名”可以用户指定,如果不指定,就会随机生成一个“数据卷名”。
挂载宿主机目录
当然用户也可以指定宿主机具体目录作为数据卷的内容,挂载到容器的“挂载点”。如下所示:下面将宿主机的/host/dir挂载到了容器的/container/dir目录。

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

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

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

查看数据卷的具体信息

在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串,具体在这就不展开了。

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

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

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

删除数据卷

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

删除数据卷的三种方式

第一种方式: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,如果执行这条命令,那么会将所有没有被容器使用的数据卷删除掉。

备份一个数据卷

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

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

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

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。命令如下所示:

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

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

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

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

实例

  • 将名为vo1的数据卷备份;
  • 使用备份文件恢复vo1数据卷。
#!/bin/bash
#拉取ubutun 最新镜像,实际生产中,docker pull 这一步可以省略,docker run的时候会自己去拉取。
docker pull ubuntu
# 创建一个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 **********#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值