在我的本地计算机上,我已经构建了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 \
.
从构建输出中,我们可以看到COPY
的{{1}}没有使用Gemfile
图像中的大小写,而我还没有更新该文件:
latest
旁节点:它在我的本地计算机上运行良好。
在Docker文档Leverage build cache上似乎并不能解释其行为,因为Dockerfile和Gemfile均未更改,因此应使用缓存。
什么使Docker不使用Gemfile缓存?
我尝试使用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
复制设置了正确权限的文件,但是它仍然不使用缓存。
打开的Docker论坛主题:https://forums.docker.com/t/docker-build-not-using-cache-when-copying-gemfile-while-using-cache-from/69186
答案 0 :(得分:2)
在过去的几天里,我一直在努力解决Docker build和--cache-from
的问题,对于缺少--cache-from
的正确行为的文档的了解有点令人沮丧,尽管有在野外有些误传。
在我将在这里分享一些见解之后,我认为我终于设法解决了我身边的问题,希望对其他人有用。
--cache-from
时,顺序很重要!顺序非常重要,因为在第一场比赛中, Docker将停止寻找其他比赛,并将其用于其余所有命令。
This is explained by the fellow who implemented the feature in the Github PR:
使用多个--cache-from时,将按照用户指定的顺序检查它们是否有缓存命中。如果其中一幅图像产生命令命中缓存命中,则只有该图像用于其余的构建。
还有a lenghtier explanation in the initial ticket proposal:
指定多个--cache-from图像有点麻烦。如果两个图像都匹配,则无法(无需多次通过)找出要使用的图像。因此,我们选择第一个(让用户控制优先级),但这可能不是最后我们可以匹配的最长链。如果我们允许针对某些命令与一个映像进行匹配,然后又切换到链较长的其他映像,则由于我们仅验证历史记录和缓存层,因此可能会泄漏映像之间的某些信息。目前,我将其保留下来是为了让我们在找到匹配项时,仅将目标图像用于其余命令。
--cache-from
:将不使用本地Docker缓存这意味着它不会添加新的缓存源,您提供的图像标签将是Docker构建的唯一缓存源。
即使您只是在本地构建了相同的映像,下一次为它运行docker build时,为了从缓存中受益,您还需要:
使用--cache-from
(以及正确的优先级)提供正确的标签;或
完全不使用--cache-from
(这样它将使用本地构建缓存)
例如,如果您有一个基于docker:stable
的图像,并且docker:stable
得到了更新,则随着基础图像层的更改,图像的缓存版本将不再有效。 / p>
答案 1 :(得分:1)
与DockerHub automated builds和--cache-from
交战的人。我意识到,从DockerHub构建的映像在被拉起并用作构建缓存源时,总是会导致COPY
命令的缓存崩溃。 @Marcelo(引用his comment)似乎也是如此。
我通过创建一个非常简单的图像进行了研究,该图像使用了两个RUN
命令以及后来的COPY
。除COPY
外,所有内容都在使用缓存。即使要复制的文件的内容和权限在拉出的映像和本地生成的映像上都是相同的(通过sha1sum
和ls -l
验证)。
对我来说,解决方案是从CI(在我的情况下为Travis)将映像发布到注册表,而不是让DockerHub自动构建。在这里让我强调一下,我在这里谈论的是一种特定情况,即文件绝对相同并且不应缓存崩溃,但是您正在使用DockerHub自动构建。
我不确定为什么会这样,但是我知道例如旧的docker-engine版本,例如之前的1.8.0并没有忽略文件时间戳来决定是否使用缓存,请参考https://docs.docker.com/release-notes/docker-engine/#180-2015-08-11和https://github.com/moby/moby/pull/12031。
答案 2 :(得分:1)
我一直在努力解决这个问题,就我而言,当校验和可能发生变化时,我使用了 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/
然后,我可以运行以下命令:
# build cache
DOCKER_BUILDKIT=1 docker build --target base-builder -t myapp-builder .
docker push myapp-builder
# use cache
DOCKER_BUILDKIT=1 docker build --target myapp --build-arg=builder_image=myapp-builder -t myapp .
docker push myapp
这样我们就可以强制 Docker 使用预构建的镜像作为缓存。
答案 3 :(得分:0)
要缓存COPY
命令,要复制的源上的校验和必须相同。您可以在Docker历史记录输出中将缓存映像与您刚刚构建的校验和进行比较。最重要的是,除了文件内容之外,校验和还包括元数据,例如文件所有者和文件权限。文件内部的空白更改(例如更改为Linux和Windows样式之间的换行符)也会影响这一点。如果您从存储库下载代码,则元数据(例如所有者)可能与缓存的值不同。