Docker容器数据持久化和数据共享
1. 概述
docker 主要有两种数据存储形式, 一种是storage driver(也叫做 Graph driver), 另一种是 volume driver。 stroage driver主要是存储那些无状态的数据,写入密集型的场景应该使用 volume driver。
2. storage driver
容器运行的文件系统是镜像层和容器层组成的,一层一层叠加,只有最上面的那层是可写的,其他层都是只读的。 Docker通过Union FS技术支持文件的读写和新建,Docker 采用插件式的方式支持多种Union FS实现,官方文档中一般使用stroage driver术语,目前已经有多种实现的插件, 比如: aufs、overlay、overlay2、devicemanger等等。
boot2docker 缺省使用的storage-driver 为 aufs,下面命令将创建一个使用 overlay2 的 storage driver docker运行环境。
docker-machine create --driver virtualbox --engine-storage-driver overlay2 test2
正式的docker 环境, 需要修改 /etc/docker/daemon.json 文件
{
"storage-driver": "btrfs"
}
几个查询storage driver的命令:
- docker info:查询docker运行环境使用的storage-driver
- docker image inspect:查看镜像使用的存储driver
- docker container inspect :查看容器使用的存储driver
3.volume driver
volume driver 经常用来实现数据持久化和文件共享功能, 具体有两种存在方式,分别是:
3.1 bind mount方式
是将host的目录或文件直接mount到容器中, host的目录或文件既可以容器运行之前就已存在的,也可以是在容器运行之前不存在的。
如果在docker run 命令中采用了 -v /host/dir_or_file:/container/dir_or_file的形式, 就是bind mount方式,即指定了host的挂载点的绝对路径。
3.2 volume方式
是由 Docker 管理,该volume最终存储到host的 /var/lib/docker/volumes 下。 volume 方式还分为 named volume 和 Anonymous volume。named volume 有两种创建方法:
- docker run命令中采用了 -v one_volume_name:/container/dir_or_file,这里的one_volume_name不是host中的绝对路径,而是一个名称。
- 通过 docker volume create 创建的,该命令支持更多的选项, 推荐使用。
匿名volume方式 是通过 docker run 命令中传入了 -v /container/dir 类型的参数。
3.3 bind mount和volume对比
-
1)bind mount方式, docker容器直接访问host的目录或文件,性能是最好的。
-
2)bind mount方式, docker容器直接访问host的目录或文件,对于该host绝对目录可能会引入权限问题。 如果容器仅需要只读访问权限,最好是显式设定只读方式。
-
3)对于 volume方式, 如果host中落地目录为空, docker先将容器中的对应目录复制到host下, 然后再进行挂载操作;对于bind mount方式,挂载之前没有复制操作。
容器要依赖host主机的一个绝对路径, 使得容器的移植性变差, docker 官方并不推荐bind mount, 而是推荐使用volume。
几个示例说明
#创建了一个named volume, 该volume 在 /var/lib/docker/volume/myetc 下.
docker run -d --name web0 -v myetc:/etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#创建了一个匿名的volume, 该volume在/var/lib/docker/volume父目录下, 具体子目录不确定,
#比如 /var/lib/docker/volume/9170d32e15b7578240afde81d5514637beece7d469b7ea253e23759a23b0a397
docker run -d --name web1 -v /etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#使用 bind mount 方式, host上的目录为 /etc2
docker run -d --name web2 -v /etc2:/etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
docker run 命令的–volume 和 --mount 参数
–volume 和 --mount 两种参数写法都支持上述volume和bind mount方式, --mount 采用key-value的写法, 支持更多的设置选项, docker 新版更加推荐使用 --mount 参数写法,但 --volume 写法更加简洁,仍然给广泛使用。
另一种推荐的volume写法是, 显式地使用 docker volume create 命令创建 named volume。
有了上面的知识,很容易就能实现容器和Host之间共享数据。对于同一Host下多个容器共享数据,直接docker run -v参数非常不方便, 最好是使用 data container作为桥梁。一般data container 不启任何应用,也不需要将容器真正运行起来,仅仅是挂载一下 volume, data container除了用于多个容器之间数据共享之外,也可用于volume的备份和恢复。
data container和volume的备份恢复
#创建一个名 为 dbstore 的数据容器, 设置一个匿名的/dbdata volume.
docker create -v /dbdata --name dbstore busybox /bin/sh
#创建一个名为 web3 的应用容器, 将 dbstore 数据容器的volume 挂载过来.
docker run -d --name web3 --volumes-from dbstore busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#备份数据容器 dbstore 的/dbdata目录到容器到host的host_backup目录下, 最终在host上的文件名为 /host_backup/backup.tar
docker run --rm --volumes-from dbstore -v /host_backup:/backup busybox tar -cvf /backup/backup.tar /dbdata
#恢复数据容器dbstore 的/dbdata目录, 数据源为host上的文件 /host_backup/backup.tar
docker run --rm --volumes-from dbstore -v /host_backup:/backup busybox /bin/sh -c "cd /dbdata && tar -xvf /backup/backup.tar --strip 1"
docker的容器设计理念是可以即开即用,用完可以随意删除,而新建容器是根据镜像进行渲染,容器的修改是不会影响到镜像,但是有时候容器里面运行的产生的数据(如mysql)或者配置项(如nginx的nginx.conf)我们又需要保存起来的,因而我们需要对容器某些修改的数据进行挂载,也就是把这些数据持久化。