Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker build not using layer cache

Given: I want to build a Dockerfile to compile a Scala application. To speedup the build I want the dependency download to be cached.

Problem: The command ./sbt -sbt-dir ./sbt-dir -ivy ./ivy update is not cached for some reason.

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}"

Because this build runs in a new VM all the time I push the workspace image and pull it on the next run to build the cache from it

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

Here is a piece of the output

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

Can anyone explain me why Docker is not using the cache here? A link to a explanation how the cache really decides when to use the cache would be ok as well. As far as I know here Docker should use the cache until the signature of the RUN command changes.

Thanks in Advance

like image 987
fragsalat Avatar asked Jan 18 '18 15:01

fragsalat


People also ask

Are Docker layers cached?

Each layer contains the filesystem changes to the image for the state before the execution of the command and the state after the execution of the command. Docker uses a layer cache to optimize and speed up the process of building Docker images.

How do I create a Docker image without cache?

When you use the Docker build command to build a Docker image, you can simply use the --no-cache option which will allow you to instruct daemon to not look for already existing image layers and simply force clean build of an image.

How do I stop Docker from caching?

Disabling caching You can do so by passing two arguments to docker build : --pull : This pulls the latest version of the base Docker image, instead of using the locally cached one. --no-cache : This ensures all additional layers in the Dockerfile get rebuilt from scratch, instead of relying on the layer cache.

How do I remove cached Docker layers?

Running docker images --no-trunc --format '{{. ID}}' | xargs docker rmi or docker volume prune -f will delete all of the images and their layers from the volume connected to your job.


1 Answers

I found the answer by the way :) The Dockerfile itself was ok except one problem I could then find via docker history Which shows the real shell command which are executed by docker.

The Problem was that ARG BUILD_VERSION lead to docker adds to every run command the environment variable like /bin/sh -c "ARG=123 ./sbt ...". This leads to a different call signature and a different hash every time the arg changes and therefore the run command is not applied from cache. To fix this issue just move the ARG down to the first RUN command which needs it.

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}"
like image 192
fragsalat Avatar answered Sep 21 '22 05:09

fragsalat