我一直在阅读文档编写 Dockerfiles 的最佳实践。我遇到了小错误(恕我直言),在进一步阅读后,其含义很清楚:
在 RUN 语句中单独使用 apt-get update 会导致缓存问题并且随后的 apt-get install 指令失败。
我想知道为什么失败。后来他们解释了“失败”的含义:
由于 apt-get 更新未运行,因此您的构建可能会获得过时版本的 curl 和 nginx 包。
但是,对于以下内容,我仍然无法理解“如果不是,则缓存无效。”的含义:
从已经在缓存中的父映像开始,下一条指令与从该基本映像派生的所有子映像进行比较,以查看其中一个是否是使用完全相同的指令构建的。如果不是,则缓存无效。
这部分在 SO 的一些答案中提到,例如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
Run Code Online (Sandbox Code Playgroud)
缓存再次用于上次构建。文档中的“如果不是”是什么意思?
让我们专注于您原来的问题(关于apt-get update)以使事情变得更容易。以下示例不基于任何最佳实践。它只是说明了您想要理解的观点。
假设您有以下 Dockerfile:
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y nginx
Run Code Online (Sandbox Code Playgroud)
您使用构建第一个图像docker build -t myimage:latest .
发生的情况是:
apt-get updateapt install -y nginx现在假设您将 Docker 文件修改为
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y nginx openssl
Run Code Online (Sandbox Code Playgroud)
然后使用与之前相同的命令再次运行构建。发生的情况是:
--pull)apt-get update因此它使用缓存的图像nginx 和 openssl。由于 apt 数据库是在前一层创建并从缓存中获取的,因此如果此后发布了新的 nginx 和/或 openssl 版本,您将看不到它们,并且将安装过时的版本。这是否有助于您掌握缓存层的概念?
在这个特定的示例中,最好的处理是在单层中完成所有操作,确保您自己进行清理:
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -y nginx openssl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Run Code Online (Sandbox Code Playgroud)
这句话的措辞最好这样说:
如果不是,则存在缓存未命中,并且缓存不会用于此构建步骤以及 Dockerfile 此阶段的任何后续构建步骤。
这有点冗长,因为多阶段 Dockerfile 可能无法在一个阶段找到缓存匹配,然后在另一个阶段找到匹配。不同的构建都可以使用缓存。缓存对于特定的构建过程“无效”,缓存本身不会从 docker 主机中删除,并且它继续可用于将来的构建。
| 归档时间: |
|
| 查看次数: |
2079 次 |
| 最近记录: |