DEV Community

Ashim Regmi
Ashim Regmi

Posted on

Make your builds faster using Docker's RUN cache

If you're like me and dislike taking coffee breaks while your entire .m2 directory rebuilds from scratch, or if you're frustrated at the thought of waiting again for the build to complete after making a tiny modification to your pom.xml, don't worry because Docker's RUN cache has got you covered.

In this post, I'll demonstrate how to create a Dockerfile that leverages the RUN cache to efficiently cache a container's .m2 directory. It's worth noting that I'm using a Spring Boot project as an example.

First, let's begin by using a JDK as the base image for 1st stage.

FROM eclipse-temurin:17-jdk-alpine AS build
Enter fullscreen mode Exit fullscreen mode

Second, we mark a directory as our WORKDIR.

WORKDIR /workspace/app
Enter fullscreen mode Exit fullscreen mode

Now, we copy few files necessary to generate our .m2 repository.

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
Enter fullscreen mode Exit fullscreen mode

Next, this is where we use RUN cache.

RUN \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw dependency:resolve-plugins dependency:resolve
Enter fullscreen mode Exit fullscreen mode

Now, copy all the source files. We've waited until this point to ensure that the previous steps are cached by Docker and won't need to be executed every time there's a change in the project's code.

COPY src src
Enter fullscreen mode Exit fullscreen mode

Again, We use the RUN cache to utilize the same local .m2 repository for the maven's package command.

RUN \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw package
Enter fullscreen mode Exit fullscreen mode

Now, we extract the jar so that the next stage can use the extracted files to run the application.

RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
Enter fullscreen mode Exit fullscreen mode

Configure the 2nd stage of the docker build to run the application.

FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.SpringApplication"]
Enter fullscreen mode Exit fullscreen mode

Voilà! Now you have an efficient Dockerfile that respects your valuable time.

Here's a complete version of the Dockerfile.

FROM eclipse-temurin:17-jdk-alpine AS build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw dependency:resolve-plugins dependency:resolve
COPY src src
RUN \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw package
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.SpringApplication"]
Enter fullscreen mode Exit fullscreen mode

Signing off.

Top comments (0)