Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Docker镜像详谈(2): 深入理解镜像大小

Docker镜像详谈(2): 深入理解镜像大小

作者头像
Henry Zhang
发布于 2019-04-12 09:54:05
发布于 2019-04-12 09:54:05
2.4K00
代码可运行
举报
文章被收录于专栏:亨利笔记亨利笔记
运行总次数:0
代码可运行

题图摄于三亚亚龙湾

编者注:在《Docker镜像的核心价值》一文中,曾给大家介绍过Docker镜像的重要性。应读者要求,将连载DaoCloud核心成员、《Docker源码分析》一书作者孙宏亮的系列文章,全面解析Docker镜像的技术要点。继上周《容器的文件系统》文章之后,本周介绍影响容器镜像大小的因素,包括为什么有大小为0的文件层等问题。

都说容器大法好,但是如果没有 Docker 镜像,Docker 该是多无趣啊。

是否还记得第一个接触 Docker 的时候,你从 Docker Hub 下拉的那个镜像呢?在那个处女镜像的基础上,你运行了容器生涯的处女容器。镜像的基石作用已经很明显,在 Docker 的世界里,可以说是「No Image, No Container」。

再进一步思考 Docker 镜像,大家可能很快就会联想到以下几类镜像:

  1. 系统级镜像:Ubuntu 镜像、CentOS 镜像以及 Debian 容器等;
  2. 工具栈镜像:如 Golang 镜像、Flask 镜像、Tomcat 镜像等;
  3. 服务级镜像:MySQL 镜像、MongoDB 镜像、RabbitMQ 镜像等;
  4. 应用级镜像:WordPress 镜像、Docker Registry 镜像等。

镜像林林总总,想要运行 Docker 容器,必须要有 Docker 镜像;想要有 Docker 镜像,必须要先下载 Docker 镜像;既然涉及到下载 Docker 镜像,自然会存在 Docker 镜像存储。谈到 Docker 镜像存储,那我们首先来聊聊 Docker 镜像大小方面的知识。

以下将从三个角度来分析 Docker 镜像的大小问题:「Dockerfile 与镜像」、「联合文件系统」以及「镜像共享关系」。

Dockerfile 与镜像

Dockerfile 由多条指令构成,随着深入研究 Dockerfile 与镜像的关系,很快大家就会发现,Dockerfile 中的每一条指令都会对应于 Docker 镜像中的一层。

继续以如下 Dockerfile 为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM ubuntu:14.04
 ADD run.sh /
 VOLUME /data
 CMD ["./run.sh"]

通过 docker build 以上 Dockerfile 的时候,会在 ubuntu:14.04 镜像基础上,添加三层独立的镜像,依次对应于三条不同的命令。镜像示意图如下:

有了 Dockerfile 与镜像关系的初步认识之后,我们再进一步联系到每一层镜像的大小。

不得不说,在层级化管理的 Docker 镜像中,有不少层大小都为 0。那些镜像层大小不为 0 的情况,归根结底的原因是,构建 Docker 镜像时,对当前的文件系统造成了修改更新。而修改更新的情况主要有两种:

  1. ADD 或 COPY 命令:ADD 或者 COPY 的作用是在 docker build 构建镜像时向容器中添加内容,只要内容添加成功,当前构建的那层镜像就是添加内容的大小,如以上命令 ADD run.sh /,新构建的那层镜像大小为文件 run.sh 的大小。
  2. RUN 命令:RUN 命令的作用是在当前空的镜像层内运行一条命令,倘若运行的命令需要更新磁盘文件,那么所有的更新内容都在存储在当前镜像层中。举例说明:RUN echo DaoCloud 命令不涉及文件系统内容的修改,故命令运行完之后当前镜像层的大小为 0;RUN wget http://abc.com/def.tar 命令会将压缩包下载至当前目录下,因此当前这一层镜像的大小为对文件系统内容的增量修改部分,即 def.tar 文件的大小(在成功执行的情况下)。

联合文件系统

Dockerfile 中命令与镜像层一一对应,那么是否意味着 docker build 完毕之后,镜像的总大小是否等于每一层镜像的大小总和呢?答案是肯定的。依然以上图为例:如果 ubuntu:14.04 镜像的大小为 200 MB,而 run.sh 的大小为 5 MB,那么以上三层镜像从上到下,每层大小依次为 0、0 以及 5 MB,那么最终构建出的镜像大小的确为 0 + 0 + 5 + 200 = 205 MB。

