关键词:Docker 联合文件系统 镜像 容器 云信私有化

在本文中,我们来实战构建一个Docker镜像,然后实例化容器,在Docker的生命周期中详细分析一下Docker的文件存储情况和DockerFile优化策略。

在开始实战之前,我们先介绍一个概念,联合文件系统(Union File System)。联合文件系统是实现Docker镜像的技术基础,支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。镜像的分层存储和继承就是基于此特性实现。

下面是Docker官方的一张描述文件系统的图片,显示了一张联合文件系统在串联镜像层和容器层起到的作用

Docker支持多种联合文件系统,常见的有aufs,deviceMapper,overlay,overlay2,本文章中使用的系统版本为debian9.1,Docker版本为17.06.2-ce,默认使用是overlay2。

看到这里如果你已经对Docker文件系统有了简单的概念,那么让我们开始实战,来对分层文件系统的存储方式进行更加深入的了解。

镜像层

这是一个云信私有化项目中基于debian系统镜像创建的jdk8基础镜像,为了方便阅读和分析,我们Dockerfile进行了一些精简,只保留核心部分内容

FROM hub.c.163.com/library/debian:stretch

MAINTAINER nim

#下载jdk

ADD http://10.173.11.100/nim/jdk-8u202-linux-x64.tar.gz /usr/local/nim/

#解压jdk并删除

RUN tar -xzvf /usr/local/nim/jdk-8u202-linux-x64.tar.gz -C /usr/local/nim/ \

&& rm /usr/local/nim/jdk-8u202-linux-x64.tar.gz

#设置环境变量

ENV JAVA_HOME=/usr/local/nim/jdk1.8.0_202

ENV PATH=$JAVA_HOME/bin:$PATH

CMD ["/bin/bash"]

根据构建镜像,查看构建结果,原基础镜像100M,构建后镜像体积697M。

镜像存储

现在开始看一下构建镜像工作在文件层存储情况。首先我们使用Docker history查看一下刚刚构建镜像情况,可以看到基础镜像占用100M,两个镜像分层占用194MB和403M。

接下来我们看查看一下文件系统中的存储情况,本环境使用overlay2,Docker镜像层存储默认路径为/var/lib/Docker/overlay2/,可以看到镜像存储目录下有4个目录,其中110M的对应是基础镜像,另外两个为ADD JDK(186M)和解压JDK压缩包的镜像分层(389M)。

其中的l目录包含了所有层的软连接,软链接使用短名称,避免mount时候参数达到页面大小限制。

下面我们了解一下,每个分层中的文件内容。基础镜像分层包含diff文件夹和link文件,diff文件夹中存放当前分层内容,link文件记录短名称。

接下来看一下COPY JDK生成的内容,diff文件夹保存了jdk压缩包,本层相比基础镜像层,多了lower,merged,work三个文件/文件夹,其中lower记录了此层的下层ID(基础镜像层),merged目录作为提供了统一视图,在容器层读写层被使用,work目录用于联合挂载指定的工作目录,使用过程对用户不可见。

解压JDK层的文件夹结构内容和上一层类似,主要关注jdk压缩包占用空间为0,表示已被删除。

现在来重点关注一个问题,镜像大小等于所有分层相加,在后续分层中被删除的jdk压缩包仍然要占用存储空间,这并不是我们原本意图,因此这里就出现了镜像文件进行优化的点。优化后的Dockerfile如下

FROM hub.c.163.com/library/debian:stretch

MAINTAINER nim

RUN curl -o /usr/local/nim/jdk-8u202-linux-x64.tar.gz http://10.173.11.100/nim/jdk-8u202-linux-x64.tar.gz \

&& tar -xzvf /usr/local/nim/jdk-8u202-linux-x64.tar.gz -C /usr/local/nim/ \

&& rm /usr/local/nim/jdk-8u202-linux-x64.tar.gz \

&& export JAVA_HOME=/usr/local/nim/jdk1.8.0_202 \

&& export PATH=$JAVA_HOME/bin:$PATH

CMD ["/bin/bash"]

借这个优化后的内容,我们再谈一下构建Docker镜像时在时间和空间可优化的点

  1. 组合运行语句:合并相同类型构建语句,可以有效减少镜像分层;
  2. 利用镜像构建缓存:时间同步,基础软件安装等固定内容在镜像前部分处理,镜像重新构建时会使用缓存,节省时间;
  3. 清理中间产物:注意安装过程中使用的软件和压缩包在一定要同一层里清理,否则仍然会占用镜像空间;
  4. 构建语句优化:比如ADD在处理本地文件时可以直接解压缩,起到COPY + RUN tar的作用;
  5. 优化基础镜像源:国内高校和大型IT企业都有创建镜像站,选择一个稳定更新及时的镜像站可以有效缩短构建时间;

