Docker 构建不使用层缓存

fra*_*lat 6 caching scala docker dockerfile

鉴于:我想构建一个 Dockerfile 来编译 Scala 应用程序。为了加速构建,我希望缓存依赖项下载。

问题:由于./sbt -sbt-dir ./sbt-dir -ivy ./ivy update某种原因,该命令没有被缓存。

FROM openjdk:8 as workspace

ARG BUILD_VERSION

WORKDIR /build

COPY ./sbt ./sbt
COPY ./sbt-dist ./sbt-dist
COPY ./build.sbt ./build.sbt
COPY ./project/build.properties ./project/build.properties
COPY ./project/plugins.sbt ./project/plugins.sbt

RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy update

COPY ./ ./

# Embedded postgres need to be run as non-root user
RUN useradd -ms /bin/bash runner
RUN chown -R runner /build
USER runner

RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy clean test
RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy docker:stage -Ddocker.image.version="${BUILD_VERSION}"
Run Code Online (Sandbox Code Playgroud)

因为此构建始终在新 VM 中运行,所以我推送工作区映像并在下次运行时拉取它以从中构建缓存

docker build --rm=false --cache-from=workspace --build-arg BUILD_VERSION=1 -t workspace .
Run Code Online (Sandbox Code Playgroud)

这是输出的一部分

Step 2/22 : ARG BUILD_VERSION
 ---> Using cache
 ---> de98ffcfad8e
Step 3/22 : WORKDIR /build
 ---> Using cache
 ---> 253b71142240
Step 4/22 : COPY ./sbt ./sbt
 ---> Using cache
 ---> 3091fa1e1821
Step 5/22 : COPY ./sbt-dist ./sbt-dist
 ---> Using cache
 ---> f9c68659cd91
Step 6/22 : COPY ./build.sbt ./build.sbt
 ---> Using cache
 ---> d30058c451fc
Step 7/22 : COPY ./project/build.properties ./project/build.properties
 ---> Using cache
 ---> 7451eb63303f
Step 8/22 : COPY ./project/plugins.sbt ./project/plugins.sbt
 ---> Using cache
 ---> 79ac2d1e5ff5
Step 9/22 : RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy update
 ---> Running in 609104e7045e
Getting org.scala-sbt sbt 1.0.3 ...
Run Code Online (Sandbox Code Playgroud)

谁能解释一下为什么 Docker 没有在这里使用缓存?缓存如何真正决定何时使用缓存的解释链接也可以。据我所知,Docker 应该使用缓存,直到 RUN 命令的签名发生变化。

提前致谢

fra*_*lat 8

顺便说一句,我找到了答案:) Dockerfile 本身没问题,但我可以通过docker history它找到一个问题,其中显示了由 docker 执行的真实 shell 命令。

问题是ARG BUILD_VERSION导致 docker 将环境变量添加到每个运行命令中,例如/bin/sh -c "ARG=123 ./sbt ...". 每次 arg 更改时,这都会导致不同的调用签名和不同的哈希值,因此不会从缓存中应用运行命令。要解决这个问题,只需将ARG下移到RUN需要它的第一个命令。

FROM openjdk:8 as workspace

WORKDIR /build

COPY ./sbt ./sbt
COPY ./sbt-dist ./sbt-dist
COPY ./build.sbt ./build.sbt
COPY ./project/build.properties ./project/build.properties
COPY ./project/plugins.sbt ./project/plugins.sbt

RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy update

COPY ./ ./

# Embedded postgres need to be run as non-root user
RUN useradd -ms /bin/bash runner
RUN chown -R runner /build
USER runner

RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy clean test

ARG BUILD_VERSION
RUN ./sbt -sbt-dir ./sbt-dir -ivy ./ivy docker:stage -Ddocker.image.version="${BUILD_VERSION}"
Run Code Online (Sandbox Code Playgroud)

  • 我真的希望有某种方法可以显示或记录它为什么使用缓存或不使用缓存。当我需要阻止缓存时,我已经非常擅长阻止缓存,但我经常希望它缓存以提高性能,并且我知道停止缓存的步骤没有任何变化,但它不缓存。我确实确保尽可能晚地使用 ARG 命令 - 在最后或在需要它之前。 (4认同)