Optimizing Maven Builds with Gitlab Docker Runner

Maven Aug 2, 2020

Maven is a great build tool. Although it's based on XML, it's still manageable XML. Easy to understand, easy to write.

It also is a quite simple build tool, the only thing we need, in terms of Java/Kotlin/any other JVM based language is a pom.xml ("Project Object Model"... makes sense in hindsight, but I could have never guessed it)

Maven and Gitlabs Docker Runners

Today we would like to promote the usage of Maven as a build tool with Gitlabs Docker Runner. And there is not much we can do wrong by using Maven and Gitlab Docker Runners, except two things.

Since Maven in contrast to other build dependency management solutions stores its general settings not in the before mentioned pom.xml but rather uses a dedicated settings.xml and a dedicated cache folder in the .m2 folder of the user directory, its performance in combination with Docker is open for improvements.

Mind you, nothing impossible there, but also not as straight forward as with other solutions like composer and npm

So lets address these two pain points, shall we?

Caching Maven Dependencies with Gitlabs Docker Runner

Actually, it's quite simple, but takes a bit of digging through the World Wide Web to find the solution, which is as simple as an environment variable. In our case we found it best to utilize the MAVEN_OPTS environment variable setting its value to -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository

build_maven:
  variables:
    MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  cache:
    paths:
      - ./.m2/repository/
  image: maven:3-jdk-12-alpine
  stage: build
  script:
    - mvn clean verify
  only:
    - master
    - develop

What we can see from the example above is that we set the Maven local repository to the current build directory, which in turn now, as Gitlab is only able to cache stuff within the current project directory, enables Gitlab to cache our dependencies.

Of course, depending on the size of our project this could be a huge performance impact of our builds, or a really marginal one. Nevertheless, as our project grows, we definitely want to have those cody bits in there to save some time.

Using a settings.xml in our Build Project

Maybe, just maybe, we are one of the majorities that don't have their artifacts shipped to mvnrepository.com. That's fine, since most of the work a normal developer does is proprietary software, we probably have our own JFrog Artifactoy or Sonatype Nexus Repository setup within our company.

But that also means standard mvnwouldn't know about it, that's why we generate a fancy settings.xml out of those tools, put it into our .m2 folder on our development machine and be happy about it.

But as soon as CI/CD hits, we are faced with the question:

How can my Docker Runner use such a configuration?

And the answer is also, quite simple again.

mvn --settings $MAVEN_SETTINGS_XML clean deploy

Cheesy right? Gitlab offers the possibility to provide environment variables during build jobs, and we should utilize that possibility, create an CI/CD user for our repository, and copy the generated settings XML into such an environment variable.

Mind the type of that variable though: File.

Gitlab here is putting the content we put in there into a file on the file system referencing the path to it via the environment variable, which we are passing tomvn.

So effectively we are passing a path to it, not an inline version of the settings.xml

This way and with the mvn option --settings we can pass those settings to Maven in order to be utilized by the build it's about to be doing for us.

Congratulations!

To be honest, it's not rocket science, and we can probably get away without optimizing our CI/CD pipeline in such a manner, but putting the time into making our CI/CD as efficient as possible will definitely help us in the long run!

Feel free to copy the combined example of both our above explained techniques.

build_maven:
  variables:
    MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  cache:
    paths:
      - ./.m2/repository/
  image: maven:3-jdk-12-alpine
  stage: artifactory
  script:
    - mvn --settings $MAVEN_SETTINGS_XML clean deploy
  only:
    - master
    - develop

Tags

Nico Filzmoser

Hi! I'm Nico 😊 I'm a technology enthusiast, passionate software engineer with a strong focus on standards, best practices and architecture… I'm also very much into Machine Learning 🤖