Dockerfile 中,把多个 RUN 合并在一起,能减少镜像尺寸吗?

先说结论:
有些时候能,有些时候不能,但你要明白原理 – Docker 使用 UnionFS,镜像尺寸随着层数增多,是单调非减的。

问题

看到一个 Dockerfile:

FROM python:3.17.7-alpine3.20
RUN pip3 install pillow
RUN pip3 install django
RUN pip3 install jieba
RUN pip3 install nltk
RUN pip3 install colormap

有人建议,把这几个 pip3 install 合并成一个 pip3 install -r requirements.txt,可以减小最终打包出来的镜像尺寸,真得是这样吗?

实验一:一次 pip 安装 vs 多次 pip 安装

多次 pip 安装

我们把上面这个最初始的 Dockerfile 打包出来的镜像起名为 temp:multi。
通过 docker image ls temp:multi 看到,这个包的大小为 396MB
然后,通过 docker history temp:multi 看到这个包的层级如下:

IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
a934e19243c7   2 hours ago   RUN /bin/sh -c pip3 install colormap   -i ht…   177MB     buildkit.dockerfile.v0
<missing>      2 hours ago   RUN /bin/sh -c pip3 install nltk       -i ht…   22.8MB    buildkit.dockerfile.v0
<missing>      2 hours ago   RUN /bin/sh -c pip3 install django     -i ht…   39.1MB    buildkit.dockerfile.v0
<missing>      2 hours ago   RUN /bin/sh -c pip3 install jieba      -i ht…   83.5MB    buildkit.dockerfile.v0
<missing>      2 hours ago   RUN /bin/sh -c pip3 install pillow     -i ht…   27.1MB    buildkit.dockerfile.v0
<missing>      2 weeks ago   CMD ["python3"]                                 0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;  for src in idle3 p…   36B       buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;   apk add --no-cach…   38.1MB    buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV PYTHON_VERSION=3.12.7                       0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV GPG_KEY=7169605F62C751356D054A26A821E680…   0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;  apk add --no-cache…   999kB     buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV LANG=C.UTF-8                                0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV PATH=/usr/local/bin:/usr/local/sbin:/usr…   0B        buildkit.dockerfile.v0
<missing>      5 weeks ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      5 weeks ago   /bin/sh -c #(nop) ADD file:5758b97d8301c84a2…   7.8MB

可以看到,pip 安装的这些包,总大小应该在 350MB 左右,加上 python-alpine 原来46MB 的大小,整好是在 396 MB

一次 pip 安装

创建 requirements.txt 文件,用于 pip 集中安装:

-i https://pypi.tuna.tsinghua.edu.cn/simple
pillow
django
jieba
nltk
colormap

修改 Dockerfile

FROM python:3.12.7-alpine3.20
COPY requirements.txt /root/
RUN pip install -r /root/requirements.txt

使用 docker build 打包镜像 temp:one。 可以看到,temp:one 的大注也是 396 MB。
使用 docerk history temp:one 查看:

IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
a802510b2faa   2 hours ago   RUN /bin/sh -c pip3 install -r /home/require…   349MB     buildkit.dockerfile.v0
<missing>      2 hours ago   COPY requirements.txt /home/ # buildkit         79B       buildkit.dockerfile.v0
<missing>      2 weeks ago   CMD ["python3"]                                 0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;  for src in idle3 p…   36B       buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;   apk add --no-cach…   38.1MB    buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV PYTHON_VERSION=3.12.7                       0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV GPG_KEY=7169605F62C751356D054A26A821E680…   0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   RUN /bin/sh -c set -eux;  apk add --no-cache…   999kB     buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV LANG=C.UTF-8                                0B        buildkit.dockerfile.v0
<missing>      2 weeks ago   ENV PATH=/usr/local/bin:/usr/local/sbin:/usr…   0B        buildkit.dockerfile.v0
<missing>      5 weeks ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      5 weeks ago   /bin/sh -c #(nop) ADD file:5758b97d8301c84a2…   7.8MB

可以看到,把所有 pip 安装一个 requirements 里安装,实际上并没有减小镜像包的尺寸

使用 pip --no-cache-dir 实际能减少大小

在一次性 pip 安装的基础上,给 Dockerfile 的 RUN pip 命令加上 --no-cache-dir 的参数

FROM python:3.12.7-alpine3.20
COPY requirements.txt /root/
RUN pip install -r /root/requirements.txt

添加这个参数之后,最后生成的镜像大小为 300MB。

实验二:添加一个文件,然后删除

再看这个 Dockerfile

FROM alpine
COPY bigfile /home
RUN rm -f /home/bigfile

这里,我们基于 alpine 镜像,先往里面拷贝了一个 6.4 MB 的大文件,然后又把它给删除了。相当于什么都没做。
最理想的结果,是打包出来的镜像(起名为 temp:add_remove),大小和 alpine 差不多,也应该是 7.8MB 左右的样子。
但实际结果不是这样。
通过 docker image ls temp:add_remove 可以看到,镜像大小为 14.4MB
而用 docker history temp:add_remove 看,结果如下:

IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
81de752d816c   55 minutes ago   RUN /bin/sh -c rm -f /home/bigfile # buildkit   0B        buildkit.dockerfile.v0
<missing>      56 minutes ago   COPY bigfile /home/ # buildkit                  6.62MB    buildkit.dockerfile.v0
<missing>      47 hours ago     RUN /bin/sh -c adduser -D dot # buildkit        3.03kB    buildkit.dockerfile.v0
<missing>      5 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:5758b97d8301c84a2…   7.8MB

可以看到,原来 COPY 的内容实际仍然在打包的镜像里面。为什么删除没有效果呢?

原因是 Docker 的 Union FS

Docker 使用 Union FS 来管理文件系统。
它允许将多个目录挂载到同一个挂载点上,这些目录在挂载点处表现为一个连贯的文件系统。
在 Docker 的上下文中,这意味着可以创建含多个只读层的堆叠,并在顶部添加一个可写层。
Union FS支持层叠多个目录,其中每个目录都可以被视为一个独立的层。
这允许 Docker 镜像由多个只读层组成,每个层代表一个 Dockerfile 指令的结果。

Docker 早期使用的是 AUFS,后来改为使用 overlay2。目前的 Linux 内核,决大多数都支持 oerverlay2。

Overlay2 的一个持点就是:写时复制(Copy-on-Write)
当容器尝试修改一个文件时,overlay2 会检查该文件是否存在于下面的只读层中。
如果是,overlay2 会在可写层创建该文件的副本并进行修改,保持原始只读层不变。

所以,每次 RUN 操作,实际上就是对原始记录加了一层。
如果两个动作如果没有重叠,就像用多个 pip install 不同的包,产生的多层和合在一个 pip 安装产生的一层的大小差不多。
但是,对于先添加,又删除,添加的那层文件始终是在的,只是之后又被删除动作在新的一层上标记为删除。

相当于一个本子上先写了一笔,然后又划掉了(而不是用橡皮擦掉),并不能使本子恢复空白。

最根本的原因,是 overlay2,除了最上层的读写层之外,底下的每一层都是只读的。

打个比方 – 就像钢笔写字,不能擦除

每一次 RUN 操作执行完成后,就生成一层。这层生成之后,就是只读的,不可修改的。
对于下一个操作,以前 RUN 的结果生成的各层,就象是一份份由钢笔书写的文件。
就算是我想修改以前的内容,也只能是做一个标记(就像用钢笔把以前某个文件上的某句话划掉),然后在最新的文件上加上要修改的内容。
总而言之,每新做一个操作,会添加一层。总体的镜像尺寸随着层数增多,是单调非减的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Request2:Post请求和Json

百度翻译拿到自己想看的数据&#xff0c;下图查看请求到数据的请求 preview提前看下 取出对应的RequestUrl &#xff0c;看出来要使用的话得用post请求 #!/usr/bin/env python # -*- coding:utf-8 -*- import requests import json if __name__ "__main__":#1.指定…

SAP物料凭证报表字段调整

业务场景&#xff1a; 报表MB51的输入和输出字段调整&#xff1a; 输入&#xff08;选择界面&#xff09; 输出界面 可以看到在这是没有布局调整的 后台路径&#xff1a; SPRO-物料管理-库存管理和实际库存-报表-定义物料凭证列表的字段选择 事务码&#xff1a;SM30-V_MMI…

FPGA学习(6)-基础语法参数化设计阻塞与非阻塞

目录 1.两种参数化不改变源文件&#xff0c;只改仿真文件的值 2.参数化设计实现模块的重用 2.1不用参数化方法 2.1.1源文件 2.1.2仿真文件 2.1.3仿真波形及实验 2.2 用参数方法 2.2.1调用之前写的led灯闪烁模块&#xff0c;在本源函数中&#xff0c;例化4次调用之前的模…

史上最烂 spring transaction 原理分析

史上最烂 spring transaction 原理分析 事务定义、事务作用、事务特性、生命周期、数据库事务三种运行模式、数据库事务控制、并发事务问题、隔离级别、数据库事务实现原理、spring 事务传播行为、spring 事务核心组件、spring boot 事务相关组件、事务嵌套原理、编程式事务与声…

51单片机的万年历【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块时钟模块按键蜂鸣器等模块构成。适用于电子万年历、数字时钟万年历等相似项目。 可实现功能: 1、LCD1602实时显示年月日星期和北京时间&#xff0c;具备闰年判断功能 2、按键可设置闹钟时间 3、按键可修改当前时…

[Halcon矩阵] 通过手眼标定矩阵计算相机旋转角度

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

06.队列介绍+实现

目录 一、队列的概念 二、队列的实现 1、头文件定义 2、功能函数实现 3、主函数测试 一、队列的概念 队列就像吃饭排队类似&#xff0c;先来先吃&#xff0c;先进先出。 队头&#xff1a;队列的头部。 队尾&#xff1a;队列的尾部。 入队&#xff1a;在队尾操作。 出队&…

STM32—BKP备份寄存器RTC实时时钟

