Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cache local Maven repository using Docker with Pipelines?

I want to run my Maven builds in a Docker container. I don't want to upload all depenedencies with every build, so I tried to mount host's local Maven repository as documented at Using Docker with Pipeline:

Caching data for containers

[...]

Pipeline supports adding custom arguments which are passed to Docker, allowing users to specify custom Docker Volumes to mount, which can be used for caching data on the agent between Pipeline runs. The following example will cache ~/.m2 between Pipeline runs utilizing the maven container, thereby avoiding the need to re-download dependencies for subsequent runs of the Pipeline.

pipeline {
    agent {
        docker {
            image 'maven:3-alpine'
            args '-v $HOME/.m2:/root/.m2'
        }
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn -B'
            }
        }
    }
}

Code

pipeline {
    agent {
        docker { 
            image 'maven:3-alpine' 
            args '-v /home/jenkins/.m2:/root/.m2'
        }    
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn -B clean verify'
            }
        }
    }   
}

Log

Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on jenkins-docker in /home/jenkins/workspace/Test/Docker Test@2
[Pipeline] {
[Pipeline] sh
+ docker inspect -f . maven:3-alpine
.
[Pipeline] withDockerContainer
jenkins-docker does not seem to be running inside a container
$ docker run -t -d -u 1000:1000 -v /home/jenkins/.m2:/root/.m2 -w "/home/jenkins/workspace/Test/Docker Test@2" -v "/home/jenkins/workspace/Test/Docker Test@2:/home/jenkins/workspace/Test/Docker Test@2:rw,z" -v "/home/jenkins/workspace/Test/Docker Test@2@tmp:/home/jenkins/workspace/Test/Docker Test@2@tmp:rw,z" -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** maven:3-alpine cat

[...]

[DEBUG] Reading global settings from /usr/share/maven/conf/settings.xml
[DEBUG] Reading user settings from ?/.m2/settings.xml
[DEBUG] Reading global toolchains from /usr/share/maven/conf/toolchains.xml
[DEBUG] Reading user toolchains from ?/.m2/toolchains.xml
[DEBUG] Using local repository at /home/jenkins/workspace/Test/Docker Test@2/?/.m2/repository
[DEBUG] Using manager EnhancedLocalRepositoryManager with priority 10.0 for /home/jenkins/workspace/Test/Docker Test@2/?/.m2/repository

Problem

After building the ~/m2 directory is empty, no file/directory was added. All files were added under /home/jenkins/workspace/Test/Docker Test@2/?/.m2 (Test is the name of the folder, Docker Test is the name of the pipline).

The problem is that this directory is only used for this particular pipeline not for other pipelines, so I could not share local Maven repository with different pipelines/jobs.

Also my settings.xml is not used, because it is saved under ~/m2.

Is there any solution for sharing local Maven repository and Maven settings with different pipelines using Docker?

like image 218
dur Avatar asked Mar 11 '19 14:03

dur


1 Answers

I found a work-around, see Local settings.xml not picked up by Jenkins agent:

The issue is related to the -u uid:gid that jenkins uses to run the container. As you may know the image you are running only has the user root created, so when jenkins pass its own uid and gid , there is no entry for the user and consequentially no $HOME declared for it.

If you only want to run the build independently of the user, you can use the follow as agent:

agent {
        docker {
            image 'maven:3-alpine'
            args '-v $HOME/.m2:/root/.m2:z -u root'
            reuseNode true
        }
}

A few notes:

  1. if you notice the volume I am using with the flag z, as I am going to build with root, I need to tell docker that this volume will be shared among another containers, and then preventing access denied from my jenkins container (running with the user jenkins not root)
  2. I tell jenkins to reuseNode, so any other stage using the same image, will be executing on the same container (it is just to speed up the provisioning time)

Log

[DEBUG] Reading global settings from /usr/share/maven/conf/settings.xml
[DEBUG] Reading user settings from /root/.m2/settings.xml
[DEBUG] Reading global toolchains from /usr/share/maven/conf/toolchains.xml
[DEBUG] Reading user toolchains from /root/.m2/toolchains.xml
[DEBUG] Using local repository at /root/.m2/repository
[DEBUG] Using manager EnhancedLocalRepositoryManager with priority 10.0 for /root/.m2/repository

Unfortunately the files in local repository /home/jenkins/.m2 are now owned by user root instead of user jenkins. That could cause other problems.

like image 178
dur Avatar answered Nov 03 '22 01:11

dur