使用--cache-from复制Gemfile时,Docker构建未使用缓存

Zed*_*TuX 6 caching docker

在本地计算机上,我已经构建了latest映像,并docker build在应有的位置运行另一个使用缓存。

然后,将映像作为上载到注册表latest,然后在CI服务器上,提取latest应用程序的映像,以将其用作构建缓存来构建新版本:

docker pull $CONTAINER_IMAGE:latest

docker build --cache-from $CONTAINER_IMAGE:latest \
             --tag $CONTAINER_IMAGE:$CI_COMMIT_SHORT_SHA \
             .
Run Code Online (Sandbox Code Playgroud)

从构建输出中,我们可以看到的COPYGemfile没有使用图片中的大小写latest,而我还没有更新该文件:

Step 15/22 : RUN gem install bundler -v 1.17.3 &&     ln -s /usr/local/lib/ruby/gems/2.2.0/gems/bundler-1.16.0 /usr/local/lib/ruby/gems/2.2.0/gems/bundler-1.16.1
 ---> Using cache
 ---> 47a9ad7747c6
Step 16/22 : ENV BUNDLE_GEMFILE=$APP_HOME/Gemfile     BUNDLE_JOBS=8
 ---> Using cache
 ---> 1124ad337b98
Step 17/22 : WORKDIR $APP_HOME
 ---> Using cache
 ---> 9cd742111641
Step 18/22 : COPY Gemfile $APP_HOME/
 ---> f7ff0ee82ba2
Step 19/22 : COPY Gemfile.lock $APP_HOME/
 ---> c963b4c4617f
Step 20/22 : RUN bundle install
 ---> Running in 3d2cdf999972
Run Code Online (Sandbox Code Playgroud)

旁节点:它在我的本地计算机上运行良好。

查看Docker文档杠杆构建缓存似乎没有在此解释行为,因为Dockerfile和Gemfile均未更改,因此应使用缓存。

是什么让Docker不使用Gemfile缓存?

更新资料

我尝试使用来复制设置了正确权限的文件,COPY --chown=user:group source dest但仍不使用缓存。

打开Docker论坛主题:https : //forums.docker.com/t/docker-build-not-using-cache-when-copying-gemfile-while-using-cache-from/69186

Eli*_*les 10

--cache-from在过去的几天里,我一直在努力解决Docker构建问题--cache-from,而对于的正确行为,缺少文档也令人感到沮丧,而实际上却存在一些错误信息。

我认为,在我将在这里分享一些见解之后,我终于设法解决了我身边的问题,希望对其他人有用。

提供多个时--cache-from,顺序很重要!

该顺序非常重要,因为在第一个匹配项中,Docker将停止寻找其他匹配项,并将其用于其余所有命令

这是由在Github PR中实现该功能的人解释的

当使用多个--cache-from时,将按照用户指定的顺序检查是否有缓存命中。如果其中一幅图像产生命令命中的高速缓存命中,则仅该图像用于其余的构建。

初始购票提议中还有一个更简短的解释

指定多个--cache-from图像有点麻烦。如果两个图像都匹配,则无法(无需多次通过)找出要使用的图像。因此,我们选择第一个(让用户控制优先级),但这可能不是最后我们可以匹配的最长链。如果我们允许针对某个命令匹配一个映像,然后又切换到链较长的另一个映像,则由于我们仅验证历史记录和缓存层,因此可能会泄漏映像之间的某些信息。目前,我已将其保留下来,这样,如果我们找到匹配项,则其余命令只使用该目标图像。

使用--cache-from是专有的:将不使用本地Docker缓存

这意味着它不会添加新的缓存源,您提供的图像标签将是Docker构建的唯一缓存源。

即使您只是在本地构建了相同的映像,下一次为它运行docker build时,为了从缓存中受益,您还需要:

  1. 提供正确的标签--cache-from(并具有正确的优先级);要么

  2. 完全不使用--cache-from(以便它将使用本地构建缓存)

如果父映像更改,则缓存将失效

例如,如果您有一个基于的图像docker:stabledocker:stable进行了更新,则由于基础图像的层已更改,因此图像的缓存版本将不再有效。

这就是为什么,如果您要配置CI构建,那么它对于docker pull基础映像也很有用,并将其包含在中--cache-from,如本注释在另一个Github讨论中所述


Den*_*s V 5

我一直在努力解决这个问题,在我的例子中,当校验和可能发生变化时,我使用了 COPY(但仅在技术上,内容在功能上是相同的)。所以,我这样解决:

Dockerfile:

ARG builder_image=base-builder

# Compilation/build stage
FROM golang:1.16 AS base-builder
RUN echo "build the app" > /go/app

# This step is required to facilitate docker cache. With the definition of a `builder_image` build tag
# we can essentially skip the build stage and use a prebuilt-image directly.
FROM $builder_image AS builder

# myapp docker image
FROM ubuntu:20.04 AS myapp

COPY --from=builder /go/app /opt/my-app/bin/
Run Code Online (Sandbox Code Playgroud)

然后,我可以运行以下命令:

ARG builder_image=base-builder

# Compilation/build stage
FROM golang:1.16 AS base-builder
RUN echo "build the app" > /go/app

# This step is required to facilitate docker cache. With the definition of a `builder_image` build tag
# we can essentially skip the build stage and use a prebuilt-image directly.
FROM $builder_image AS builder

# myapp docker image
FROM ubuntu:20.04 AS myapp

COPY --from=builder /go/app /opt/my-app/bin/
Run Code Online (Sandbox Code Playgroud)

这样我们就可以强制 Docker 使用预构建的镜像作为缓存。


BMi*_*tch 1

对于COPY要缓存的命令,校验和需要与正在复制的源上相同。您可以比较缓存映像与刚刚构建的映像之间的 docker 历史记录输出中的校验和。最重要的是,除了文件内容之外,校验和还包括文件所有者和文件权限等元数据。文件内的空格更改(例如更改 Linux 和 Windows 样式之间的换行符)也会影响这一点。如果您从存储库下载代码,则元数据(例如所有者)可能与缓存的值不同。

  • 谢谢你的评论,我会看看的。另外请注意,您对校验和中包含的修改时间的看法是错误的,因为文档说“这些校验和中不考虑文件的上次修改时间和上次访问时间。” (请参阅我的“利用构建缓存”链接;)) (2认同)