- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Docker镜像存储overlayfs的使用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、概述 。
docker中的镜像采用分层构建设计,每个层可以称之为“layer”,这些layer被存放在了/var/lib/docker/<storage-driver>/目录下,这里的storage-driver可以有很多种如:aufs、overlayfs、vfs、brtfs等。可以通过docker info命令查看存储驱动,(笔者系统是centos7.4):
通常ubuntu类的系统默认采用的是aufs,centos7.1+系列采用的是overlayfs。而本文将介绍以overlayfs作为存储驱动的镜像存储原理以及存储结构.
2、overlayfs 介绍 。
overlayfs是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(例如ext4fs和xfs等等),并不直接参与磁盘空间结构的划分,仅仅将原来底层文件系统中不同的目录进行“合并”,然后向用户呈现,这也就是联合挂载技术,对比于aufs,overlayfs速度更快,实现更简单。 而linux 内核为docker提供的overlayfs驱动有两种:overlay和overlay2。而overlay2是相对于overlay的一种改进,在inode利用率方面比overlay更有效。但是overlay有环境需求:docker版本17.06.02+,宿主机文件系统需要是ext4或xfs格式.
联合挂载 。
overlayfs通过三个目录:lower目录、upper目录、以及work目录实现,其中lower目录可以是多个,work目录为工作基础目录,挂载后内容会被清空,且在使用过程中其内容用户不可见,最后联合挂载完成给用户呈现的统一视图称为为merged目录。以下使用mount将演示其如何工作的.
使用mount命令挂载overlayfs语法如下:
1
|
mount
-t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged_dir
|
创建三个目录a、b、c,以及worker目录:
然后使用mount联合挂载到/tmp/test 下:
然后我们再去查看/tmp/test目录,你会发现目录a、b、c被合并到了一起,并且相同文件名的文件会进行“覆盖”,这里覆盖并不是真正的覆盖,而是当合并时候目录中两个文件名称都相同时,merged层目录会显示离它最近层的文件:
同时我们还可以通过mount命令查看其挂载的选项:
以上这样的方式也就是联合挂载技术.
docker中的overlay驱动 。
介绍了overlay驱动原理以后再来看docker中的overlay存储驱动,以下是来自docker官网关于overlay的工作原理图:
在上述图中可以看到三个层结构,即:lowerdir、uperdir、merged,其中lowerdir是只读的image layer,其实就是rootfs,对比我们上述演示的目录a和b,我们知道image layer可以分很多层,所以对应的lowerdir是可以有多个目录。而upperdir则是在lowerdir之上的一层,这层是读写层,在启动一个容器时候会进行创建,所有的对容器数据更改都发生在这里层,对比示例中的c。最后merged目录是容器的挂载点,也就是给用户暴露的统一视角,对比示例中的/tmp/test。而这些目录层都保存在了/var/lib/docker/overlay2/或者/var/lib/docker/overlay/(如果使用overlay).
演示 。
启动一个容器 。
查看其overlay挂载点,可以发现其挂载的merged目录、lowerdir、upperdir以及workdir:
overlay2的lowerdir可以有多个,并且是软连接方式挂载,后续我们会进行说明.
如何工作 。
当容器中发生数据修改时候overlayfs存储驱动又是如何进行工作的?以下将阐述其读写过程:
读:
修改:
注意事项 。
3、overlay2镜像存储结构 。
从仓库pull一个ubuntu镜像,结果显示总共拉取了4层镜像如下:
此时4层被存储在了/var/lib/docker/overlay2/目录下:
这里面多了一个l目录包含了所有层的软连接,短链接使用短名称,避免mount时候参数达到页面大小限制(演示中mount命令查看时候的短目录):
处于底层的镜像目录包含了一个diff和一个link文件,diff目录存放了当前层的镜像内容,而link文件则是与之对应的短名称:
在这之上的镜像还多了work目录和lower文件,lower文件用于记录父层的短名称,work目录用于联合挂载指定的工作目录。而这些目录和镜像的关系是怎么组织在的一起呢?答案是通过元数据关联。元数据分为image元数据和layer元数据.
image元数据 。
镜像元数据存储在了/var/lib/docker/image/<storage_driver>/imagedb/content/sha256/目录下,名称是以镜像id命名的文件,镜像id可通过docker images查看,这些文件以json的形式保存了该镜像的rootfs信息、镜像创建时间、构建历史信息、所用容器、包括启动的entrypoint和cmd等等。例如ubuntu镜像的id为47b19964fb50
查看其对应的元数据(使用vim :%!python -m json.tool格式化成json) 截取了其rootfs的构成:
上面的 diff_id 对应的的是一个镜像层,其排列也是有顺序的,从上到下依次表示镜像层的最低层到最顶层:
diff_id如何关联进行层?具体说来,docker 利用 rootfs 中的每个diff_id 和历史信息计算出与之对应的内容寻址的索引(chainid) ,而chaiid则关联了layer层,进而关联到每一个镜像层的镜像文件.
layer元数据 。
layer 对应镜像层的概念,在 docker 1.10 版本以前,镜像通过一个 graph 结构管理,每一个镜像层都拥有元数据,记录了该层的构建信息以及父镜像层 id,而最上面的镜像层会多记录一些信息作为整个镜像的元数据。graph 则根据镜像 id(即最上层的镜像层 id) 和每个镜像层记录的父镜像层 id 维护了一个树状的镜像层结构。 。
在 docker 1.10 版本后,镜像元数据管理巨大的改变之一就是简化了镜像层的元数据,镜像层只包含一个具体的镜像层文件包。用户在 docker 宿主机上下载了某个镜像层之后,docker 会在宿主机上基于镜像层文件包和 image 元数据构建本地的 layer 元数据,包括 diff、parent、size 等。而当 docker 将在宿主机上产生的新的镜像层上传到 registry 时,与新镜像层相关的宿主机上的元数据也不会与镜像层一块打包上传。 。
docker 中定义了 layer 和 rwlayer 两种接口,分别用来定义只读层和可读写层的一些操作,又定义了 rolayer 和 mountedlayer,分别实现了上述两种接口。其中,rolayer 用于描述不可改变的镜像层,mountedlayer 用于描述可读写的容器层。具体来说,rolayer 存储的内容主要有索引该镜像层的 chainid、该镜像层的校验码 diffid、父镜像层 parent、storage_driver 存储当前镜像层文件的 cacheid、该镜像层的 size 等内容。这些元数据被保存在 /var/lib/docker/image/<storage_driver>/layerdb/sha256/<chainid>/ 文件夹下。如下:
每个chainid目录下会存在三个文件cache-id、diff、zize:
cache-id文件:
docker随机生成的uuid,内容是保存镜像层的目录索引,也就是/var/lib/docker/overlay2/中的目录,这就是为什么通过chainid能找到对应的layer目录。以chainid为d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4 对应的目录为 130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5,也就保存在/var/lib/docker/overlay2/130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5 。
diff文件:
保存了镜像元数据中的diff_id(与元数据中的diff_ids中的uuid对应) 。
size文件:
保存了镜像层的大小 。
在 layer 的所有属性中,diffid 采用 sha256 算法,基于镜像层文件包的内容计算得到。而 chainid 是基于内容存储的索引,它是根据当前层与所有祖先镜像层 diffid 计算出来的,具体算如下:
mountedlayer 信息存储的可读init层以及容器挂载点信息包括:容器 init 层id(init-id)、联合挂载使用的id(mount-id)以及容器层的父层镜像的 chainid(parent)。相关文件位于/var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/ 目录下。如下启动一个id为3c96960b3127的容器
查看其对应的mountedlayer三个文件:
可以看到initid是在mountid后加了一个-init,同时initid就是存储在/var/lib/docker/overlay2/的目录名称:
查看mountid还可以直接通过mount命令查看对应挂载的mountid,对应着/var/lib/docker/overlay2/目录,这也是overlayfs呈现的merged目录
在容器中创建了一文件:
此时到宿主的merged目录就能看到对应的文件:
关于init层 。
init层是以一个uuid+-init结尾表示,夹在只读层和读写层之间,作用是专门存放/etc/hosts、/etc/resolv.conf等信息,需要这一层的原因是当容器启动时候,这些本该属于image层的文件或目录,比如hostname,用户需要修改,但是image层又不允许修改,所以启动时候通过单独挂载一层init层,通过修改init层中的文件达到修改这些文件目的。而这些修改往往只读当前容器生效,而在docker commit提交为镜像时候,并不会将init层提交。该层文件存放的目录为/var/lib/docker/overlay2/<init_id>/diff 。
小结 。
通过以上的内容介绍,一个容器完整的层应由三个部分组成,如下图:
4、总结 。
本文介绍了以overlayfs作为存储驱动的的镜像存储原理其中每层的镜像数据保存在/var/lib/docker/overlay2/<uuid>/diff目录下,init层数据保存了在 /var/lib/docker/overlay2/<init-id>/diff目录下,最后统一视图(容器层)数据在 /var/lib/docker/overlay2/<mount_id>/diff目录下,docker通过image元数据和layer元数据利用内容寻址(chainid)将这些目录组织起来构成容器所运行的文件系统.
参考:
《use overlayfs driver 》 。
《docker 镜像之存储管理》 。
到此这篇关于docker镜像存储overlayfs的使用的文章就介绍到这了,更多相关docker镜像存储overlayfs内容请搜素我以前的文章或下面相关文章,希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/wdliu/p/10483252.html 。
最后此篇关于Docker镜像存储overlayfs的使用的文章就讲到这里了,如果你想了解更多关于Docker镜像存储overlayfs的使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在使用以下dockerfile: FROM ubuntu:14.04 MAINTAINER xxx xxx # SSH RUN apt-get update && apt-get install
我运行了docker-compose build celery,(经过数小时的尝试,我的连接不良)成功了。 app Dockerfile的前80%是相同的,但不会重复使用缓存。从我可以浏览的内容来看,
我可以使用以下命令成功创建 Docker 注册表 v2 服务:docker service create 然后我使用 docker Push 将一些图像推送到该服务。 当我通过 curl localh
我正在尝试使用 gitlab 构建 CI,我从 docker 的 docker 镜像开始,我的前端存储库没有任何问题,但现在使用相同的 gitlab-ci 配置文件,我有此守护程序错误。 这是构建的输
用例: 我们在 Jenkins 中有几个“发布作业”build 和 push 应用程序的 Docker 镜像到 docker registry,更新各种文件中的项目版本,最后将发布标签推送到相应的 G
当我尝试构建我的 docker 文件时,docker 返回以下错误: [+] Building 0.0s (1/2)
docker-in-docker 的作者在此博客中建议不要将此图像用于 CI 目的: jpetazzo/Using Docker-in-Docker for your CI or testing en
我创建了一个 Dockerfile 来在 Docker 中运行 Docker: FROM ubuntu:16.04 RUN apt-get update && \ apt-get in
我尝试为 Docker 镜像定位一个特定标签。我怎样才能在命令行上做到这一点?我想避免下载所有图像,然后删除不需要的图像。 在 Ubuntu 官方版本中,https://registry.hub.do
我正在尝试在docker中运行docker。唯一的目的是实验性的,我绝不尝试实现任何功能,我只想检查docker从另一个docker运行时的性能。 我通过Mac上的boot2docker启动docke
docker-compose.yml version: "3" services: daggr: image: "docker.pvt.com/test/daggr:stable"
我有一个非常具体的开发环境用例。在一些代码中,我启动了一个容器来抓取页面并检索在容器中运行的服务(Gitlab)的 token 。 现在,我希望 Dockerize 运行它的代码。具体来说,类似: o
之前已经问过这个问题,但我不确定当时是否可以使用docker-compose文件完成docker堆栈部署。 由于最新版本支持使用compose将服务部署到堆栈,因此,我无法理解dab文件的值。 我检查
我在一次采访中被问到这个问题,但无法回答。也没有找到任何相关信息。 最佳答案 正如 Docker 文档中所述,Docker 注册表是: [...] a hosted service containin
有没有一种方法可以将具有给定扩展名的所有文件复制到Docker中的主机?就像是 docker cp container_name:path/to/file/in/docker/*.png path/o
我的日志驱动程序设置为journald。使用日志记录驱动程序时,daemon.json文件中的日志级别配置会影响日志吗?使用docker logs 时仅会影响容器日志? 例如,docker和journ
我最近开始使用Docker + Celery。我还共享了full sample codes for this example on github,以下是其中的一些代码段,以帮助解释我的观点。 就上下文
运行docker build .命令后,尝试提交构建的镜像,但收到以下错误 Step 12 : CMD activator run ---> Using cache ---> efc82ff1ca
我们有docker-compose.yml,其中包含Kafka,zookeeper和schema registry的配置 当我们启动docker compose时,出现以下错误 docker-comp
我是Docker的新手。是否可以在Docker Hub外部建立Docker基本镜像存储库?假设将它们存储在您的云中,而不是拥有DH帐户?谢谢。 最佳答案 您可以根据需要托管自己的注册表。可以在Depl
我是一名优秀的程序员,十分优秀!