当前位置: 首页 > 知识库问答 >
问题:

构建Dockerfile时,是什么导致缓存无效?

邢勇
2023-03-14

我一直在阅读docs编写Dockerfiles的最佳实践。我遇到了小错误(IMHO),在进一步阅读后,其含义很清楚:

在RUN语句中单独使用apt-get更新会导致缓存问题和后续apt-get安装指令失败。

我想知道为什么失败。后来解释了他们所说的“失败”是什么意思:

由于apt get更新未运行,您的构建可能会获得过时版本的curl和nginx包。

但是,对于以下内容,我仍然无法理解他们所说的“如果没有,缓存将无效”是什么意思:

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

这一部分在一些答案中提到,例如Docker如何知道在构建过程中何时使用缓存,何时不使用缓存?总的来说,缓存失效的概念对我来说很清楚,我已经阅读了以下内容:

Docker映像缓存何时失效?Docker使用哪种算法使缓存无效?

但“如果不是”的含义是什么?起初,我确信这个短语的意思是如果找不到这样的图像。这将是过分的——使缓存失效,这可能在以后的其他构建中有用。事实上,当我尝试以下内容时,如果没有找到图像,则不会失效:

$ docker build -t alpine:test1 - <<HITTT
> FROM apline
> RUN echo "test1"
> RUN echo "test1-2"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM apline
pull access denied for apline, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
(base) nb0408:docker a.martianov$ docker build -t alpine:test1 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-2"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Running in 928453d33c7c
test1
Removing intermediate container 928453d33c7c
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-2"
 ---> Running in b068bbaf8a75
test1-2
Removing intermediate container b068bbaf8a75
 ---> daeaef910f21
Successfully built daeaef910f21
Successfully tagged alpine:test1

$ docker build -t alpine:test1-1 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Using cache
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-3"
 ---> Running in 74aa60a78ae1
test1-3
Removing intermediate container 74aa60a78ae1
 ---> 266bcc6933a8
Successfully built 266bcc6933a8
Successfully tagged alpine:test1-1

$ docker build -t alpine:test1-2 - <<HITTT
> FROM alpine
> RUN "test2"
> RUN 
(base) nb0408:docker a.martianov$ docker build -t alpine:test2 - <<HITTT
> FROM alpine
> RUN echo "test2"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test2"
 ---> Running in 1a058ddf901c
test2
Removing intermediate container 1a058ddf901c
 ---> cdc31ac27a45
Step 3/3 : RUN echo "test1-3"
 ---> Running in 96ddd5b0f3bf
test1-3
Removing intermediate container 96ddd5b0f3bf
 ---> 7d8b901f3939
Successfully built 7d8b901f3939
Successfully tagged alpine:test2

$ docker build -t alpine:test1-3 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Using cache
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-3"
 ---> Using cache
 ---> 266bcc6933a8
Successfully built 266bcc6933a8
Successfully tagged alpine:test1-3

缓存再次用于上一次生成。“如果不是”是什么意思?

共有2个答案

谷梁永年
2023-03-14

这句话的措辞应该是:

如果没有,则存在缓存未命中,并且缓存不用于此生成步骤以及Dockerfile此阶段的任何后续生成步骤。

这有点冗长,因为多级Dockerfile可能无法在一个阶段找到缓存匹配,然后在另一个阶段找到匹配。不同的构建都可以使用缓存。缓存对于特定的构建过程是“无效的”,缓存本身不会从docker主机中删除,它仍然可以用于未来的构建

阎知
2023-03-14

让我们关注您的原始问题(关于apt get update),让事情变得更简单。以下示例并非基于任何最佳实践。它只是说明了你试图理解的一点。

假设您有以下Dockerfile:

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y nginx

您可以使用docker build-t myImage: date构建第一个映像。

发生的情况是:

  • 如果ubuntu图像不存在,则将其拉取
  • 一个层被创建并缓存以运行apt-get更新
  • 创建一个层缓存运行apt安装-y nginx

现在假设您将Docker文件修改为

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y nginx openssl

然后使用与之前相同的命令再次运行构建。发生的情况是:

  • 本地已经有一个ubuntu映像,因此它不会被拉取(除非你的原力使用--pull

这是否有助于您掌握缓存层的概念?

在这个特定的例子中,最好的处理方法是在一个单层中做所有的事情,确保你自己清理后:

FROM ubuntu:18.04

RUN apt-get update  \
    && apt-get install -y nginx openssl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

 类似资料:
  • 问题内容: 直到几天前,它仍能正常工作,而当我今天再次尝试构建它时,终端中出现以下错误。我尝试使用多个docker基本映像,但仍给出相同的错误。谁能帮我这个?我不认为我错过了任何东西。如果我错过了,应该早点给我错误,但是现在为什么呢? 而我的docker版本是 这是我的 问题答案: 我刚刚更改了VM Player网络设置。从更改为。现在工作了

  • 我们正在使用@Cacheable和@CacheEvict来实现缓存。 问题是,构建缓存需要3分钟以上。根据应用程序逻辑,首先清除缓存,然后创建缓存。在此期间,如果有任何用户访问我们的应用程序,应用程序将无法发送数据,因为缓存仍在构建中。 是否有任何spring方法可以首先构建缓存,然后用新缓存替换旧缓存(除了@CachePut之外)。 谢谢,斯里坎特。

  • 问题内容: 我目前正在为我的应用程序开发Node后端。在对其进行Docker化(docker build。)时,最长的阶段是。该指令在每个小的服务器代码更改上运行,通过使开发人员每次都等待构建完成来影响生产率。 我发现在应用程序代码所在的位置运行npm install并使用ADD指令将node_modules添加到容器中可以解决此问题,但这远非最佳实践。这有点破坏了将其Docker化的整个想法,并

  • 问题内容: 我在搜索我的网站上具有自动完成/提前输入功能。我看到他们有时是一个例外。我们正在使用代理服务器。 引起原因:java.net.ConnectException:连接被拒绝 这是我的编码方式 谁能告诉我为什么我只在某个时候得到这个例外?是否可能是由于从Android应用程序发出搜索请求而导致此异常,因为我们的网站不支持从android应用程序发出请求 问题答案: 当您尝试打开与IP地址/

  • 问题内容: 我将Java库打包为JAR,当我尝试从中调用方法时会抛出很多s。这些错误似乎随机出现。哪些类型的问题可能导致此错误? 问题答案: 这意味着你对库进行了一些不兼容的二进制更改,而无需重新编译客户端代码。 Java语言规范§13详细介绍了所有这些更改,最显着的是将非非私有字段/方法更改为,反之亦然。 根据新库重新编译客户端代码,你应该一切顺利。 更新:如果发布公共库,则应尽可能避免进行不兼

  • 本文向大家介绍什么是LRU缓存?相关面试题,主要包含被问及什么是LRU缓存?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: LRU(最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高 实现:使用一个链表保存缓存数据,将新数据插入到头部,每当缓存命中时,则将命中的数据移动到链表头部,当链表满的时候,将链表尾部的数据丢弃。