举例的镜像中优化策略涉及1,3条,用curl替代add,与解压和删除合并为一层,Dockerfile减少了层数,清理中间过程的jdk安装包,下图是优化后镜像体积变化:

构建镜像真的是层数越少越好吗?当然不是这么绝对,尤其在早期镜像版本不是很稳定或是后续迭代比较频繁时,合理的镜像分层会减少编译时间,降低出错概率,也可以让Dockerfile更具有可读性。可以再稳定版本形成之后对镜像进行二次优化。

镜像元数据

分析一个镜像元数据我们主要关注三个目录

/var/lib/Docker/image/overlay2/imaged/

/var/lib/Docker/image/overlay2/layerdb/

/var/lib/Docker/overlay2/

第一个目录保存镜像基础元数据,第二个目录保存镜像分层元数据,第三个是上文提到的分层存储目录,保存实际分层内容。下面就根据实际情况来看一下,元数据与存储信息是如何关联起来的。

Docker镜像的基本信息保存在/var/lib/Docker/image/overlay2/imaged/content/sha256/下面,可以根据Docker image ID在此目录下查找到对应ID开头文件。此文件中以json的形式保存了该镜像的分层文件系统、构建信息、相关容器等内容。

第二个目录/var/lib/Docker/image/overlay2/layerdb/sha256/保存分层元数据,每一个分层元数据目录下有cache-id,diff,size信息,其中cache-id对应分层存储层,diff关联镜像基础元数据信息。

容器层

首先我们来启动一个容器,挂载宿主机/opt/yunxin目录到容器/usr/local/yunxin目录

创建容器完成之后,在镜像存储目录/var/lib/Docker/overlay2/会生成容器的初始层和读写层,两者使用相同标识,初始层后面多了-init。初始层中主要保存初始化容器环境时,与容器相关的环境信息,如容器主机名,主机host信息以及域名服务文件等;读写层用于容器的读写,Docker容器内的进程只对读写层拥有写权限,而对其他层文件内容只拥有读权限

接下来我们进入容器操作进行一系列操作,再根据结果分析一下读写层对于文件的保存和处理,下面是操作和对应结果以及读写层实际文件存储情况。

序号

类  型

操    作

表 现

1

写入新文件

写入/root/container_file.txt

写入读写层

2

挂载目录写入新文件

写入/usr/local/yunxin/mount_file.txt

不写入读写层,仅保存在挂载目录

3

修改镜像原有文件

修改

/usr/local/nim/jdk1.8.0_202/THIRDPARTYLICENSEREADME.txt

写入读写层

4

删除镜像原有文件

删除

/usr/local/nim/jdk1.8.0_202/README.html

保存在读写层

读写层中的merged文件夹提供了统一视图,面向用户展示联合文件系统挂载完成的最终形态。

接下来我们再基于同一个镜像启动几个容器实例,然后来查询一下Docker容器使用空间,只有第一个容器由于上面修改文件只占用154k,新启动的容器并没有额外占用空间。可见基于同一个镜像创建容器时,所有的容器共享镜像层内容,有效节约了空间。读写层只保存修改内容,如果是操作镜像层文件,Docker采用的是修改时复制策略(copy-on-write)。这时回头再看一下第一节出现的两张图,会对Docker的文件系统有了更深的体会。

结语

Docker 镜像和容器文件系统相关知识在云信私有化产品的镜像管理和运维存储管理方面作出理论支撑,但这只是深入了解Docker的开始。随着时间的积淀和云信旗下IM、音视频、点播以及众多相关产品私有化工作的深入,更多的模块和镜像,更多的客户和需求,更复杂的网络和环境都逐渐呈现在我们面前。Docker作为构建云信私有化服务的基础,只有更深入的去了解原理才能在使用中去更好的优化产品和开展运维。希望我们能为用户提供更可靠的云信私有化服务,也希望能在后续的文章中能与大家分享更多关于Docker的知识。

立即了解网易云信私有云>>

更多技术干货,欢迎关注vx公众号网易智慧企业技术+”。系列课程提前看,精品礼物免费得,还可直接对话CTO。

听网易CTO讲述前沿观察,看最有价值技术干货,学网易最新实践经验。网易智慧企业技术+,陪你从思考者成长为技术专家。

