【问题标题】:Docker build not using layer cacheDocker 构建不使用层缓存
【发布时间】:2018-06-27 17:58:15
【问题描述】:

Given:我想构建一个 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}"

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

docker build --rm=false --cache-from=workspace --build-arg BUILD_VERSION=1 -t workspace .

这是输出的一部分

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 ...

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

提前致谢

【问题讨论】:

    标签: scala docker caching dockerfile


    【解决方案1】:

    我顺便找到了答案 :) 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}"
    

    【讨论】:

      【解决方案2】:

      正如 docker build 输出所示,构建在阶段停止使用缓存:

      4:32:35 PMStep 4/22 : ADD ./sbt ./sbt
      4:32:36 PM---> 7a9e21819cea
      

      发生这种情况是因为主机上的 ./sbt 文件夹发生了变化,因此 docker 将重新运行 ADD 指令。从那时起,docker 将不再使用缓存,因为基础层已失效,导致其后的层也失效。

      更改可能发生在目录的内容中,而是一些微不足道的东西,例如时间戳。

      作为最佳实践,为了利用构建缓存机制,您应该将经常更改的指令延迟到 Dockerfile 的底部。通常,将源代码添加到 docker 映像是这些步骤之一,会在构建之间非常频繁地更改。

      【讨论】:

      • 对不起,我复制了错误的日志输出。请再看一遍
      猜你喜欢
      • 2018-02-06
      • 2021-08-04
      • 2022-07-05
      • 2020-07-05
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 2019-06-30
      • 2019-07-01
      相关资源
      最近更新 更多