如何在Jenkins流水线中使Maven构件在运行之间保留?
如何在Jenkins流水线中使Maven构件在运行之间保留?
我们有一个使用Maven构建的Java项目,我们希望在Jenkins BlueOcean流水线中运行。
我按照这个教程进行操作。这个流水线可以执行我们的代码。耶!
然而,每当我们的流水线的'build'阶段在新的Jenkins运行下执行时,它会重新下载所有的Maven构件。这大大增加了我们的构建时间。
我使用以下命令启动'jenkins-docker'容器:
docker container run --name jenkins-docker --rm --detach \ --privileged --network jenkins --network-alias docker \ --env DOCKER_TLS_CERTDIR=/certs \ --volume jenkins-docker-certs:/certs/client \ --volume jenkins-data:/var/jenkins_home \ --publish 2376:2376 docker:dind
以及使用以下命令启动'jenkins-blueocean'容器:
docker container run --name jenkins-blueocean --rm --detach \ --network jenkins --env DOCKER_HOST=tcp://docker:2376 \ --env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 \ --volume jenkins-data:/var/jenkins_home \ --volume jenkins-docker-certs:/certs/client:ro \ --publish 8080:8080 --publish 50000:50000 jenkinsci/blueocean
然后我们的Jenkinsfile流水线如下:
pipeline {
agent {
docker {
image 'maven:3.6.3-jdk-8'
args '-v /root/.m2:/root/.m2'
}
}
stages {
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
}
}
这里,Jenkins启动一个新的'maven:3.6.3-jdk-8'的docker镜像来运行。它还映射了一个卷来持久化.m2目录,据我所知。
由于我的'jenkins-docker'实例在构建之间没有关闭,我希望将这个.m2目录持久化。这样,每次连续运行都可以利用已下载构件的缓存,而不需要花费5分钟重新下载它们。
有人能提供一些我做错的见解吗?
提前感谢。
问题的原因是在Jenkins流水线中,Maven构件在运行之间不会持久化。这是因为Docker实例运行构建时,没有自动设置user.home
变量,导致每次构建执行时,它会将.m2构件存储在包含一个?
的路径下。根据一个类似的问题,Maven Docker映像期望将构件下载到/root/.m2
。这表明Maven Docker映像使用/root
作为其主目录。
解决方法是在Jenkinsfile中添加一个指令,让Maven Docker实例正确使用其默认主目录。然后通过解决权限问题,将卷直接映射到Maven Docker映像的/root
目录。这与Jenkins教程中的设置不同,教程中将其映射到/root/.m2
。
为了确保不同的构建不会同时使用相同的本地仓库,可以通过限制Jenkins同时只执行一个作业来解决。但是,仍然需要缓存.m2目录,以避免不断重新下载构件。这在这种情况下尤为重要。
总结起来,可以使用以下Jenkinsfile来解决问题:
environment { JAVA_TOOL_OPTIONS = '-Duser.home=/root' } agent { docker { image 'maven:3.6.3-jdk-8' args '-v /var/jenkins_home:/root' } } stages { stage('Build') { steps { sh 'mvn -B -DskipTests clean compile' } } stage('Test') { steps { sh 'mvn -X test' jacoco() } post { always { junit 'target/surefire-reports/*.xml' } } } }
需要注意的是,如果使用相同的Maven坐标构建多个分支,有可能使用来自不同分支的构件,这通常不是一个好主意。
Jenkins官方文档建议按照上述方法进行设置。如果有任何反对意见,可以提供一个完整的答案,展示如何在Jenkins蓝海流水线构建中使用maven:3.6.3-jdk-8 Docker映像。
问题的出现的原因:
用户想要在Jenkins流水线中持久化Maven构件,避免每次运行都重新下载构件,但是目前的方法无法实现这一需求。
解决方法:
1. 不要共享/持久化.m2文件夹,因为Maven不是线程安全的。最简单的方法是设置一个Maven镜像仓库(如Nexus),并告诉Docker中的Maven构建使用该镜像仓库作为镜像源。这仍然需要从镜像仓库下载所有构件。
2. 可以将本地仓库附加到每个agent,并重复使用它(因此每次最多只会被一个构建使用)。但是需要先创建该仓库,这不再是最简单的解决方法。
3. 对于声称.m2仓库不是线程安全的主张,希望能提供引用。据我了解,.m2缓存通常用于在构建服务器上存储依赖项。Jenkins教程也建议这样做。
整理成的文章如下:
多种解决方案可行。不要共享/持久化.m2文件夹,因为Maven不是线程安全的(至少在我上次查看时是这样,现在可能已经修复了)。
最简单的方法是设置一个Maven镜像仓库(例如Nexus),并告诉Docker中的Maven构建使用该镜像仓库作为镜像源。
这仍然意味着你需要从镜像仓库下载所有构件。是的,这是最简单的方法。还存在更巧妙的解决方案,这是Maven显示其年龄的方式之一。
我认为你也可以将本地仓库附加到每个agent,并重复使用它(因此每次最多只会被一个构建使用)。顺便说一句,我没有对你的答案进行downvote。
是的,但你必须首先创建它,然后它就不再是最简单的解决方案了。至于downvotes - 如果那些随便点赞的人不留下对他或她不喜欢的东西的评论,我倒不介意,因为信息仍然是正确的。
这应该是一个评论,而不是一个答案。对于声称.m2仓库不是线程安全的主张,希望能提供引用。据我了解,.m2缓存通常用于在构建服务器上存储依赖项。Jenkins教程也建议这样做。