Docker文件系统实战的更多相关文章

  1. Docker虚拟化实战学习——基础篇(转)

    Docker虚拟化实战学习——基础篇 2018年05月26日 02:17:24 北纬34度停留 阅读数:773更多 个人分类: Docker   Docker虚拟化实战和企业案例演练 深入剖析虚拟化技 ...

  2. 干货 | Docker文件系统的分层与隔离

    现在就开始今天的分享~ M老师:docker 的很多特性都表现在它所使用的文件系统上,比如大家都知道docker的文件系统是分层的,所以它可以快速迭代,可以回滚.这个回滚机制跟github很像,每次提 ...

  3. Docker 监控实战

    如今,越来越多的公司开始使用 Docker 了,现在来给大家看几组数据: 2 / 3 的公司在尝试了 Docker 后最终使用了它 也就是说 Docker 的转化率达到了 67%,而转化市场也控制在 ...

  4. Docker入门实战_正版电子书在线阅读_百度阅读

    Docker入门实战_正版电子书在线阅读_百度阅读 Docker入门实战

  5. Docker swarm 实战-部署wordpress

    Docker swarm 实战-部署wordpress 创建一个overlay的网络 docker network create -d overlay demo 6imq8da3vcwvj2n499k ...

  6. Docker下实战zabbix三部曲之一:极速体验

    对于想学习和实践zabbix的读者来说,在真实环境搭建一套zabbix系统是件费时费力的事情,本文内容就是用docker来缩减搭建时间,目标是让读者们尽快投入zabbix系统的体验和实践: 环境信息 ...

  7. Docker下实战zabbix三部曲之二:监控其他机器

    在上一章<Docker下实战zabbix三部曲之一:极速体验>中,我们快速安装了zabbix server,并登录管理页面查看了zabbix server所在机器的监控信息,但是在实际场景 ...

  8. Docker下实战zabbix三部曲之三:自定义监控项

    通过上一章<Docker下实战zabbix三部曲之二:监控其他机器>的实战,我们了解了对机器的监控是通过在机器上安装zabbix agent来完成的,zabbix agent连接上zabb ...

  9. docker入门实战笔记

    1.什么是docker: docker翻译为搬运工,在这里应该可以理解为搬运应用的工具,也就是云.先了解其运用场景之后更容易对他形成深刻理解. Docker提供了一种可移植的配置标准化机制,允许你一致 ...

  10. docker企业实战视频教程

    Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机).bare metal. ...

随机推荐

  1. FMDB 版本迁移

    FMDB 版本迁移 安装 1. 通过CocoaPods 在项目根目录创建并编辑 Podfile 内容如下 $ cd /path/to/MyProject $ touch Podfile $ edit ...

  2. sqlserver 2008 左补齐字符串

    SQLServer:right函数 语法 Right(string, length)   Right 函数的语法具有下面的命名参数:   部分 说明 string 必要参数.字符串表达式,从中最右边的 ...

  3. DB天气app冲刺第二天

    烦躁 烦躁 很烦躁 从大早起就想做一个listview的列表 到晚上也没有做好.不知道为什么.决定明天去问问同学 .做不出来太影响心情了.虽然做出来东西的感觉是很好.. 另外觉得真的没有队友是挺孤独. ...

  4. prmopt 提示框接收字符串,输入后按确定弹出警告框,警告内容为逆序的字符串

    虽然已经找到offer,但因为公司还没安排实习,所以在学校的时间多了很多.好吧,这段时间我用来备考四级啦(好悲催,还没过),然后这一天,闲着无聊,就帮妹妹看了这样子一道题目啦. 题目内容: 编制一个从 ...

  5. Highcharts 异步加载数据曲线图表

    导入 data.js 文件 异步加载数据需要引入以下js 文件: <script src="http://code.highcharts.com/modules/data.js&quo ...

  6. iOS 10 因苹果健康导致闪退 crash

    如果在app中调用了苹果健康,iOS10中会出现闪退.控制台报出的原因是: Terminating app due to uncaught exception 'NSInvalidArgumentEx ...

  7. 在firefox的flashgot中配置各种下载器

    一.在firefox中安装flashgot下载管理器 flashgot是firefox的一个扩展,在联网的情况下,可以在firefox中的附加组件中搜索flashgot,然后安装. 二.在flashg ...

  8. socket.io emit callback调用探秘

    socket.io https://socket.io/ https://socket.io/docs/ What Socket.IO is Socket.IO is a library that e ...

  9. Mybatis进阶学习笔记——输入映射

    1.输入映射 输入映射支持的类型: 1) 基本的类型,int,String,double 等(*)2) JavaBean 类型(*)3) 包装JavaBean 类型(对象里面包含另一个对象) 1.1基 ...

  10. swift 获取Documnets 的路径 和 CGD 延迟

    // CGD 延迟 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64( * NSEC_PER_SEC)), dispatch_get_main ...