Docker 为容器提供了两种存放数据的资源:

1.storage driver 管理的镜像层和容器层。

2.Data Volume

3.storage driver 和 data volume 是容器存放数据的两种方式

1. storage driver

docker mpi容器 每天5分钟玩转docker容器技术_数据库

容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中。这样的分层结构最大的特性是 Copy-on-Write:

1.新数据会直接存放在最上面的容器层

2.修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。

3.如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。

分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于 Docker storage driver。正是 storage driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。

Docker 支持多种 storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它们都能实现分层的架构,同时又有各自的特性。对于 Docker 用户来说,具体选择使用哪个 storage driver 是一个难题,因为:

1.没有哪个 driver 能够适应所有的场景。

2.driver 本身在快速发展和迭代。

不过 Docker 官方给出了一个简单的答案:优先使用 Linux 发行版默认的 storage driver

Docker 安装时会根据当前系统的配置选择默认的 driver。默认 driver 具有最好的稳定性,因为默认 driver 在发行版上经过了严格的测试。

运行docker info查看 Ubuntu 的默认 driver,下图只截取了部分信息:

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_02

Ubuntu 用的 AUFS,底层文件系统是 xfs,各层数据存放在 /var/lib/docker/aufs。

Redhat/CentOS 的默认 driver 是 Device Mapper,SUSE 则是 Btrfs。

对于某些容器,直接将数据放在由 storage driver 维护的层中是很好的选择,比如那些无状态的应用。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建。

比如 busybox,它是一个工具箱,我们启动 busybox 是为了执行诸如 wget,ping 之类的命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除,这没问题,下次再启动新容器即可。

但对于另一类应用这种方式就不合适了,它们有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的。

这就要用到 Docker 的另一种存储机制:Data Volume

2. Data Volume

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。Data Volume 有以下特点:

1.Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。

2.容器可以读写 volume 中的数据。

3.volume 数据可以被永久的保存,即使使用它的容器已经销毁。

好,现在我们有数据层(镜像层和容器层)和 volume 都可以用来存放数据,具体使用的时候要怎样选择呢?考虑下面几个场景:

1.Database 软件 vs Database 数据

2.Web 应用 vs 应用产生的日志

3.数据分析软件 vs input/output 数据

4.Apache Server vs 静态 HTML 文件

相信大家会做出这样的选择:

1.前者放在数据层中。因为这部分内容是无状态的,应该作为镜像的一部分。

2.后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开存放

还有个大家可能会关心的问题:如何设置 voluem 的容量?

因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。

docker 提供了两种类型的 volume:bind mount 和 docker managed volume

a) Bind mount

bind mount 是将 host 上已存在的目录或文件 mount 到容器。

例如 docker host 上有目录 $HOME/htdocs/index.html:

docker mpi容器 每天5分钟玩转docker容器技术_数据库_03

通过 -v 将其 mount 到 httpd 容器:

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_04

-v 的格式为 <host path>:<container path>。/usr/local/apache2/htdocs 就是 apache server 存放静态文件的地方。由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host $HOME/htdocs/ 中的数据,这与 linux mount 命令的行为是一致的。

docker mpi容器 每天5分钟玩转docker容器技术_docker_05

docker mpi容器 每天5分钟玩转docker容器技术_数据库_06


 


 

docker mpi容器 每天5分钟玩转docker容器技术_docker_07

可以看到本地的/root/htdocs/目录中的信息映射到了container目录当中;

b) Bind数据持久性

1) 在容器中添加内容

进入容器当中进行对/usr/local/apache2/htdocs/当中添加信息,例如创建文件或目录,是否会在host主机端存在?

答案:可以的,当把容器停止/删除也会永久存储

docker mpi容器 每天5分钟玩转docker容器技术_docker_08

 

2) 在host主机中添加内容

docker mpi容器 每天5分钟玩转docker容器技术_运维_09

docker mpi容器 每天5分钟玩转docker容器技术_数据库_10

 

docker mpi容器 每天5分钟玩转docker容器技术_docker_11

 

docker mpi容器 每天5分钟玩转docker容器技术_运维_12

 

创建文件

docker mpi容器 每天5分钟玩转docker容器技术_运维_13

进入容器查看

docker mpi容器 每天5分钟玩转docker容器技术_docker_14

 

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_15


 

 

3) 容器销毁看看对数据有什么影响

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_16

 

docker mpi容器 每天5分钟玩转docker容器技术_运维_17


 

docker mpi容器 每天5分钟玩转docker容器技术_docker_18

可见,即使容器没有了,bind mount 也还在。这也合理,bind mount 是 host 文件系统中的数据,只是借给容器用用,哪能随便就删了啊。

 

4) 对映射文件的读写(默认可读可写)

另外,bind mount 时还可以指定数据的读写权限,默认是可读可写,可指定为只读:

docker mpi容器 每天5分钟玩转docker容器技术_数据库_19

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_20

 

