Docker 如何知道在构建期间何时使用缓存,何时不使用缓存?

我对 Docker 的缓存层的工作效果感到惊讶,但我也想知道它是如何决定是否可以使用缓存层的。

让我们以下面这些构建步骤为例:

Step 4 : RUN npm install -g   node-gyp
---> Using cache
---> 3fc59f47f6aa
Step 5 : WORKDIR /src
---> Using cache
---> 5c6956ba5856
Step 6 : COPY package.json .
---> d82099966d6a
Removing intermediate container eb7ecb8d3ec7
Step 7 : RUN npm install
---> Running in b960cf0fdd0a

例如,它如何知道它可以使用缓存层的 npm install -g node-gyp,但创建一个新的层的 npm install

26332 次浏览

这是因为您的 package.json文件已被修改,请参阅 Removing intermediate container

这也是为什么包管理器(供应商/第三方)信息文件在 docker build期间首先被 COPY’的原因。之后运行包管理器安装,然后添加应用程序的其余部分,即 src

如果您没有对库进行任何更改,那么这些步骤将从构建缓存中提供。

构建缓存过程在 编写 Dockerfiles 的最佳实践: 利用构建缓存小节中有相当详细的解释。

  • 从已经在缓存中的父映像开始,下一条指令将与从该基础映像派生的所有子映像进行比较,以查看是否使用完全相同的指令构建了其中一个子映像。否则,缓存将失效。

  • 在大多数情况下,只需将 Dockerfile中的指令与其中一个子映像进行比较即可。然而,某些指示需要更多的检查和解释。

  • 对于 ADDCOPY指令,检查图像中文件的内容,并为每个文件计算校验和。在这些校验和中不考虑文件的最后修改和最后访问的时间。在缓存查找过程中,会将校验和与现有映像中的校验和进行比较。如果文件中有任何更改,例如内容和元数据,那么缓存将失效。

  • 除了 ADDCOPY命令之外,缓存检查不会查看容器中的文件来确定缓存匹配。例如,在处理 RUN apt-get -y update命令时,不检查容器中更新的文件以确定是否存在缓存命中。在这种情况下,只使用命令字符串本身来查找匹配项。

一旦缓存失效,所有后续的 Dockerfile命令将生成新的映像,并且不使用缓存。

你会遇到这样的情况: OS 包、 NPM 包或 Git 回购被更新到更新的版本(比如 package.json中的 ~2.3 semver) ,但是由于你的 Dockerfilepackage.json还没有更新,docker 将继续使用缓存。

通过修改某些智能检查上的行(例如从 repo 检索最新的 git 分支 shasum,以便在克隆指令中使用) ,可以通过编程方式生成一个 Dockerfile来破坏缓存。还可以使用 --no-cache=true定期运行构建,以强制执行更新。