1.BKP简介 BKP(Backup Registers)备份寄存器BKP可用于存储用户应用程序数据。当VDD&#xff08;2.0~3.6V&#xff09;电源被切断&#xff0c;他们仍然由VBAT(1.8~3.6V)维持供电。当系统在待机模式下被唤醒&#xff0c;或系统复位或电源复位时&#xff0c;他们也不会被复位TAMP…

【GAMES101笔记速查——Lecture 16 Ray Tracing4】

上节课的内容&#xff1a;辐射度量学、光线传播、反射方程、渲染方程、全局光照、概率论复习 这节课要介绍一种真实的渲染方法-蒙特卡洛路径追踪 目录 1 简单回顾 1.1 渲染方程&#xff08;The Rendering Equation&#xff09; 1.2 概率 2 蒙特卡洛积分&#xff08;Monte…

SQL Injection | SQL 注入概述

关注这个漏洞的其他相关笔记&#xff1a;SQL 注入漏洞 - 学习手册-CSDN博客 0x01&#xff1a;SQL 注入漏洞介绍 SQL 注入就是指 Web 应用程序对用户输入数据的合法性没有判断&#xff0c;前端传入后端的参数是可控的&#xff0c;并且参数会带入到数据库中执行&#xff0c;导致…

(10) GTest c++单元测试(mac版)

文章目录 概要安装实现机制-断言&#xff08;简单、独立的测试&#xff09;实现机制-测试套件实现机制-Test Fixture和事件 概要 官方文档 https://google.github.io/googletest/ 安装 git clone https://github.com/google/googletestcd googletestmkdir build && c…

数字化营销助企业在生态平台实现内卷突围

在当今数字化时代&#xff0c;企业竞争激烈&#xff0c;内卷化严重。而数字化生态平台建设与数字化营销为企业带来了新机遇。 数字化生态平台意义重大。它能整合企业内外资源&#xff0c;提高运营效率。打破地域限制&#xff0c;拓展市场&#xff0c;吸引更多客户。还能为企业创…

【AI副业项目】太离谱了!爆涨粉47W+,下一个风口项目AI+大健康养S赛道,单月变现30W,教你如何用AI做爆款健康养生账号

我一直说小红薯平台是最适合新手素人做的平台&#xff0c;去中心化的平台&#xff0c;任何普通人都可以在这个平台分一杯羹的平台。 但但但是很多朋友发小红薯作品都是超低的小眼睛&#xff0c;连最基本的流量都没拿到。 从他们的经历来看就是小红薯太难做了。那是没有掌握技…

【Vue】Vue3.0 (十二)、watchEffect 和watch的区别及使用

上篇文章&#xff1a; 【Vue】Vue3.0 &#xff08;十二&#xff09;、watch对ref定义的基本类型、对象类型&#xff1b;reactive定义的对象类型的监视使用 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&…

智慧油田智能安全管控方案-AI助力油气田安全管控升级

在科技日新月异的今天&#xff0c;万物纵横科技凭借其前沿的智慧油田智能安全管控方案&#xff0c;正引领着油气田行业向智能化、高效化转型。该方案深度融合了AI视频智能分析与AIoT&#xff08;物联网人工智能&#xff09;技术&#xff0c;为采油场、油气场的设备运维、环境监…

2024全网最详细CTF入门指南、CTF夺旗赛使用工具及刷题网站

2024年最新的CTF&#xff08;Capture The Flag&#xff0c;夺旗赛&#xff09;入门指南如下&#xff0c;涵盖了入门思路、常见题型及练习网站推荐&#xff0c;帮助你逐步了解并提升在CTF中的解题技巧。 如果你对网络安全入门感兴趣&#xff0c;我给大家整理好了相关资料&#…

Java集合剖析2】Java集合底层常用数据结构

一、数据结构与集合 接下来就要学习集合具体的实现类了&#xff0c;集合的实现类底层可能用1种或多种数据结构来存储数据。所以在学习集合的实现类前&#xff0c;我们有必要了解一下一些常见的数据结构&#xff0c;这样我们在后面查看集合实现类的底层源码时&#xff0c;才不会…

项目模块三:Socket模块

一、模块设计 1、套接字编程常用头文件展示 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> 2、成员函数设计 &#xff08;1&#xf…

题目:连续子序列

解题思路&#xff1a; 首先&#xff0c;不能使用暴力枚举&#xff0c;时间为O(n2)&#xff0c;超时。以下为正确做法&#xff1a; 假设找到一段区间&#xff08;其和>m&#xff09;&#xff0c;如上图黄色部分&#xff0c;那么该区间加上i后面的元素形成的新区间和都>m&a…

Excel中如何进行傅里叶变换(FT),几步完成

在 Excel 中&#xff0c;虽然没有像 MATLAB 那样专门的函数库来直接进行傅里叶变换&#xff0c;但可以使用 Excel 内置的分析工具库提供的傅里叶变换&#xff08;FT &#xff0c;Fourier Transform&#xff09;功能。这个工具可以对数据进行频域分析。以下是如何在 Excel 中进行…