docker mpi容器 每天5分钟玩转docker容器技术_运维_21

 

1.对container文件进行读测试

docker mpi容器 每天5分钟玩转docker容器技术_数据库_22

 

可以发现读,没有问题

2.对container文件进行写测试

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_23

 

可以发现写操作也没有问题

3.对host中的文件写,对container中文件产生什么效果?

l host端进行数据追加

docker mpi容器 每天5分钟玩转docker容器技术_数据库_24


 

l Container端进行信息查看

docker mpi容器 每天5分钟玩转docker容器技术_docker_25


 

可以发现host端更改之后主机端信息也发生了改变。

5) 把相同目录挂载给多个container

l 新建container【test_volume_bind_RO】并挂载/root/docker_file/,并且进行写入操作

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_26

l 在container【test_volume_bind】中查看信息

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_27


 

由此可见通过Bind方式可以将相同的信息挂载多个container中。

 

 

6) 以只读方式挂载

docker run -it --name test_volume_bind_readonly -v /root/docker_file/:/root/docker_file/:ro centos

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_28

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_29

 

docker mpi容器 每天5分钟玩转docker容器技术_数据库_30

 

通过上图结果可以看出来,无法进行写入操作。

 

c) Bind mount小结

使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录 bind mount 给容器。

mount point 有很多应用场景,比如我们可以将源代码目录 mount 到容器中,在 host 中修改代码就能看到应用的实时效果。再比如将 mysql 容器的数据放在 bind mount 里,这样 host 可以方便地备份和迁移数据

bind mount 的使用直观高效,易于理解,但它也有不足的地方:bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。

d) docker managed volume

1) Docker manager volume基本用法

docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了。

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_31

当-d和-it参数同时使用时就不会exited

通过 -v 告诉 docker 需要一个 docker manager volume,并将其 mount 到 /root/docker_file/

进入container查看是否挂载成功

docker mpi容器 每天5分钟玩转docker容器技术_运维_32


 

可以看到container中有/root/docker_file目录,说明挂载是没有问题的;那另一个问题来了,挂载的docker manager volume是哪里来的呢?

通过docker inspect命令进行对container【test_data_volume】查看

docker mpi容器 每天5分钟玩转docker容器技术_运维_33

其中有很多信息,我们查看Mounts部分

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_34

 

Source项就是我们的docker manager volume的地址

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

可见docker会在/var/lib/docker/volumes/目录下生成,那之后的c2f90b8dfb7cd756f7b733fcf448911d08588a87eea52d24084a0674dfe4281f/_data目录又是什么意思呢?在container中创建文件进行测试

docker mpi容器 每天5分钟玩转docker容器技术_运维_35

 

docker mpi容器 每天5分钟玩转docker容器技术_docker_36


 

l 在host中目录查看

docker mpi容器 每天5分钟玩转docker容器技术_运维_37

 

可以看到数据实际是放到了/var/lib/docker/volumes/c2f90b8dfb7cd756f7b733fcf448911d08588a87eea52d24084a0674dfe4281f/_data的目录中的

/var/lib/docker/volumes这个目录是docker所有docker manager volume存放目录

c2f90b8dfb7cd756f7b733fcf448911d08588a87eea52d24084a0674dfe4281f是container的docker manager volume

_data是 docker manager volume创建的,最终给container存放数据

再通过一个实验进一步了解docker manager volume

2) Docker manager volume高级用法

上个实验中是将docker manager volume挂载到了container中的空目录中,那如果挂载到非空目录中是什么情况?

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_38

docker mpi容器 每天5分钟玩转docker容器技术_数据库_39

 

Container创建成功,说明挂载没有问题。

l 进入容器查看/etc/sysconfig/目录下内容

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_40


 

可以看到/etc/sysconfig/目录下有内容

l 在host中查看信息

通过docker inspect查看容器使用的是哪个docker manager volume

docker inspect test_data_volume01

docker mpi容器 每天5分钟玩转docker容器技术_运维_41

5fbfbccdae98095f420ba2d62607e42a0d08a211f4004c236159da214129f74b

docker mpi容器 每天5分钟玩转docker容器技术_数据库_42

可以发现container中的目录下的内容映射到了主机中

注意:当使用docker manager volume映射给container中的目录,目录中有信息,那么会把当前目录中的信息复制到docker manager volume

e) Bing mount与docker manager volume对比

docker mpi容器 每天5分钟玩转docker容器技术_数据库_43

f) 数据共享

1) Host与constainer共享数据

两种类型的 data volume,它们均可实现在容器与 host 之间共享数据,但方式有所区别。

对于 bind mount 是非常明确的:直接将要共享的目录 mount 到容器。具体请参考前面 httpd 的例子,不再赘述。

docker managed volume 就要麻烦点。由于 volume 位于 host 中的目录,是在容器启动时才生成,所以需要将共享数据拷贝到 volume 中。请看下面的例子:

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_44

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_45

 

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_46

 

