Docker文件系统实战
关键词: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镜像时在时间和空间可优化的点:
- 组合运行语句:合并相同类型构建语句,可以有效减少镜像分层;
- 利用镜像构建缓存:时间同步,基础软件安装等固定内容在镜像前部分处理,镜像重新构建时会使用缓存,节省时间;
- 清理中间产物:注意安装过程中使用的软件和压缩包在一定要同一层里清理,否则仍然会占用镜像空间;
- 构建语句优化:比如ADD在处理本地文件时可以直接解压缩,起到COPY + RUN tar的作用;
- 优化基础镜像源:国内高校和大型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文件系统实战的更多相关文章
- Docker虚拟化实战学习——基础篇(转)
Docker虚拟化实战学习——基础篇 2018年05月26日 02:17:24 北纬34度停留 阅读数:773更多 个人分类: Docker Docker虚拟化实战和企业案例演练 深入剖析虚拟化技 ...
- 干货 | Docker文件系统的分层与隔离
现在就开始今天的分享~ M老师:docker 的很多特性都表现在它所使用的文件系统上,比如大家都知道docker的文件系统是分层的,所以它可以快速迭代,可以回滚.这个回滚机制跟github很像,每次提 ...
- Docker 监控实战
如今,越来越多的公司开始使用 Docker 了,现在来给大家看几组数据: 2 / 3 的公司在尝试了 Docker 后最终使用了它 也就是说 Docker 的转化率达到了 67%,而转化市场也控制在 ...
- Docker入门实战_正版电子书在线阅读_百度阅读
Docker入门实战_正版电子书在线阅读_百度阅读 Docker入门实战
- Docker swarm 实战-部署wordpress
Docker swarm 实战-部署wordpress 创建一个overlay的网络 docker network create -d overlay demo 6imq8da3vcwvj2n499k ...
- Docker下实战zabbix三部曲之一:极速体验
对于想学习和实践zabbix的读者来说,在真实环境搭建一套zabbix系统是件费时费力的事情,本文内容就是用docker来缩减搭建时间,目标是让读者们尽快投入zabbix系统的体验和实践: 环境信息 ...
- Docker下实战zabbix三部曲之二:监控其他机器
在上一章<Docker下实战zabbix三部曲之一:极速体验>中,我们快速安装了zabbix server,并登录管理页面查看了zabbix server所在机器的监控信息,但是在实际场景 ...
- Docker下实战zabbix三部曲之三:自定义监控项
通过上一章<Docker下实战zabbix三部曲之二:监控其他机器>的实战,我们了解了对机器的监控是通过在机器上安装zabbix agent来完成的,zabbix agent连接上zabb ...
- Docker镜像实战(ssh、systemctl、nginx、tomcat、mysql)
Docker镜像实战 1.构建ssh镜像 2.构建systemctl 镜像 3.构建nginx镜像 4.构建tomcat镜像 5.构建mysql镜像 1.构建ssh镜像: 创建镜像目录 mkdir / ...
随机推荐
- Java实现 LeetCode 684 冗余连接(并查集)
684. 冗余连接 在本问题中, 树指的是一个连通且无环的无向图. 输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, -, N) 的树及一条附加的边构成.附加的边的两个顶点包含在1到N中间 ...
- Java实现 蓝桥杯VIP 算法提高 聪明的美食家
算法提高 聪明的美食家 时间限制:1.0s 内存限制:256.0MB 问题描述 如果有人认为吃东西只需要嘴巴,那就错了. 都知道舌头有这么一个特性,"由简入奢易,由奢如简难"(据好 ...
- Java实现格子取数问题
1 问题描述 有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右走,一共走两次(即从左上角往右下角走两趟),把所有经过的格子里的数加起来,求总和的最大值.如果两次经过同一个 ...
- Spring Cloud 系列之 Apollo 配置中心(四)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Apollo 配置中心(一) Spring Cloud 系列之 Apollo 配置中心(二) Spring Clou ...
- Redis集群方式
Redis有三种集群方式:主从复制,哨兵模式和集群. 1.主从复制 主从复制原理: 从服务器连接主服务器,发送SYNC命令: 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用 ...
- OSI七层模型及各层作用
物理层:建立.维护.断开物理连接 数据链路层:该层的作用包括了物理地址寻址,数据的成帧,流量控制,数据的检错,重发等.该层控制网络层与物理层之间的通信,解决的是所传输数据的准确性的问题.为了保证传输, ...
- Hive中row_number()、dense_rank()、rank()的区别
摘要 本文对Hive中常用的三个排序函数row_number().dense_rank().rank()的特性进行类比和总结,并通过笔者亲自动手写的一个小实验,直观展现这三个函数的特点. 三个排序函数 ...
- 前端技术 - SeaJS学习
SeaJS 是一个模块加载器,模块加载器需要实现两个基本功能: 实现模块定义规范,这是模块系统的基础. 模块系统的启动与运行. define参数 在 CMD 规范中,一个模块就是一个文件.代码的书写格 ...
- 键盘鼠标共享效率工具----Synergy
在日常工作中,为了提高工作效率以及用户体验,会一个主机接多个显示器,像程序员一般都是使用两块显示器. 然而,有很多人是和我一样,自己有多台电脑,两个笔记本.公司一个台式机,如何在台机器之间来回切换工作 ...
- 列表、元组、字典和简单if语句【python实验1】
第一次实验报告: 学生姓名 总成绩 tom 90 jack 89 john 96 kate 86 peter 100 实验内容3-1 建立两个列表分别对学生的姓名和总成绩信息进行存储 name=['t ...