Docker镜像优化指南:如何有效地压缩镜像体积并缩短构建时间?

简介:

时至今日,大家已经能够从多种Docker支持的存储驱动程序中做出选择,从而确保其与我们的实际环境以及用例切实吻合——然而,除非深入理解镜像层(更不用提镜像与容器本身),否则一般用户根本不会考虑这方面问题。很明显,这些简单而且缺乏吸引力的技术元素层虽然是构成镜像的基本条件,但却往往得不到高度关注——因为闪亮的新型工具往往比基本信息更能抓人眼球。

在今天的文章中,我们将探讨镜像体积及构建时间方面的话题——而这两项工作也已经成为用户们迫切需要实现的目标。

让我们首先着眼于镜像与层,对其概念加以阐述:

Docker镜像是一套由只读层外加部分元数据构成的标签化结构。

每个层都拥有自己的UUID,而且每个连续层都建立在其下的层之上。

每个Dockerfile指令都会生成一个新层。

看起来基本理念非常简单,且不需要再做过多解释,不过我曾经遇上过这样一个让人如坠雾里的Dockerfile:

FROM centos:7.1.1503

RUN yum -y install java-1.8.0-openjdk-devel-1:1.8.0.65-2.b17.el7_1.x86_64

RUN yum clean all

这个Dockerfile到底出了什么问题?这个嘛,其中第二个RUN命令并没能真正影响到镜像体积——虽然它看起来确实应该有效削减镜像大小。让我们重新审视Docker镜像与层的定义,并着重强调其中的语法表达:

Docker镜像是一套由只读层外加部分元数据构成的标签化结构。

每个层都拥有自己的UUID,而且每个连续层都建立在其下的层之上。

每个Dockerfile指令都会生成一个新层。

现在,可以明确看到该Dockerfile并没能优化镜像体积。无论如何,让我们进行深入探讨,看看这些yum缓存是如何被从镜像层当中移除出去的。

不过为了保证文章浅显易懂的特性,我们首先将关注范畴限定在AUFS存储驱动程序身上。AUFS存储驱动程序能够添加一个疏排文件以覆盖镜像中底部只读层内文件的存在,从而将其从层内删除出去。除此之外,大家可以推断出镜像的大小相当于各层体积的总和,而添加到Dockerfile中的每条附加指令都会进一步增加镜像的体积。

只要将两项RUN指令加以合并,我们就能轻松对上面提到的Dockfile进行修复:

FROM centos:7.1.1503

RUN yum -y install java-1.8.0-openjdk-devel-1:1.8.0.65-2.b17.el7_1.x86_64 &&

yum clean all

下面让我们构建并检查这两套镜像以证明其瘦身效果。大家需要执行docker build -t 以在Dockerfile所容纳的目录当中构建一套镜像。在此之后,我们会发现两套镜像的体积有所不同:

$ docker images

REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE

combined-layers latest defa7a199555 4 seconds ago 407 MB

separate-layers latest b605eff36c7b About a minute ago 471.8 MB

大家应该能够轻松判断哪套镜像是通过哪个Dockerfile构建而成,但让我们进一步查看两套镜像各自包含的层:

$ docker history --no-trunc separate-layers

IMAGE CREATED CREATED BY SIZE

b605eff36c7b418aa30e315dc0a1d809d08a1ebb8e574e934b11f5ad7cd490dc 2 minutes ago /bin/sh -c yum clean all 2.277 MB

4c363330dc9057ce6285be496aa02212759ecfc75c4ad3a9a74e6e2f3dacb1dd 2 minutes ago /bin/sh -c yum -y install java-1.8.0-openjdk-devel-1:1.8.0.65-2.b17.el7_1.x86_64 257.5 MB

173339447b7ec3e8cb93edc61f3815ff754ec66cfadf48f1953ab3ead6a754c5 8 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B

4e1d113aa16e0631795a4b31c150921e35bd1a3d4193b22c3909e29e6f7c718d 8 weeks ago /bin/sh -c #(nop) ADD file:d68b6041059c394e0f95effd6517765405402b4302fe16cf864f658ba8b25a97 in / 212.1 MB

a2c33fe967de5a01f3bfc3861add604115be0d82bd5192d29fc3ba97beedb831 7 months ago /bin/sh -c #(nop) MAINTAINER The CentOS Project - ami_creator 0 B

$ docker history --no-trunc combined-layers

IMAGE CREATED CREATED BY SIZE

defa7a199555834ac5c906cf347eece7fa33eb8e90b30dfad5f9ab1380988ade 48 seconds ago /bin/sh -c yum -y install java-1.8.0-openjdk-devel-1:1.8.0.65-2.b17.el7_1.x86_64 && yum clean all 195 MB

173339447b7ec3e8cb93edc61f3815ff754ec66cfadf48f1953ab3ead6a754c5 8 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B

4e1d113aa16e0631795a4b31c150921e35bd1a3d4193b22c3909e29e6f7c718d 8 weeks ago /bin/sh -c #(nop) ADD file:d68b6041059c394e0f95effd6517765405402b4302fe16cf864f658ba8b25a97 in / 212.1 MB

a2c33fe967de5a01f3bfc3861add604115be0d82bd5192d29fc3ba97beedb831 7 months ago /bin/sh -c #(nop) MAINTAINER The CentOS Project - ami_creator 0 B