当前container中没有/root/docker_file/目录,所以无法复制

在container中建立相应的目录

docker mpi容器 每天5分钟玩转docker容器技术_docker_47

docker mpi容器 每天5分钟玩转docker容器技术_数据库_48

在host中继续进行复制

docker mpi容器 每天5分钟玩转docker容器技术_运维_49


 

在container中查看

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_50


 

docker cp 可以在容器和 host 之间拷贝数据,当然我们也可以直接通过 Linux 的 cp 命令复制到 /var/lib/docker/volumes/xxx。

2) 容器之间共享数据-Bind mount

l 新建container【test_volume_bind_RO】并挂载/root/docker_file/,并且进行写入操作

docker mpi容器 每天5分钟玩转docker容器技术_运维_51

l 在container【test_volume_bind】中查看信息

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_52

由此可见通过Bind方式可以将相同的信息挂载多个container中。

3) 容器之间共享数据-volume container

volume container 是专门为其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume。下面我们创建一个 volume container:

docker mpi容器 每天5分钟玩转docker容器技术_数据库_53

我们将容器命名为 VC_data(VC 是 volume container 的缩写)。注意这里执行的是 docker create 命令,这是因为 volume container 的作用只是提供数据,它本身不需要处于运行状态。容器 mount 了两个 volume:

1.bind mount,存放 web server 的静态文件。

2.docker managed volume,存放一些实用工具(当然现在是空的,这里只是做个示例)。

通过 docker inspect 可以查看到这两个 volume。

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_54

 

其他容器可以通过 --volumes-from 使用 VC_data 这个 volume container:

docker mpi容器 每天5分钟玩转docker容器技术_数据库_55

三个 httpd 容器都使用了 vc_data,看看它们现在都有哪些 volume,以 web01 为例:

docker inspect web01

docker mpi容器 每天5分钟玩转docker容器技术_数据库_56

 

进入容器验证bind mount与manger volume是否挂载成功

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_57


 

Web01 容器使用的就是 vc_data 的 volume,而且连 mount point 都是一样的。验证一下数据共享的效果:

l Host操作

docker mpi容器 每天5分钟玩转docker容器技术_数据库_58

 

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_59

 

docker mpi容器 每天5分钟玩转docker容器技术_运维_60

 

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_61


 

l Container【web01】验证

docker mpi容器 每天5分钟玩转docker容器技术_docker_62

 

l Container【web02】验证

docker mpi容器 每天5分钟玩转docker容器技术_数据库_63


 

l Container【web03】验证

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_64


 

l Host验证

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_65

 

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_66

 

可见,三个容器已经成功共享了 volume container 中的 volume。

 

总结:

1.与 bind mount 相比,不必为每一个容器指定 host path,所有 path 都在 volume container 中定义好了,容器只需与 volume container 关联,实现了容器与 host 的解耦。

2.使用 volume container 的容器其 mount point 是一致的,有利于配置的规范和标准化,但也带来一定的局限,使用时需要综合考虑。

4) 容器之间共享数据-data-packed volume container

在上一节的例子中 volume container 的数据归根到底还是在 host 里,有没有办法将数据完全放到 volume container 中,同时又能与其他容器共享呢?

当然可以,通常我们称这种容器为 data-packed volume container。其原理是将数据打包到镜像中,然后通过 docker managed volume 共享。

用下面的 Dockfile 构建镜像:

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_67

 

docker mpi容器 每天5分钟玩转docker容器技术_docker mpi容器_68

 

docker mpi容器 每天5分钟玩转docker容器技术_数据库_69

 

docker mpi容器 每天5分钟玩转docker容器技术_docker_70

 

docker mpi容器 每天5分钟玩转docker容器技术_数据库_71

 

docker mpi容器 每天5分钟玩转docker容器技术_docker_72

 

ADD 将静态文件添加到容器目录 /usr/local/apache2/htdocs。
VOLUME 的作用与 -v 等效,用来创建 docker managed volume,mount point 为 /usr/local/apache2/htdocs,因为这个目录就是 ADD 添加的目录,所以会将已有数据拷贝到 volume 中。 

build 新镜像 datapacked:

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_73

 

docker mpi容器 每天5分钟玩转docker容器技术_运维_74

 

docker mpi容器 每天5分钟玩转docker容器技术_操作系统_75


 

l 运行另一个容器进行验证

docker mpi容器 每天5分钟玩转docker容器技术_docker_76


 

docker mpi容器 每天5分钟玩转docker容器技术_运维_77


 

docker mpi容器 每天5分钟玩转docker容器技术_数据库_78


 

容器能够正确读取 volume 中的数据。data-packed volume container 是自包含的,不依赖 host 提供数据,具有很强的移植性,非常适合 只使用 静态数据的场景,比如应用的配置信息、web server 的静态文件等。