虽然最终镜像的大小是每层镜像的累加,但是需要额外注意的是,Docker 镜像的大小并不等于容器中文件系统内容的大小(不包括挂载文件,/proc、/sys 等虚拟文件)。个中缘由,就和联合文件系统有很大的关系了。

首先来看一下这个简单的 Dockerfile 例子(假设在 Dockerfile 当前目录下有一个 100 MB 的压缩文件 compressed.tar):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM ubuntu:14.04
 ADD compressed.tar /
 RUN rm /compressed.tar
 ADD compressed.tar /
  1. FROM ubuntu:14.04:镜像 ubuntu:14.04 的大小为 200 MB;
  2. ADD compressed.tar /: compressed.tar 文件为 100 MB,因此当前镜像层的大小为 100 MB,镜像总大小为 300 MB;
  3. RUN rm /compressed.tar:删除文件 compressed.tar,此时的删除并不会删除下一层的 compressed.tar 文件,只会在当前层产生一个 compressed.tar 的删除标记,确保通过该层将看不到 compressed.tar,因此当前镜像层的大小也为 0,镜像总大小为 300 MB;
  4. ADD compressed.tar /:compressed.tar 文件为 100 MB,因此当前镜像层的大小为 300 MB + 100 MB,镜像总大小为 400 MB;

分析完毕之后,我们发现镜像的总大小为 400 MB,但是如果运行该镜像的话,我们很快可以发现在容器根目录下执行 du -sh 之后,显示的数值并非 400 MB,而是 300 MB 左右。主要的原因还是,联合文件系统的性质保证了两个拥有 compressed.tar 文件的镜像层,容器仅能看到一个。同时这也说明了一个现状,当用户基于一个非常大,甚至好几个 GB 的镜像运行容器时,在容器内部查看根目录大小,发现竟然只有 500 MB 不到,甚至更小。

分析至此,有一点大家需要非常注意:镜像大小和容器大小有着本质的区别。

镜像共享关系

Docker 镜像说大不大,说小不小,但是一旦镜像的总数上来之后,岂不是对本地磁盘造成很大的存储压力?平均每个镜像 500 MB,岂不是 100 个镜像就需要准备 50 GB 的存储空间?

结果往往不是我们想象的那样,Docker 在镜像复用方面设计得非常出色,大大节省镜像占用的磁盘空间。Docker 镜像的复用主要体现在多个不同的 Docker 镜像可以共享相同的镜像层。

假设本地镜像存储中只有一个 ubuntu:14.04 的镜像,我们以两个 Dockerfile 来说明镜像复用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM ubuntu:14.04
 RUN apt-get update
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM ubuntu:14.04
 ADD compressed.tar /

假设最终 docker build 构建出来的镜像名分别为 image 1 和 image 2,由于两个 Dockerfile 均基于 ubuntu:14.04,因此,image 1 和 image 2 这两个镜像均复用了镜像 ubuntu:14.04。 假设 RUN apt-get update 修改的文件系统内容为 20 MB,最终本地三个镜像的大小关系应该如下:

ubuntu:14.04: 200 MB

image 1:200 MB(ubuntu:14.04 的大小)+ 20 MB = 220 MB

image 2:200 MB(ubuntu:14.04 的大小)+ 100 MB = 300 MB

如果仅仅是单纯的累加三个镜像的大小,那结果应该是:200 + 220 + 300 = 720 MB,但是由于镜像复用的存在,实际占用的磁盘空间大小是:200 + 20 + 100 + 320 MB,足足节省了 400 MB 的磁盘空间。在此,足以证明镜像复用的巨大好处。

总结

学习 Docker 的同时,往往有三部分内容是分不开的,那就是 Dockerfile、Docker 镜像与 Docker 容器,分析 Docker 镜像大小也是如此。Docker 镜像的大小,貌似平淡无奇,却是优化镜像、容器磁盘限额必须要涉及的内容。