这清楚地表明链式命令能帮助我们在对各层进行提交前进行清理工作,不过这并不意味着我们应当将一切都塞进单一层当中。如果大家重新审视以上命令的输出结果,就会发现两套镜像的3个最底层拥有着同样的UUID,这意味着两套镜像共享这些层(有鉴于此,docker images命令才能够报告各镜像的虚拟体积)。

有人可能会说,如今磁盘空间的使用成本已经如此低廉,我们真的有必要如此纠结于所谓镜像体积吗?但除了缓存镜像层之外,大家还有其它方面需要关注。其中最重要的一点在于镜像的构建时间。简单来讲,如果大家能够复用某个层,则无需对其进行重新构建。另外,如果大家的镜像需要通过网络进行传输(例如在流程中分阶段进行构建推进),那么更为袖珍的镜像体积与缓存层运用能够显著节约传输时长(并降低网络流量负载),因为需要实际传输的镜像层中有相当一部分已经被整合在新版本镜像当中。

现在结论已经显而易见,大家应当尽可能减少Dockerfile顶层的指令数量,从而提高缓存复用比例并努力着眼于底层对Dockerfile进行变更。

考虑到以上各项因素,有些朋友可以认为优化程度最高的解决方案应当是将全部发生变更的元素塞进各自不同的层当中,从而清理每个层的执行流程; 但一般来讲,这种作法并不会简化工作负担。首先,Docker对层数做出了限制,即不可超过127个,而且大家最好与上限之间保持一定距离。包含有大量层的Dockerfile既不易于后期维护,也不太可能排除那些不必要的数据; 相反,其结果是我们会面对一套非常臃肿的镜像,且最好将其拆分成多个不同镜像。而更重要的是,层的实现并非毫无成本,具体取决于我们使用的存储驱动程序,由此造成的额外负担也有所区别。举例来说,在AUFS当中,每个层都会在面向镜像层堆栈中各现有文件的首次写入时给容器写入性能造成延迟,特别在文件体积庞大且存在于大量镜像层之下的情况当中。

因此在文章最后,我们需要再次强调:要想切实提升镜像体积优化效果并压缩构建时间,大家必须了解自己想要优化什么,并有意识地做出必要妥协。

1. 如果大家需要了解或者深入掌握容器中的层概念,请点击此处查看Docker说明文档。

2. 查看存储驱动程序说明文档以了解与其性能表现相关的各项细节信息。

3. 如果大家发现自己需要处理高强度写入工作负载,可以考虑使用数据分卷(它们会绕开存储驱动程序)。


本文转自d1net(转载)

目录
打赏
0
0
0
0
16429
分享
相关文章
docker load 后镜像名称为空的问题解决
Docker在容器化应用程序时提供了强大的镜像管理功能,但也可能在某些操作中遇到如镜像名称为空的问题。通过理解问题的成因并采取适当的解决方案,如正确保存和加载镜像、手动修复标签等,可以有效避免和解决这一问题。通过本文提供的指导,您可以确保在使用Docker进行镜像操作时更为顺利,并提高容器管理的效率。
119 82
YashanDB Docker镜像制作
本文介绍了使用Docker部署YashanDB数据库的方法及其优势。相比传统部署方式,Docker简化了环境配置,实现一键部署,确保软件在不同环境中一致运行。文章详细讲解了数据库镜像与容器的概念、Dockerfile的构建流程,以及如何通过Dockerfile定制YashanDB镜像。此外,还演示了镜像的发布过程,包括推送至阿里云容器镜像服务(ACR)。最后,探讨了容器启动时的初始化脚本设置和数据文件复用方法,满足客户对数据库自动化初始化和数据持久化的需求。
Docker Image即Docker镜像
Docker 镜像是 Docker 容器的基础,包含了运行应用程序所需的一切。通过 Dockerfile 可以方便地创建自定义镜像,并且利用 Docker 提供的命令可以轻松管理和使用这些镜像。掌握 Docker 镜像的创建、管理和使用,是进行容器化应用开发和部署的基础技能。希望本文能帮助读者更好地理解 Docker 镜像的概念和操作,提高开发和运维效率。
97 13
docker环境安装kafka/Flink/clickhouse镜像
通过上述步骤和示例,您可以系统地了解如何使用Docker Compose安装和配置Kafka、Flink和ClickHouse,并进行基本的验证操作。希望这些内容对您的学习和工作有所帮助。
225 28
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
271 70
|
4月前
|
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
323 76
多种脚本批量下载 Docker 镜像:Shell、PowerShell、Node.js 和 C#
本项目提供多种脚本(Shell、PowerShell、Node.js 和 C#)用于批量下载 Docker 镜像。配置文件 `docker-images.txt` 列出需要下载的镜像及其标签。各脚本首先检查 Docker 是否安装,接着读取配置文件并逐行处理,跳过空行和注释行,提取镜像名称和标签,调用 `docker pull` 命令下载镜像,并输出下载结果。使用时需创建配置文件并运行相应脚本。C# 版本需安装 .NET 8 runtime。
129 2
docker centos镜像 npm安装包时报错“npm ERR! code ECONNRESET”
通过上述步骤,您可以有效解决在 Docker 中使用 CentOS 镜像安装 npm 包时遇到的 "npm ERR! code ECONNRESET" 错误。希望这些方法能帮助您顺利进行 npm 包的安装。
177 26
Docker-基础(数据卷、自定义镜像、Compose)
通过数据卷实现持久化存储,通过自定义镜像满足特定需求,通过Docker Compose方便地管理多容器应用
111 27
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
239 6
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等