docker镜像与容器存储结构分析
注意:转载请注明出处:http://www.programfish.com/blog/?p=9
Docker是一个开源的应用容器引擎,主要利用linux内核namespace实现沙盒隔离,用cgroup实现资源限制。
Docker 支持三种不同的镜像层次存储的drivers: aufs、devicemapper、btrfs ;
Aufs:
AUFS (AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统。 Aufs driver是docker 最早支持的driver,但是aufs只是linux内核的一个补丁集而且不太可以会被合并加入到linux内核中。但是由于aufs是唯一一个 storage driver可以实现容器间共享可执行及可共享的运行库, 所以当你跑成千上百个拥有相同程序代码或者运行库时时候,aufs是个相当不错的选择。
Device Mapper:
Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略(详见:http://www.ibm.com/developerworks/cn/linux/l-devmapper/index.html) 。
Device mapper driver 会创建一个100G的简单文件包含你的镜像和容器。每一个容器被限制在10G大小的卷内。(如果想要调整,参考:http://jpetazzo.github.io/2014/01/29/docker-device-mapper-resize/ 。中文译文: http://zhumeng8337797.blog.163.com/blog/static/100768914201452405120107/ )
你可以在启动docker daemon时用参数-s 指定driver: docker -d -s devicemapper ;
Btrfs:
Btufs driver 在docker build 可以很高效。但是跟 devicemapper 一样不支持设备间共享存储(文档里是does not share executable memory between devices)。
下面笔者就已有的条件去分析下docker的镜像与容器的存储结构。
环境:
opensuse 13.10 + Docker version 1.2.0, build fa7b24f
Ubuntu 14.10 + Docker version 1.0.1, build 990021a
在没有aufs支持的linux发行版本上(CentOS,opensuse等)安装docker可能就使用了devicemapper driver。
查看你的linux发行版有没有aufs支持:lsmod | grep aufs
笔者opensuse 13.10里是没有加载这个模块的:
而虚拟机里的ubuntu 14.10 是加载了这个模块的:
而我们列出/var/lib/docker 这个目录的内容也可以看出你那个docker是使用了哪个storage driver:
opensuse 13.10 上的/var/lib/docker
这里应该看出是使用了device mapper这个driver ;
然后再来看看虚拟机ubuntu 14.10上/var/lib/docker 目录:
这里也可以看出笔者ubuntu里docker 是使用了aufs 这个driver : 下文就这两个不同的driver作对比。
请注意分析的是哪一个。
那么镜像文件是本地存放在哪里呢?
笔者在opensuse和ubuntu里把docker彻底重新安装了一遍删除了所有镜像,并只Pull下来一个ubuntu:14.10的镜像,这样分析起来会比较简单明了: 现在两个系统都只有一个ubuntu:14.10的镜像:
opensuse:
Ubuntu :
好了。首先现在我们来看看/var/lib/docker里都是什么文件。
1、首先用Python 的json.tool工具查看下repositories-* 里的内容。
opensuse:
里面的json数据记录的正是本地上存放的镜像的名称及其64位长度的ID.这个ID可以有其12位的简短模式。 Ubuntu上也是一样的:
而且我们可以发现这两个ID是一样。这时我们其实可以猜想到:这个ID是全局性的,就是说你这个镜像在镜像仓库上的ID也是这个。被其它机器上ID也是这个。这样的好处无疑是方便管理镜像。
2、/var/lib/docker/graph 目录里的内容:
opensuse:
Ubuntu:
Graph目录里有7个长ID命名的目录,其中第二个长ID是我们所pull下来的ubuntu14.10镜像的对应的长ID..那么其它6个是怎么来的呢?
这里我们用docker images -tree列出镜像树形结构:
可以看到最下层的镜像是我们的ubuntu14.10。那么上面对应的是6个layer。就是说在这个树中第n+1个层是基于第n个层上改动的。而第个层在graph目录里都对应着一个长ID目录。
我们来看看虚拟机里ubuntu14.10 里的docker images -tree:
大小数量一致。但是到了最后一个层的大小不一样(这里原因可能会是系统问题,也可能是docker版本问题。具体原因需要另外考察)
再分析一下各个层的大小,第一个为0B, 第二个层就应该为198.9MB,第三个层大小为0.2MB(199.1-198.9)…如此类推下去。
上层的image依赖下层的image(注:这里的逻辑上层是上图树形结构的下层),因此docker中把下层的image称作父image,没有父image的image称作base image ;
例如我要用这里的ubuntu:14.10为模板启动一个容器时,docker会加载树形结构中的最下层( 2185fd5…),然后加载其父层(f180ea…),这样一直加载到第一层(511136…)才算加载这个rootfs。那么一个层在哪里保存它的父 层信息呢?在下面长ID目录里的json文件其实也可以看到这个信息。
graph长ID目录内容:(对于ubuntu里是一样的,这里以opensuse为例)
我们进入长ID目录里看看里面的内容:
opensuse :
我们进入最后一个层长ID目录里。里面有一个json文件及一个名为layersize的文件。 用cat查看layersize里的内容,里面记录的数字是指这个层的大小。这里(绿色前头)是0。而我们从上面的目录树可以算出最后一个层确实是0。如 果还不相信。我们再算算倒数第二个层的大小(opensuse里的树形图里短id为f180ea115597的层)应该为37.8M。现在进入对应长ID 目录:
可以看到是是37816084(B),约37.8M,与我们计算的刚刚吻合。
而另一个文件json又是什么呢?用python工具看看:(内容有点多,没有截完)
可以看到json这个文件保存的是这个镜像的元数据。
拉到底部可以看到有个parent:的值:
这个就是保存了其父层长ID的值。对照树形结构看f180ea115597 的父层是不是0f154c52e965 。
但是注意在graph这个目录里并没有找到我们想找到的镜像内容存放地。只是一些镜像相关的信息数据。
镜像里的内容存放在哪里
opensuse :
在opensuse下的/var/lib/docker/devicemapper/devicemapper/这个目录下找到两个文件,并列出其大小。
其中一个data的文件大小为100G(非真实占用)。真实占用的情况如下:
100G的只占用了590M。
上面我们讲到:Device mapper driver 会创建一个100G的简单文件包含你的镜像和容器。每一个容器被限制在10G大小的卷内。那么看来这个100G的简单文件正是这个名为data 的文件,那么镜像和容器下是存放在这里的。
好了。这时我在opensuse上再pull下一个ubuntu:12.10 镜像看看这个文件大小有什么变化: 这次一下子截了三个命令的信息:
Pull下来的ubuntu是172.1M。树形结构可以看到各个层的关系。而data的大小变成了787M. 没pull ubuntu:12.10之前是590M.增加了197M,跟pull下来的172.1M有点差距。这里可认为是存储了额外的某些信息。
那么容器是不是也存放在这里呢?
我们用ubuntu14.10启动一个模板看看情况如何:
这次我也是一下子截了几个命令:
可以看到了一个基于ubuntu:14.10镜像的容器在运行中,简短ID是a9b35d72fcd4,
第二个命令du列出了data的大小为789M,增加了2M。
第三个命令列出了container目录内出现一个长ID的目录,ID就是运行的容器的ID。但是里面的文件应该都是些配置文件。并没有我们想要的内容目录。
这样的话我们进一步做测试:在运行的容器内使用dd if=/dev/zero of=test.txt bs=1M count=8000 创建一个8G大小的文件后:
这里data变成了8.6G,增长了接近8G,这样也证实了容器里的内容是保存在data这个简单文件内的。
这样的话证实了devicemapper driver是把镜像和容器的文件都存储在data这个文件内。
Ubuntu 的aufs driver 又如何呢:
Ubuntu上由于是aufs driver 所以/var/lib/docker 目录下有aufs目录而不是devicemapper 目录:
这里的aufs 目录有三个目录,diff 、layers 、mnt 三个目录。
这里layers目录是保存了layers层次信息,并不是layers里面的内容。
而diff 目录时有数个长ID目录:
列出这几个目录的大小可以看出基本与上面树形结构的所能计算的大小相对应(相关部分可能是由于压缩或者其它原因造成,这里纯属猜测)。
那我们进入f180ea115597这个ID对应的目录看看里面是什么:
里面是一些文件夹,但是只有几个,并不像我们平时常规linux发行版里的那么齐全。
这里的话其实我们可以想到了因为一个层是基于另一个层之上的。Aufs文件系统可以做到增量修改,所以这里的几个文件夹是基于上一个层做的修改内容增量地保存在这里,因为上一个层对于这个层来说不可写:
在这里我需要先引用一张网上的图片:
这里我们可以看到一个我们想象中的运行中的container是包含了若干个readonly的image层,然后最上面的writable层才是我们可写的层。第一个readonly的层会加载其父层。直到最下面的base image层。
我们所做的改动会被保存在最上面的那个writable层里。当我们用commit 把容器固化成镜像时那个层就会变成我们上面看到的“目录不齐全的”长ID目录。
为了证实这一点,我们在运行一个基于ubuntu:14.10镜像的容器:
可以看到运行的容器简短ID为7b3c13323d8c 。
这时再列出diff目录的内容:
多了两个长ID目录,正是我们运行的容器的ID,列出内容:
然后我们在运行的容器中创建一个/test 目录,并在里面用dd命令创建一个8G的test.txt文件:完成这些后再列出这两个目录内容:
可以看到其中一个目录(没有init后缀)变成了7.5G,而另一个目录还是24K。
在长ID目录里还多了一个test文件夹,正是我们在容器里创建的,这样的话里面无疑问就是test.txt文件了。容器通过这种方法在writable层里记录了修改过的内容(增量记录) (这里有个小问题笔者也还不清楚:怎么记录删除了东西呢?这个问题以后再考察)
从上面我们可以知道容器的writable 层是保存在以容器ID为名的长ID目录里的,而ID+init后缀目录是保存容器的初始信息的。
好了,现在我们进行最后一个实验:把容器固化成镜像。
(这里要做个小小调整。把上面8G的文件删除了再建一个3G大小的文件test_3G.txt代替)
Commit 后把容器固化成了test_image的镜像。得到那个镜像的长ID。
现在看看变化:
那个窗口目录还在,原因是我们还没用rm 命令删除那个容器。而多出来的镜像目录正是我们固化所得到的,其大小与上面容器writable层大小一致为3GB。现在看看里面是什么内容:
里面有一个test目录,目录下对应我们创建的3GB大小的test_3G.txt文件。
这就是我们改动过的内容保存了在这个目录内。
现在我们用rm命令删除容器看看结果:
容器被删除了,其对应的长目录ID也被删除了。而那个固化的得到的镜像( c7560af30 )被保存了下来。
通过上面的小实验基本可以看清docker 在devicemapping 和 aufs这两个driver 的存储结构,但是这些目录是怎样灵活地在运行容器时被加载到一起就需要读者去了解更深层的关于aufs及devicemapping相关的知识。
参考文献:
docker官方文档:https://docs.docker.com/reference/commandline/cli/
Docker存储结构:http://blog.thoward37.me/articles/where-are-docker-images-stored/
欢迎访问本人网站:http://www.programfish.com
LinuxCoder 社区: http://linuxcoder.org
注意:转载请注明 “作者:广州Linux爱好者+云计算 刁金明”
docker镜像与容器存储结构分析的更多相关文章
- CentOS7更改Docker默认镜像和容器存储位置
图片出处:https://bobcares.com/wp-content/uploads/docker-change-directory.jpg 一.Why? 通常,当你开始使用docker时,我们并 ...
- centos7下更改docker镜像和容器的默认路径
笔者近期在服务器上搭建docker环境,可由于笔者是普通用户,在安装的时候就跳了很多坑,现在记录一下. 一.docker权限问题 据官方解释,搭建docker环境必须使用root权限,或者sudo装, ...
- Docker镜像和容器
本节内容: 安装Docker 卸载docker 镜像基本操作 容器基本操作 一.安装Docker Docker 对 Linux 内核版本的最低要求是3.10,如果内核版本低于 3.10 会缺少一些运行 ...
- docker镜像与容器
目录 docker镜像与容器 概述 分层存储 镜像与容器 删除镜像与容器 将容器中的改动提交到镜像 慎用 docker commit--构建镜像推荐使用dockerfile docker镜像与容器 概 ...
- Docker容器化【Docker镜像与容器相关命令】
# Docker 学习目标: 掌握Docker基础知识,能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用 ...
- Docker镜像与容器的常用操作
Docker镜像加速配置:Docker镜像常用操作:Dcoker容器常用操作. 镜像加速器 国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器.国内很多云服务商都提供了国内加 ...
- docker 入门(docker 镜像 、容器、仓库)
一.关于docker 镜像 .容器.仓库之间的关系 镜像(Image): 类似于虚拟机 的镜像 容器(Container): 类似于操作系统(或者说是独立的软件), 由镜像可以创建大量的容器. 仓库( ...
- docker镜像和容器的导出导入
本文介绍docker镜像和容器的导入导出,用于迁移.备份.升级等场景.主要用到export.import.save.load四个方法. 原文地址:代码汇个人博客 http://www.codehui. ...
- 快速批量删除 docker 镜像或容器
原文:快速批量删除 docker 镜像或容器 点击在我的博客 xuxusheng.com 中查看,有更好的排版哦~ docker 本身并没有提供批量删除的功能,当有大量的镜像或者容器需要删除的时候,手 ...
随机推荐
- vim 多行注释
多行注释: 1. 进入命令行模式,按ctrl + v进入 visual block模式,然后按j, 或者k选中多行,把需要注释的行标记起来 2. 按大写字母I,再插入注释符,例如// 3. 按esc键 ...
- 接入SDK
管理提醒: 本帖被 fm2010 设置为精华(2014-11-12) http://www.cocoachina.com/bbs/read.php?tid-239087.html 本帖属于Co ...
- SQL中什么叫模式
模式(schema) 是 数据库体系结构中的一个节点对于 SQL Server 数据库来说.访问具体的一个表,可以由 4个部分组成分别为 服务器名, 数据库名,模式名,表名.对于访问本地的数据库因为 ...
- Linux(Centos)下安装MySQL
转载:http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html 一.mysql简介 说到数据库,我们大多想到的是关 ...
- Java开发工具与程序调试
开发工具:MyEclipse,Eclipse等. 程序调试: (1)断点:设置断点是程序调试中必不可少的手段,Java调试器每次遇到程序断点时都会将当前线程挂起,即暂停当前程序的运行.(在Eclip ...
- PowerShell_零基础自学课程_1_初识PowerShell
欢迎转载本系列文章:转载请注明出处:www.cnblogs.com/volcanol 自从微软推出.Net以来,微软旗下的windows体系就发生了很大的变化,首先是操作系统的界面的变化,例如vist ...
- ps&&/proc/pid/xxx
ps 如果想看一个进程的启动时间,可以用lstart来看 [root@jiangyi02.sqa.zmf /home/ahao.mah] #ps -eo pid,lstart,etime,cmd |g ...
- pyqt listwidget下面创建多张图片
def Photosvisi(self): i=0 self.lists.setIconSize(QtCore.QSize(70,70))#设置显示图片大小 self.lists.setResizeM ...
- java并发编程--Executor框架(一)
摘要: Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程 ...
- (2)入门指南——(3)为什么jquery工作的很好(Why jQuery works well)
With the resurgence of interest in dynamic HTML comes a proliferation of JavaScript frameworks. Some ...