如何在Jenkins流水线中使Maven构件在运行之间保留?

7 浏览
0 Comments

如何在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分钟重新下载它们。

有人能提供一些我做错的见解吗?

提前感谢。

0
0 Comments

问题的原因是在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映像。

0
0 Comments

问题的出现的原因:

用户想要在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教程也建议这样做。

0