1.8 存储基本配置
通过前面的学习,现在我们可以自己运行容器、打包制作镜像了。但是要真正在生产上运用Docker,还要学习数据卷的配置和Docker网络配置。
前面学习容器的时候,运行的是一些没有持久化数据存储的容器。也就是说,我们运行的容器能提供服务,但是服务生成的数据没有存到硬盘里。我们知道,有些服务是必须要有持久化功能的,比如数据库,用Docker运行一个MySQL的容器并且提供服务,那么数据需要有个地方存储,图1-48所示为给MySQL容器挂载数据卷(volume)。所以,我们要学习如何给容器挂载一块“硬盘”,让容器产生的数据有存储的地方。
图1-48 给MySQL容器挂载数据卷
如何给容器添加一块存放数据的“硬盘”呢?这就要用到容器的数据卷服务了。接下来我们从什么是数据卷、创建/挂载数据卷、共享和同步数据卷、备份和还原数据卷这4个方面进行讲解,帮助大家学习如何给容器挂载数据卷,让数据持久化。
1.8.1 什么是数据卷
1.为什么要用数据卷
数据卷的意义上面我们已经介绍了,就是为了让容器有持久化数据的功能,如果没有数据卷,就无法存储容器服务产生的数据。
2.数据卷的特点
我们一定要了解数据卷的特点,这样在日后的使用中才能灵活运用它。
1)在Dockerfile里可以指定数据卷(1.6.2节介绍过VOLUME指令)。
2)数据卷随着容器的启动开始初始化,如果镜像里面数据卷挂载点有数据,那么会通过COPY ON WRITE(写时复制)命令写到数据卷里。
3)数据卷里的内容可以直接修改,无论是在容器内操作还是在容器外操作,都会立即生效。
4)数据卷可以在容器之间共享和重用。也就是说,多个不同的容器可以同时使用一个数据卷(类似NFS共享)。
5)数据卷、容器、镜像都能独立存在。
6)挂载数据卷的容器如果被删除,数据卷还会存在,不会跟着容器一起删除。
1.8.2 创建、挂载数据卷
上面介绍了数据卷的作用和特点,接下来学习如何使用数据卷。给容器挂载数据卷的方法很简单,主要有3种:第一种是用docker volume命令创建并挂载;第二种是通过docker run命令里-v参数指定数据卷挂载路径;第三种就是我们之前讲过的,做镜像的时候在Dockerfile里用VOLUME指令设置好数据卷路径。
1.docker volume方式
通过docker volume命令可以创建、删除、罗列、查看数据卷。
首先创建一个数据卷。
$ docker volume create
运行命令后会在/var/lib/docker/volumes路径下创建一个随机命名的数据卷,如图1-49所示。
图1-49 创建随机命名的数据卷
当然,我们也可以给数据卷指定一个名字,只要在命令后面加一个--name即可,比如创建一个名为test的数据卷,如图1-50所示。
图1-50 创建名为test的数据卷
注意,创建好的数据卷其实就是一个文件夹。
创建好数据卷后,怎么给容器挂载呢?用-v参数即可做挂载操作。比如运行如下命令,把刚才创建的名为test的数据卷挂载到一个ubuntu容器里。
$ docker run -d -v test:/data ubuntu /bin/bash
这样创建好的test数据卷就挂载映射到容器的/data目录下了。如果想删除数据卷,直接运行docker volume rm+数据卷的名字或者ID即可。注意,这个数据卷在没有容器使用或占用时才能被成功删除。
如果想罗列出所有创建好的数据卷,直接运行docker volume ls命令即可,如图1-51所示。
图1-51 列出创建好的数据卷
如果想查看创建好的某个数据卷信息,直接运行docker volume inspect+数据卷的名字或者ID即可,如图1-52所示。
图1-52 查看数据卷信息
2.docker run-v方式
docker run -v 宿主机里绝对路径:容器里绝对路径 -it 镜像名 /bin/bash
docker run-v宿主机里绝对路径:容器里绝对路径-it镜像名/bin/bash
示例如下。
$ docker run -d \ -v /docker_volume/volume_01:/data -it hub.tecent.com/library/centos /bin/bash
1)-v:指定映射关系的参数。
2)/docker_volume/volume_01:宿主机里给容器存储数据设置的绝对路径,如果宿主机里不存在这个路径,运行命令后会自动创建一个。
3)/data:容器中存储数据的路径。通过这条命令让/data目录与/docker_volume/volume_01目录做映射,表面看数据是存放在/data下面,其实是存在/docker_volume/volume_01里,并且这里用的也是宿主机硬盘的IO。
运行上例中的docker run-v命令后,在容器里/data目录下创建一个test.txt文件存放数据。退出容器后,进入/docker_volume/volume_01,可以看到刚才在容器里创建的test.txt文件,它们是实时同步的。
3.用Dockerfile VOLUME命令指定数据卷路径
如果容器中事先用VOLUME命令指定好了挂载数据卷的路径,那么用这个镜像生成的容器就会自动挂载数据卷。容器里的路径就是VOLUME命令设置的那个路径,然后宿主机里会默认主机上有一个特定的区域(/var/lib/docker/volumes路径下)是用来存放数据卷的。在生成数据卷的时候如果不指定名称,便会随机命名。所以,这个目录下的名字都是随机的ID,类似于:
"/var/lib/docker/volumes/4ae9914bc4bd127e669b89ee6b703a0c9cc91f18c8dfe5034dbb838de2ca8062/_data"
这里要注意,如果用同一个镜像生成了两个容器,那么/var/lib/docker/volumes/路径下会随机生成两个不同的路径,分别对应这两个容器,也就是说不同的容器会对应不同的路径。
1.8.3 共享、同步数据卷
通过上文的学习,我们知道了如何挂载一个本地路径给容器使用。但是有种情况需要考虑到,那就是多个容器之间要共用一个路径以达到数据共享。多个容器挂载同一数据卷目录,如图1-53所示。
图1-53 多个容器挂载同一数据卷目录
我们可以通过--volumes-from参数实现共享数据卷,命令格式如下所示。
docker run --volumes-from 容器名
示例如下。
$ docker run -d -it --name docker2 --volumes-from docker1 ubuntu /bin/bash
命令说明如下。
1)docker2:要创建的容器名。
2)--volumes-from:指定数据卷的源Docker容器名,注意这里必须是容器名。
3)docker1:假设的已经创建好的容器,里面做好了数据卷的挂载。
如果有一个docker3容器也想使用docker1里的数据卷,运行同样的命令即可。
$ docker run -d -it --name docker3 --volumes-from docker1 ubuntu /bin/bash
这样docker2和docker3都使用docker1的数据卷了。
由此我们可以知道,数据卷共享其实是通过容器实现的,而不是在宿主机里创建目录,把数据卷同时挂载给多个容器。
必须通过一个容器作桥梁以共享数据卷,这个容器我们一般称为“数据卷容器”。因此,我们做数据卷共享时,要提前规划并生成共享数据卷容器。这个容器先挂载好数据卷,然后其他容器用--volumes-from参数来共享数据卷,执行如下三步运行。
$ docker run --name docker1 -v /data ubuntu echo "share data volume container" $ docker run -d -it --name docker2 --volumes-from docker1 ubuntu /bin/bash $ docker run -d -it --name docker3 --volumes-from docker1 ubuntu /bin/bash
注意,我们先给docker1映射好数据卷/data,接下来的docker2和docker3就直接使用docker1里的/data目录了,抽象出来如图1-54所示。
图1-54 多个容器抽象使用同一目录
1.8.4 备份、还原数据卷
前面我们讲解了创建、挂载、删除、查看数据卷的方法,接下来学习另两个很重要的操作,那就是数据卷的备份和还原。我们知道,数据是IT生产环境里非常重要的一部分,绝大多数的服务都是围绕着数据进行操作,数据就是核心!所以容器数据的备份和还原是非常重要的。
1.备份数据卷
我们同样用--volumes-from参数备份数据卷,然后结合数据卷容器就能达到备份数据卷的目的。推荐用这样的方式去备份数据卷,因为要备份的数据卷在这个数据卷容器里,所以我们针对这个数据卷容器操作即可。
我们引用上边创建好的docker1,通过下面的命令,备份套用即可。
$ docker run -it --volumes-from docker1 \ -v /var/lib/docker/volumes/test:/backup --name docker_backup \ --rm ubuntu tar cvf /backup/backup.tar /data
命令说明如下。
1)首先我们通过--volumes-from docker1指定了docker1的数据卷,这个命令的运行效果是创建一个临时容器docker_backup。
2)docker_backup容器同时挂载了两个数据卷,一个是来自docker1的共享数据卷(注意这个共享的数据卷就是我们要备份的/data目录),另外一个是挂载映射了宿主机的/var/lib/docker/volumes/test,容器内部是/backup目录。
3)docker_backup容器创建成功后,会将docker1的共享数据卷(也就是需要备份的/data目录)打成tar包备份到宿主机的/backup/backup.tar下。
4)注意命令里带了--rm参数,所以最后备份好数据就会删除这个docker_backup容器。
命令运行效果如图1-55所示。
图1-55 备份数据卷
如图1-55所示,我们在/var/lib/docker/volumes/test下能直接看到备份好的backup.tar。
有些读者可能会有疑问,这里为什么还要运行一个容器再做备份操作呢?虽然看上去有些麻烦,但这是最专业的备份数据卷方式。容器就是一个进程,运行一个容器就是运行一个备份进程,不会占用太多资源。
2.恢复数据卷
恢复数据卷也是通过--volumes-from命令实现的,创建一个临时容器就能恢复刚才备份好的backup.tar了。
我们参照下面的命令做恢复操作即可。
$ docker run -it --name docker_recover -v /data ubuntu /bin/bash $ docker run --rm --volumes-from docker_recover \ -v /var/lib/docker/volumes/test:/backup ubuntu tar xvf /backup/backup.tar -C /data
命令说明如下。
1)我们创建一个数据卷容器docker_recover,设置内部容器卷目录为/data。目的是把之前备份好的backup.tar数据恢复到docker_recover容器里。
2)临时创建一个容器,执行--volumes-from命令,这个临时容器挂载了docker_recover里的/data目录。
3)宿主机里的/var/lib/docker/volumes/test目录容器内部的目录/backup做映射,注意/var/lib/docker/volumes/test目录下有之前备份的backup.tar,所以这里一定要映射这个目录,这样这个临时容器的/backup目录里才有backup.tar。
4)容器里直接解压/backup下的backup.tar,并且把数据解压指定到容器里的/data目录下。注意,这个/data目录也是docker_recover容器里的数据卷。我们把文件解压到/data,那么docker_recover自然也有了要恢复的数据。
本节讲解了容器数据卷,它在一些需要持久化的容器服务里经常用到。这里我们着重了解数据卷的共享、备份和恢复操作。备份和恢复操作有点难度,大家最好动手实际操作一下,便于理解。