欢迎通过留言交流。 本文已获授权发表,转载请与作者联系。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2015-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 亨利笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Docker镜像详谈(1): 容器的文件系统
Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
Henry Zhang
2019/04/12
3K1
Docker镜像详谈(1): 容器的文件系统
Docker镜像详谈(4): 镜像的json文件
很多时候,当大家谈论起 Docker,经常会提到 Docker 作为容器解决方案,在虚拟化资源方面存在不小优势。轻量级虚拟化技术的优点暂且不谈,从软件生命周期来看,Docker 在打包软件、分发软件方面的能力同样出众。而后者很大程度上依赖于 Docker 的镜像技术。
Henry Zhang
2019/04/12
2.2K0
Docker镜像详谈(4): 镜像的json文件
Docker的镜像基本原理和概念
docker client 提供了各种命令和 daemon 交互,来完成各种任务,其中和镜像有关的命令有:
KevinYan
2020/02/26
1.2K0
深入剖析Docker镜像(文末送书)
镜像对于YAML工程师来说都不陌生,每天都在和他打交道,编写、构建、发布,重复而有趣。
没有故事的陈师傅
2021/10/19
6410
深入剖析Docker镜像(文末送书)
Docker 镜像
Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。
traffic
2022/05/11
6.5K0
这就是你日日夜夜想要的docker!!!---------Docker镜像制作与私有仓库建立
Docker 镜像是由文件系统叠加而成(是一种文件的存储形式)。最底端是一个文件引 导系统,即 bootfs,这很像典型的 Linux/Unix 的引导文件系统。Docker 用户几乎永远不会和 引导系统有什么交互。实际上,当一个容器启动后,它将会被移动到内存中,而引导文件系 统则会被卸载,以留出更多的内存供磁盘镜像使用。Docker 容器启动是需要一些文件的, 而这些文件就可以称为 Docker 镜像。
不吃小白菜
2020/09/22
6260
这就是你日日夜夜想要的docker!!!---------Docker镜像制作与私有仓库建立
Docker镜像详谈(3): 镜像内容存放在哪里?
据说重要的事情要说三遍,那我再表述一下个人观点:Docker 镜像是 Docker 的灵魂所在。
Henry Zhang
2019/04/12
8.7K0
Docker镜像详谈(3): 镜像内容存放在哪里?
理解Docker镜像分层
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
Ryan-Miao
2019/03/04
3.1K0
理解Docker镜像分层
Docker 镜像的创建与构建私有库
一、Docker镜像的创建方法 docker镜像是除了docker的核心技术之外,也是应用发布的标准格式。一个完整的docker镜像可以支撑一个docker容器的运行,在docker的整个使用过程中,进入一个已经定型的容器之后,就可以在容器中进行操作,最常见的操作就是在容器中安装应用服务,如果要把已经安装的服务进行迁移,就需要把环境及搭建的服务生成新的镜像。
小手冰凉
2019/11/29
8390
Docker 进阶之镜像分层详解
1.构建测试镜像v1.0:docker build -t image_test:1.0 .
看、未来
2022/06/30
1.6K0
Docker 进阶之镜像分层详解
docker新建镜像_docker基础镜像和项目镜像
–创建镜像有很多方法,用户可以从 Docker Hub 获取已有镜像并更新,也可以利用本地文件系统创建一个。
全栈程序员站长
2022/09/20
4K0
Docker--DockerFile与镜像
    Dockerfile是一个用于引导docker镜像生成过程的文件,遵循其特定的语法,我们便可以创建一个自己的镜像。
洋仔聊编程
2019/01/15
9770
Docker三大核心概念之镜像
Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。
分母为零
2019/07/04
7910
Docker镜像的原理
运行容器,且进入容器内,参数 解释 -i 交互式命令操作 -t 开启一个终端 bash 进入容器后执行的命令
NeilNiu
2023/02/25
6330
docker学习之使用镜像
原文在此 获取镜像 之前提到过,Docker Hub 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像并运行。 从 Docker Registry 获取镜像的命令是 docker pul
若与
2018/04/25
9240
docker学习之使用镜像
技能篇:docker的简易教程
虚拟机技术每家公司发展到一定规模都必须考虑的,更好的环境隔离,更好的事故排查,更好的服务部署
潜行前行
2021/07/23
6460
docker的简易教程
虚拟机技术每家公司发展到一定规模都必须考虑的,更好的环境隔离,更好的事故排查,更好的服务部署
时代疯
2021/07/22
3980
004.Docker镜像管理
镜像是一个包含程序运行必要依赖环境和代码的只读文件,其本质是磁盘上一系列文件的集合。它采用分层的文件系统,将每一次改变以读写层的形式增加到原来的只读文件上。镜像是容器运行的基石。
木二
2019/07/26
1.4K0
创建自己的Docker基础镜像
Docker 提供了两种方法来创建基础镜像,一种是通过引入tar包的形式,另外一种是通过一个空白的镜像来一步一步构建,本文使用的是第二种方法,既FROM scratch
大江小浪
2018/07/24
2.9K0
创建自己的Docker基础镜像
性能环境之docker操作指南6(全网最全)
ubuntu容器内运行着的SSH Server占用22端口,对外为50022端口。
高楼Zee
2019/07/17
7720
相关推荐
Docker镜像详谈(1): 容器的文件系统
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档