25

How can I mount a volume to store my .m2 repo so I don't have to download the internet on every build?

My build is a Multi stage build:

FROM maven:3.5-jdk-8 as BUILD

COPY . /usr/src/app
RUN mvn --batch-mode -f /usr/src/app/pom.xml clean package

FROM openjdk:8-jdk
COPY --from=BUILD /usr/src/app/target /opt/target
WORKDIR /opt/target
    
CMD ["/bin/bash", "-c", "find -type f -name '*.jar' | xargs java -jar"]
Sandburg
  • 757
  • 15
  • 28
DarVar
  • 16,882
  • 29
  • 97
  • 146
  • 1
    You cannot mount a volume as part of the build process. Builds are meant to be independent from your host. – larsks Jul 05 '18 at 15:16
  • Possible duplicate of [Maven docker cache dependencies](https://stackoverflow.com/questions/42208442/maven-docker-cache-dependencies) – David Maze Jul 05 '18 at 22:23
  • You cannot access volume data during a build. See https://stackoverflow.com/questions/51627401/cant-access-a-volume-during-building-a-docker-image – quasipolynomial Nov 21 '18 at 10:46
  • 1
    @larsks There are things that might benefit from not being independent (package caches which you would otherwise have to pull over the Internet for each build, and for which a given version doesn't change). – ProgrammingLlama Dec 07 '18 at 06:29
  • 1
    I wish I could give your question a bounty just because of "download the internet". That's exactly how I feel! – Bruno Brant May 25 '21 at 20:00

2 Answers2

22

You can do that with Docker >18.09 and BuildKit. You need to enable BuildKit:

export DOCKER_BUILDKIT=1

Then you need to enable experimental dockerfile frontend features, by adding as first line do Dockerfile:

# syntax=docker/dockerfile:experimental

Afterwards you can call the RUN command with cache mount. Cache mounts stay persistent during builds:

RUN --mount=type=cache,target=/root/.m2 \
    mvn --batch-mode -f /usr/src/app/pom.xml clean package
Franklin Piat
  • 3,952
  • 3
  • 32
  • 45
  • 1
    Does this mount the .m2 from host machine into the docker build environment? When I tried to run the container, exec and see what is in the "target" path inside the container, I did not see the same contents as the host machine. It was empty and hence my "mvn -o install" would not work.. – A.R.K.S Aug 20 '19 at 21:06
0

Although the anwer from @Marek Obuchowicz is still valid, here is a small update.

First add this line to Dockerfile:

# syntax=docker/dockerfile:1

You can set the DOCKER_BUILDKIT inline like this:

DOCKER_BUILDKIT=1 docker build -t mytag .

I would also suggest to split the dependency resolution and packagin phase, so you can take the full advantage from Docker layer caching (if nothing changes in pom.xml it will use the cached layer with already downloaded dependencies). The full Dockerfile could look like this:

# syntax=docker/dockerfile:1
FROM maven:3.6.3-openjdk-17 AS MAVEN_BUILD
COPY ./pom.xml ./pom.xml
RUN --mount=type=cache,target=/root/.m2 mvn dependency:go-offline -B
COPY ./src ./src
RUN --mount=type=cache,target=/root/.m2 mvn package

FROM openjdk:17-slim-buster
EXPOSE 8080
COPY --from=MAVEN_BUILD /target/myapp-*.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar","-Xms512M","-Xmx2G","-Djava.security.egd=file:/dev/./urandom"]
Marcin Kunert
  • 5,596
  • 5
  • 26
  • 52