Dockerfile生成镜像的时候是如何缓存的?
本关将讲述镜像构建时的缓存机制希望能够帮助大家更好地使用Dockerfile。Dockerfile生成镜像的时候是如何缓存的? 比如我安装一个东西耗时两个小时,但是构建成功之后再构建一次他就很快了,说明它缓存了,现在我的疑惑是如果我稍微改变了一点东西,如何保证他不需要在再耗时两个小时。docker build过程中每执行一步RUN命令,就生成一个镜像,另外镜像之间有血缘关系,
本关将讲述镜像构建时的缓存机制希望能够帮助大家更好地使用Dockerfile。
Dockerfile生成镜像的时候是如何缓存的?
比如我安装一个东西耗时两个小时,但是构建成功之后再构建一次他就很快了,说明它缓存了,现在我的疑惑是如果我稍微改变了一点东西,如何保证他不需要在再耗时两个小时。
docker build过程中每执行一步RUN命令,就生成一个镜像,另外镜像之间有血缘关系,是否需要重新编译两个小时取决于你的修改影响的第一个镜像有多早。
简单理解当你修改dockerfile时,当你修改了第N行的RUN命令, N+1之后的命令都要重跑;
docker image --tree #查看镜像的依赖关系
另外你直接docker images也能看到很多None名字的镜像文件,
那就是你之前build的结果; 如果build成功的话,就会把None改成你指定的name;
首先举一个我平时构建Dockerfile时遇到的小例子。
我想使用Dockerfile构建一个基于centos并拥有java运行环境的镜像,我的Dockerfile如下所示:
然后我使用docker build -t javaimage:v1.0 .这条命令去构建该镜像。经过长时间的下载,等待之后,镜像终于构建好了,但是我突然发现,我的JAVA_HOME环境变量竟然有问题,我竟然将jre1.8.0_144写成了jre1.8.0_14。于是我重新修改了Dockerfile文件,然后docker build -t javaimage:v1.0 .进行构建。
令人惊喜的是,这一次构建过程一下子就完成了。好像它根本不需要重新下载jre一样,那究竟是怎么回事呢?下面是第二次执行docker build -t javaimage:v1.0 .的情况。可以发现,在执行RUN指令时,显示了Using cache,也就是使用了缓存的意思。就是它让我们跳过了漫长的等待过程!那为什么从第三步开始就没有使用缓存了呢?下面我们将详细地讲述镜像构建时的缓存机制。
镜像构建时的缓存机制
在构建映像的过程中,Docker将按照指定的顺序逐步执行您的Dockerfile中的指令。随着每条指令的检查,Docker将在其缓存中查找可重用的现有映像,而不是创建一个新的(重复)映像。如果您不想使用缓存,可以在docker build命令中使用--no-cache = true选项。但是,如果您确实让Docker使用其缓存,那么了解何时会找到匹配的映像是非常重要的。
Docker将遵循的基本规则如下:
- 从已经在缓存中的父镜像开始,将下一个指令与从该基本镜像导出的所有子镜像进行比较,以查看其中一个是否使用完全相同的指令构建。如果没有,则缓存无效。
- 在大多数情况下,只需将Dockerfile中的指令与其中一个子镜像进行比较即可(通过比较是否与上一次执行的指令一致)。但是,某些指令需要一些额外的检查。对于ADD和COPY指令,将检查镜像中文件的内容,并为每个文件计算校验和。在这些校验和中不考虑文件的最后修改和最后访问的时间。在缓存查找期间,将校验和与现有映像中的校验和进行比较。如果文件(如内容和元数据)中有任何变化,则缓存无效。
-
除了ADD和COPY命令之外,缓存检查将不会查看容器中的文件来确定缓存匹配。例如,当处理RUN apt-get -y update命令时,不会检查在容器中更新的文件以确定是否存在高速缓存命中,它将只会检查命令字符串是否与之前的一致来判断是否匹配。
一旦某一层的缓存无效,所有后续的Dockerfile命令将生成新的镜像,并且高速缓存将不被使用。
我想现在你应该已经明白了Dockerfile构建过程的缓存机制了,希望这些知识能够帮助你今后更好地使用Dockerfile。
参考文献:
Docker官方对缓存的介绍:
https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#build-cache
更多推荐
所有评论(0)