【发布时间】:2023-03-05 07:31:01
【问题描述】:
我一直在阅读文档Best practices for writing Dockerfiles。我遇到了一些小错误(恕我直言),进一步阅读后含义很清楚:
在 RUN 语句中单独使用 apt-get update 会导致缓存问题 以及随后的 apt-get 安装说明失败。
我想知道为什么会失败。后来解释了他们所说的“失败”:
因为 apt-get update 没有运行,你的构建可能会得到 curl 和 nginx 软件包的过时版本。
但是,对于以下内容,我仍然无法理解“如果不是,则缓存无效。”的含义:
从已经在缓存中的父图像开始,下一个 将指令与从该指令派生的所有子图像进行比较 基本图像以查看其中一个是否是使用完全相同的 操作说明。如果不是,则缓存失效。
在一些关于 SO 的答案中提到了这部分,例如How does Docker know when to use the cache during a build and when not? 总的来说,缓存失效的概念对我来说很清楚,我读过以下内容:
When does Docker image cache invalidation occur? Which algorithm Docker uses for invalidate cache?
但是“如果不是”是什么意思呢?起初我确信这句话的意思是如果没有找到这样的图像。那将是矫枉过正 - 使缓存无效,这可能在以后对其他构建有用。实际上,如果我在下面尝试时没有找到图像,它不会失效:
$ 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
缓存再次用于上次构建。 docs 中的“如果不是”是什么意思?
【问题讨论】:
-
这个短语“如果不是”是指使用与先前运行相同的指令构建层的命令。简单地说,如果命令不同,则层缓存失效从该点开始,并沿 Dockerfile 向下流动。
-
@halfer,但是缓存并没有失效,只是没有用于这个构建,这与
cache invalidation的常用用法有很大不同 -
缓存不是每个容器,而是每个容器层。每个命令都会创建一个位于旧层之上的新层。因此,层会因更改的命令以及之后的所有内容而失效。更改命令之前缓存中的层仍在构建中使用。
-
您可以在第二次构建中看到这一点 -
Step 2/3 : RUN echo "test1"已缓存,但Step 3/3 : RUN echo "test1-3"未缓存。
标签: docker dockerfile