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(转载)

相关文章
|
5天前
|
存储 安全 数据安全/隐私保护
【Docker 专栏】Docker 容器化应用的备份与恢复策略
【5月更文挑战第9天】本文探讨了Docker容器化应用的备份与恢复策略,强调了备份在数据保护、业务连续性和合规要求中的关键作用。内容涵盖备份的重要性、内容及方法,推荐了Docker自带工具和第三方工具如Portainer、Velero。制定了备份策略,包括频率、存储位置和保留期限,并详细阐述了恢复流程及注意事项。文章还提及案例分析和未来发展趋势,强调了随着技术发展,备份与恢复策略将持续演进,以应对数字化时代的挑战。
【Docker 专栏】Docker 容器化应用的备份与恢复策略
|
5天前
|
监控 Kubernetes Docker
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
【5月更文挑战第9天】本文探讨了Docker容器中应用的健康检查与自动恢复,强调其对应用稳定性和系统性能的重要性。健康检查包括进程、端口和应用特定检查,而自动恢复则涉及重启容器和重新部署。Docker原生及第三方工具(如Kubernetes)提供了相关功能。配置检查需考虑检查频率、应用特性和监控告警。案例分析展示了实际操作,未来发展趋势将趋向更智能和高效的检查恢复机制。
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
|
1天前
|
Prometheus 监控 Cloud Native
构建高效稳定的Docker容器监控体系
【5月更文挑战第13天】在微服务架构和容器化部署日益普及的背景下,对Docker容器的监控变得尤为重要。本文将探讨一种构建高效稳定Docker容器监控体系的方法,通过集成Prometheus和cAdvisor工具,实现对容器资源使用情况、性能指标和运行状态的实时监控。同时,结合Grafana进行数据可视化,为运维人员提供直观的分析界面,以便及时发现和解决潜在问题,保障系统的高可用性和稳定性。
15 6
|
1天前
|
存储 安全 开发者
如何删除 Docker 镜像、容器和卷?
【5月更文挑战第11天】
13 2
如何删除 Docker 镜像、容器和卷?
|
3天前
|
NoSQL Redis Docker
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
Mac上轻松几步搞定Docker与Redis安装:从下载安装到容器运行实测全程指南
14 0
|
5天前
|
缓存 关系型数据库 数据库
【Docker 专栏】Docker 与容器化数据库的集成与优化
【5月更文挑战第9天】本文探讨了Docker与容器化数据库集成的优势,如快速部署、环境一致性、资源隔离和可扩展性,并列举了常见容器化数据库(如MySQL、PostgreSQL和MongoDB)。讨论了集成方法、注意事项、优化策略,包括资源调整、缓存优化和监控告警。此外,强调了数据备份、恢复测试及性能评估的重要性。未来,随着技术发展,二者的集成将更紧密,为数据管理带来更多可能性。掌握此技术将应对数字化时代的机遇与挑战。
【Docker 专栏】Docker 与容器化数据库的集成与优化
|
5天前
|
存储 安全 数据库
【Docker 专栏】Docker 容器内应用的状态持久化
【5月更文挑战第9天】本文探讨了Docker容器中应用状态持久化的重要性,包括数据保护、应用可用性和历史记录保存。主要持久化方法有数据卷、绑定挂载和外部存储服务。数据卷是推荐手段,可通过`docker volume create`命令创建并挂载。绑定挂载需注意权限和路径一致性。利用外部存储如数据库和云服务可应对复杂需求。最佳实践包括规划存储策略、定期备份和测试验证。随着技术发展,未来将有更智能的持久化解决方案。
【Docker 专栏】Docker 容器内应用的状态持久化
|
5天前
|
机器学习/深度学习 监控 Kubernetes
【Docker 专栏】Docker 容器内服务的自动扩展与缩容
【5月更文挑战第9天】本文探讨了Docker容器服务的自动扩展与缩容原理及实践,强调其在动态业务环境中的重要性。通过选择监控指标(如CPU使用率)、设定触发条件和制定扩展策略,实现资源的动态调整。方法包括云平台集成和使用Kubernetes等框架。实践中,电商平台和实时数据处理系统受益于此技术。注意点涉及监控数据准确性、扩展速度和资源分配。未来,智能算法将提升扩展缩容的效率和准确性,成为关键技术支持。
【Docker 专栏】Docker 容器内服务的自动扩展与缩容
|
5天前
|
Java 数据库连接 Docker
【Docker 专栏】Docker 容器内环境变量的管理与使用
【5月更文挑战第9天】本文介绍了Docker容器中环境变量的管理与使用,环境变量用于传递配置信息和设置应用运行环境。设置方法包括在Dockerfile中使用`ENV`指令或在启动容器时通过`-e`参数设定。应用可直接访问环境变量或在脚本中使用。环境变量作用包括传递配置、设置运行环境和动态调整应用行为。使用时注意变量名称和值的合法性、保密性和覆盖问题。理解并熟练运用环境变量能提升Docker技术的使用效率和软件部署质量。
【Docker 专栏】Docker 容器内环境变量的管理与使用