现在是数据的时代,数据的重要性不言而喻,因此在使用docker的过程中,如何存储其产生的数据就是docker的重中之中,现在我们就一起来看看docker是怎么存储数据的。
数据卷及挂载
volume(数据卷): 其由docker自身创建与管理,用于docker数据的持久化与容器间数据共享。
Bind mounts(挂载): 使用-v或–mount进行引用宿主机上已经存在的目录或文件,用于docker数据的持久化与容器间数据共享。
tmpfs mounts(tmpfs挂载): 用于存储程序运行中产生的临时数据,数据保存在主机内存中。Linux系统下专用
优缺点
volume
1、管理更方便,可以使用docker的CLI与API进行管理
2、不需要docker主机必须具有给定的目录或文件结构
3、迁移更加方便
3、数据卷可以存储在远程主机或云上
4、swarm下共享数据更加方便
bind mounts
1、只需要挂载文件时,更加方便
2、当确保Docker主机的文件或目录结构与容器所需的绑定挂载一致时。
tmpfs mounts
1、存储敏感临时数据
2、容器停止,tmpfs挂载被删除
存储驱动
容器和镜像
介绍驱动之前,我们先介绍以下docker的容器与镜像。
镜像: 由一层层的只读的文件系统(镜像)组成,在Dockerfile中,每一个RUN命令都会创建一层镜像。每一层的生成都是在上一层的基础之上有了其他改变后生成的,镜像都是只读的。
容器: 创建容器时,在镜像之上在创建一层可写层(可写文件系统),通常称为“容器层”,在容器层中做出的任何操作不会改变基础镜像,容器停止,容器层也会随之删除。
写时复制策略
Docker使用存储驱动程序来管理图像层和可写容器层的内容。每个存储驱动程序对实现的处理方式不同,但是所有驱动程序都使用可堆叠的图像层和写时复制(CoW)策略。
读取: 如果文件位于底层,从可写层需要读取文件,其会一层一层的向下查找文件,并读取找到的第一个文件。此时文件位置不变,容器体积不会增加。
第一次写操作: 如果文件位于底层,从可写层读取文件,其会一层一层的向下查找文件,并把找到的第一个文件复制到可写层,再修改文件,修改的文件是可写层的文件,此时文件变为两个,并且容器体积增大。
驱动底层支持及选择
存储驱动根据操作系统底层的支持提供了针对某种文件系统的初始化操作以及对镜像层的增、删、改、查和差异比较等操作。目前存储系统的接口已经有 aufs、btrfs、devicemapper、voerlay2 等多种。在启动 docker deamon 时可以指定使用的存储驱动,当然指定的驱动必须被底层操作系统支持。
Linux发行版 | 推荐驱动 | 备选驱动 |
---|---|---|
Docker Engine-Ubuntu上的社区 | overlay2或aufs(对于在内核3.13上运行的Ubuntu 14.04) | overlay¹,devicemapper² zfs,vfs |
Docker Engine-Debian上的社区 | overlay2(Debian Stretch)aufs或devicemapper(旧版本) | overlay¹, vfs |
Docker Engine-CentOS上的社区 | overlay2 | overlay¹,devicemapper² zfs,vfs |
Docker Engine-Fedora上的社区 | overlay2 | overlay¹,devicemapper² zfs,vfs |
docker文件系统 | 宿主机文件系统 | 备注 |
---|---|---|
overlay2 (overlay) | xfs 且ftype = 1, ext4 | Linux内核4.0(3.18)及以上,docker版本17.06.02及以上(推荐使用) |
aufs | xfs, ext4 | 内核需支持aufs |
devicemapper | direct-lvm | |
btrfs | btrfs | CE版本仅在ubuntu和Debian,EE版仅在SLES |
zfs | zfs | 必需块设备 |
vfs | 任何文件系统 |
驱动详解
aufs
联合文件系统,即把多个目录mount为同一个目录,可以在多个运行的容器中高效的共享image,可以实现容器的快速启动,减少磁盘占用量;但如果文件过大或文件位于底层时,可能会引入高延迟。Docker 18.06以下版本运行在Ubuntu 14.04以及kernel 3.13上,不支持overlay2,首选aufs。
如内核不包含aufs,请阅览“centos内核升级之安装aufs”。
1、文件或目录位于底层
读取: 从可写层向下查找文件,并读取找到的第一个文件,文件位置不变。容器体积不变,文件个数不变。
删除: 在可写层创建whiteout文件,底层的文件不会被删除,但因为whiteout文件的存在,因此该文件对于容器而言是不可见的。文件个数不变。
写操作: 从可写层向下查找文件,并将找到的第一个文件复制到可写层,再对复制的文件进行写操作。文件个数改变,容器体积明显增大。
2、文件或目录位于容器
直接进行相关操作。
overlay2
与aufs类似,但性能更强。Docker优先采用的存储驱动,对于已支持该驱动的Linux发行版,不需要任何进行任何额外的配置。
如centos内核较低,请预览“centos内核升级”。
devicemapper
驱动存储每个镜像和容器到它自己的虚拟设备上。这些设备是精简置备写时拷贝快照设备。Device Mapper技术工作在块级别而不是文件级别。意味着devicemapper存储驱动的精简置备和写时拷贝操作的是块而不是整个文件。
默认的配置模式是loopback-lvm,但是在生产环境时Docker不推荐这种模式,它的性能非常差,我们需要将其配置成direct-lvm。 对于早期的CentOS和RHEL,devicemapper是推荐的存储驱动,因为它们对应的内核版本不支持overlay2,不过,我们现在版本的CentOS与RHEL均已支持overlay2。
btrfs and zfs
Docker安装所在的宿主机文件系统是btrfs或者zfs,则Docker优先使用它们作为存储驱动,这些文件系统具有一些高级的选项配置,这些功能包括块级操作,自动精简配置,写时复制快照和易于管理。
vfs
VFS存储驱动程序不是联合文件系统。相反,每一层都是磁盘上的目录,并且不支持写时复制。要创建新层,需要对上一层进行“深层复制”。与其他存储驱动程序相比,这导致较低的性能和更多的磁盘空间使用。
Docker不推荐用于生产环境,只用于测试,性能比较差,可能无法支持copy-on-write策略。
存储过程
aufs
docker默认目录为/var/lib/docker,该目录存放docker相关的数据信息。
docker 镜像在设计上将镜像元数据和镜像文件的存储完全隔离开了。Docker 在管理镜像层元数据时采用的是从上至下 repository、image 和 layer 三个层次。由于 docker 以分层的形式存储镜像,所以 repository 和 image 这两类元数据并没有物理上的镜像文件与之对应,而 layer 这种元数据则存在物理上的镜像层文件与之对应。接下来我们就介绍这些元数据的管理与存储。
aufs:
image目录:
diffid: 镜像的各子层
diges: 镜像唯一标识,镜像的摘要(Digest)是对镜像的 manifest 内容计算 sha256sum 得到的。
对于某些image来说,可能在发布之后还会做一些更新,比如安全方面的,这时虽然镜像的内容变了,但镜像的名称和tag没有变,所以会造成前后两次通过同样的名称和tag从服务器得到不同的两个镜像的问题,于是docker引入了镜像的digest的概念,一个镜像的digest就是镜像的manifes文件的sha256码,当镜像的内容发生变化的时候,即镜像的layer发生变化,从而layer的sha256发生变化,而manifest里面包含了每一个layer的sha256,所以manifest的sha256也会发生变化,即镜像的digest发生变化,这样就保证了digest能唯一的对应一个镜像。
aufs存储解析
本段我们以一个镜像的存储解析aufs的存储,以下操作均在/varlib/docker下完成。
一、架构
二、镜像解析
1、查看当前的镜像
cat image/aufs/repositories.json |jq
OR
docker image inspect nginx:latest
2、查看指定镜像的详细信息
该文件包含了镜像架构(如 amd64)、操作系统(如 linux)、镜像默认配置、构建该镜像的容器 ID 和配置、创建时间、创建该镜像的 docker 版本、构建镜像的历史信息以及 rootfs 组成。
其中构建镜像的历史信息和 rootfs 组成部分除了具有描述镜像的作用外,还将镜像和构成该镜像的镜像层关联了起来。Docker 会根据历史信息和 rootfs 中的 diff_ids 计算出构成该镜像的镜像层的存储索引 chainID,并通过chainID获取 layer 相关信息。
docker image inspect nginx:latest
OR
cat image/aufs/imagedb/content/sha256/f7bb5701a33c0e572ed06ca554edca1bee96cbbc1f76f3b01c985de7e19d0657 |jq
参数含义:
container: 制作镜像过程中创建的历史容器
container_config: 环境变量
history: 运行过得历史命令
rootfs: 镜像包含的子层
注:Layers从上到下分别为镜像的最底层----->最顶层
3、查找第三子层的数据存储位置
ll image/aufs/layerdb/sha256/
注:该目录下存储的是镜像的各子层,目录名字为layer的chainid,自己的cahinid由自己父层的cahinid与自己计算得出,由于最底层没有父层,所以最底层的layer的chainid和diffid相同
1、根据最底层算出第二层的cahinid
最底层: sha256:556c5fb0d91b726083a8ce42e2faaed99f11bc68d3f70e2c7bbce87e7e0b3e10
第二层: sha256:49434cc20e95909131e0246cd70999bc362a1b6f511a31b20c4c9c9ad40c736b
第三层: sha256:75248c0d543896c4ba05f1624b740d73a1642d9197f9608033196061e4f1d6bb
2、计算第二层的chaibid
echo -n "sha256:556c5fb0d91b726083a8ce42e2faaed99f11bc68d3f70e2c7bbce87e7e0b3e10 sha256:49434cc20e95909131e0246cd70999bc362a1b6f511a31b20c4c9c9ad40c736b"|sha256sum -
3、第三层的chainid
echo -n "sha256:59d91a36ba4b720eadfbf346ddb825c2faa2d66cc7a915238eaf926c4b4b40ee sha256:75248c0d543896c4ba05f1624b740d73a1642d9197f9608033196061e4f1d6bb" |sha256sum -
4、根据chainid获得cache-id
ll image/aufs/layerdb/sha256/8f1984cf0de0461043fcabd6b2a2040325ac001d9897a242e0d80486fe71575e/
cat image/aufs/layerdb/sha256/8f1984cf0de0461043fcabd6b2a2040325ac001d9897a242e0d80486fe71575e/cache-id
5、根据cache-id获取数据存储位置
镜像的实际数据存储在/var/lib/docker/aufs下。
cat aufs/layers/58e2fe88f5ed205a2060f080886a74e875386e1e03bf5a346c04a593283f8bee
由图可知:当前层包含了之前的两层(其中是cache-id),并且按最顶层到最低层的顺序排列。
ll aufs/diff/58e2fe88f5ed205a2060f080886a74e875386e1e03bf5a346c04a593283f8bee/
aufs/diff/58e2fe88f5ed205a2060f080886a74e875386e1e03bf5a346c04a593283f8bee为第三层的数据存储目录。
由图可知:第三层与第二层的相比,只是/var目录有了改变,如:文件或目录有修改、删除、创建等。也即第三层只包含/var下的数据。
overlay
OverlayFS是一种现代的联合文件系统,与AUFS类似,但速度更快且实现更简单。Docker为OverlayFS提供了两个存储驱动程序:原始的overlay,更新的和更稳定的overlay2。
overlay原生支持128层。
目录结构:
overlay2存储解析
本段我们以一个镜像的存储解析overlay2的存储,以下操作均在/varlib/docker下完成,阅读该段之前请先阅读overlay驱动原理介绍。
寻找镜像第三层的存储数据所在。1、2、3、4均与aufs的操作相同,在此不在讲解。
一、架构
lowerdir: 代表只读的镜像子层
upperdir: 代表读写层,即容器
merged: 容器挂载点
二、镜像解析
1、查看当前的镜像
2、计算第二层的chaibid
3、第三层的chainid
4、根据chainid获得cache-id
cache-id:3946dde17789cb4b2472668f42a9d77d50acb8aac3ababef4c162d7303d6ac9d
3、查看/var/lib/docker/overlay
到此镜像的存储已经写完,在其中还有相关目录没有讲解,后期会在讲解容器时讲到这些目录。
参考
感谢各位老师的分享!
官网:https://docs.docker.com/v18.09/storage/storagedriver/
https://youendless.com/post/docker_storage_driver/
https://www.cnblogs.com/wdliu/p/10483252.html
来源:CSDN
作者:小小小志
链接:https://blog.csdn.net/weixin_43882688/article/details/103734461