demo-springboot-simple 仓库地址为:https://github.com/MingGH/demo-springboot-simple
这里详细的给大家说明一下,先放一下完整的Jenkinsfile。
pipeline {
agent {
docker {
image 'maven:3.8-openjdk-17'
args '-v /root/.m2:/root/.m2 -v /root/.ssh:/root/.ssh'
}
}
stages {
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Unit Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Push Nexus') {
steps {
script {
POM_VERSION = sh (
script: 'mvn spring-boot:build-info | grep Building | awk \'{split(\$0,r," "); print r[4]}\'',
returnStdout: true
).trim()
//update version for prod env, remove -SNAPSHOT
if ("${params.ENV_INFO}" == "prod") {
JAR_VERSION_WITHOUT_SNAPSHOT = sh (
script: "echo ${POM_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' ",
returnStdout: true
).trim()
sh "mvn versions:set -DnewVersion=${JAR_VERSION_WITHOUT_SNAPSHOT}"
JAR_FINAL_VERSION = sh (
script: "echo ${JAR_VERSION_WITHOUT_SNAPSHOT} ",
returnStdout: true
).trim()
}else {
JAR_FINAL_VERSION = sh (
script: "echo ${POM_VERSION} ",
returnStdout: true
).trim()
}
}
sh 'mvn clean install org.apache.maven.plugins:maven-deploy-plugin:2.8:deploy -DskipTests'
}
}
stage('Package Image') {
steps {
script {
sh 'mvn clean package dockerfile:build -DskipTests'
}
}
}
stage('Push Image') {
steps {
script {
sh "sh deploy_docker.sh push ${JAR_FINAL_VERSION} ${params.ENV_INFO} "
}
}
}
stage('Deploy') {
steps {
script {
//
if ("${params.Deploy_Port}" == "default") {
sh "sh deploy_docker.sh restart ${JAR_FINAL_VERSION} ${params.ENV_INFO} "
}else{
sh "sh deploy_docker.sh restart ${JAR_FINAL_VERSION} ${params.ENV_INFO} ${params.Deploy_Port}"
}
}
}
}
stage('Update version') {
steps {
script {
JAR_FINAL_VERSION = sh (
script: 'mvn spring-boot:build-info | grep Building | awk \'{split(\$0,r," "); print r[4]}\'',
returnStdout: true
).trim()
MAJOR_VERSION = sh (
script: "echo ${JAR_FINAL_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' | awk '{split(\$0,r,\".\"); print r[1] \".\" r[2]}\' ",
returnStdout: true
).trim()
UPDATED_VERSION = sh (
script: "echo ${JAR_FINAL_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' | awk '{split(\$0,r,\".\"); print r[3]}' | awk '{value=1+\$1} END{print value}' ",
returnStdout: true
).trim()
sh "git branch -D ${params.GIT_Branch} || true"
sh "git checkout -b ${params.GIT_Branch} || true"
sh "mvn versions:set -DnewVersion=${MAJOR_VERSION}.${UPDATED_VERSION}-SNAPSHOT"
sh "git config user.email xxxxx@sample.com"
sh "git config user.name xxxxx"
sh "git commit -a -m 'Triggered Build: update pom version'"
sh "git push -u origin ${params.GIT_Branch}"
}
}
}
}
}
Jenkins agent
首先是Jenkins agent部分,因为Jenkins采用的是“master+agent(slave)”架构。Jenkins master负责提供界面、处理HTTP请求及管理构建环境;构建的执行则由Jenkins agent负责。Jenkins agent作为一个负责执行任务的程序。
这里定义的agent是一个maven的Docker 容器,当Jenkins运行时会通过宿主机的docker创建一个maven的容器,并且映射宿主机的/root/.m2
目录和/root/.ssh
目录,获取到GitHub权限
agent {
docker {
image 'maven:3.8-openjdk-17'
args '-v /root/.m2:/root/.m2 -v /root/.ssh:/root/.ssh'
}
}
Build stage,
使用agent中的maven进行build,这里是跳过unit test的
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
Unit Test stage
这里的 [junit](https://www.jenkins.io/doc/pipeline/steps/junit/#code-junit-code-archive-junit-formatted-test-results)
step (由 JUnit Plugin 提供)用于归档JUnit XML报告(由上面的 mvn test
命令生成) 并通过Jenkins接口公开结果。在Blue Ocean中,可以在流水线运行的 Tests 页面获取结果。 而post
的 always
条件包含了这个 junit
step, 保证了这个step总是在 Test
阶段 结束后 执行,不论该阶段的运行结果如何。
stage('Unit Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
Push Nexus Stage
POM_VERSION = sh (script: 'shell script', returnStdout: true).trim()
可以通过执行shell,并且把shell的输出结果返回给定义的变量,名称是自定义的。
mvn spring-boot:build-info
可以通过maven获取到当前项目的版本信息,长这样
asher@Ashers-Mac demo-springboot-simple % mvn spring-boot:build-info
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< run.runnable:demo-springboot-simple >-----------------
[INFO] Building demo-springboot-simple 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.1:build-info (default-cli) @ demo-springboot-simple ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.430 s
[INFO] Finished at: 2023-01-04T18:59:54+08:00
[INFO] ------------------------------------------------------------------------
所以还需要一些操作来进行版本的提取,通过grep Building | awk '{split($0,r," "); print r[4]}'
来完成。
再接着就是判断Jenkins执行时传入的参数是dev
还是prod
来推送到具体的maven仓库。
${params.ENV_INFO}
表示可以通过${params.<jenkins上定义的参数>}
获取到Jenkins pipline上配置的参数。
mvn versions:set -DnewVersion=
可以更新当前项目的版本号
在这步stage中,完成的操作是拿到项目的版本号,然后判断Jenkins执行的是dev还是prod,如果是prod,那么则更新版本号为不带-SNAPSHOT
的版本号,则会推送到生产库。并把这个最后确认的版本号赋值给JAR_FINAL_VERSION。
stage('Push Nexus') {
steps {
script {
POM_VERSION = sh (
script: 'mvn spring-boot:build-info | grep Building | awk \'{split(\$0,r," "); print r[4]}\'',
returnStdout: true
).trim()
//update version for prod env, remove -SNAPSHOT
if ("${params.ENV_INFO}" == "prod") {
JAR_VERSION_WITHOUT_SNAPSHOT = sh (
script: "echo ${POM_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' ",
returnStdout: true
).trim()
sh "mvn versions:set -DnewVersion=${JAR_VERSION_WITHOUT_SNAPSHOT}"
JAR_FINAL_VERSION = sh (
script: "echo ${JAR_VERSION_WITHOUT_SNAPSHOT} ",
returnStdout: true
).trim()
}else {
JAR_FINAL_VERSION = sh (
script: "echo ${POM_VERSION} ",
returnStdout: true
).trim()
}
}
sh 'mvn clean install org.apache.maven.plugins:maven-deploy-plugin:2.8:deploy -DskipTests'
}
}
Package Image Stage
mvn clean package dockerfile:build -DskipTests
可以通过maven构建docker镜像。需要搭配pom.xml中的plugin,在之后会讲到。
stage('Package Image') {
steps {
script {
sh 'mvn clean package dockerfile:build -DskipTests'
}
}
}
Push Image Stage
在Push Nexus Stage确定的版本号JAR_FINAL_VERSION
将在这一步推送给到Docker容器镜像仓库, 需要结合另一个配置文件deploy_docker.sh
来进行使用。
stage('Push Image') {
steps {
script {
sh "sh deploy_docker.sh push ${JAR_FINAL_VERSION} ${params.ENV_INFO} "
}
}
}
Deploy Stage
这个stage需要和3.1步中的一个参数Deploy_Port
关联起来,如果是default,则端口使用deploy_docker.sh
中配置的,如果有值,则覆盖deploy_docker.sh
中的配置
stage('Deploy') {
steps {
script {
//
if ("${params.Deploy_Port}" == "default") {
sh "sh deploy_docker.sh restart ${JAR_FINAL_VERSION} ${params.ENV_INFO} "
}else{
sh "sh deploy_docker.sh restart ${JAR_FINAL_VERSION} ${params.ENV_INFO} ${params.Deploy_Port}"
}
}
}
}
Update Version Stage
在这个stage中需要修改你的git邮箱地址和username,因为在步骤2.4中已经配置了公钥在GitHub上,**且在Jenkins agent 中配置了/root/.ssh
的目录映射,**所以这里只需要配置用户名和邮箱就行。
使用之前获取到的JAR_FINAL_VERSION,拿到最小的那个版本号,比如当前版本是:1.2.3-SNAPSHOT,那么MAJOR_VERSION=**1.2
,**UPDATED_VERSION=1+3=4
最后通过git进行提交到GitHub,在当中需要配置你的用户名和邮箱
stage('Update version') {
steps {
script {
JAR_FINAL_VERSION = sh (
script: 'mvn spring-boot:build-info | grep Building | awk \'{split(\$0,r," "); print r[4]}\'',
returnStdout: true
).trim()
MAJOR_VERSION = sh (
script: "echo ${JAR_FINAL_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' | awk '{split(\$0,r,\".\"); print r[1] \".\" r[2]}\' ",
returnStdout: true
).trim()
UPDATED_VERSION = sh (
script: "echo ${JAR_FINAL_VERSION} | awk '{split(\$0,r,\"-\"); print r[1]}' | awk '{split(\$0,r,\".\"); print r[3]}' | awk '{value=1+\$1} END{print value}' ",
returnStdout: true
).trim()
sh "git branch -D ${params.GIT_Branch} || true"
sh "git checkout -b ${params.GIT_Branch} || true"
sh "mvn versions:set -DnewVersion=${MAJOR_VERSION}.${UPDATED_VERSION}-SNAPSHOT"
sh "git config user.email xxxxx@sample.com"
sh "git config user.name xxxxx"
sh "git commit -a -m 'Triggered Build: update pom version'"
sh "git push -u origin ${params.GIT_Branch}"
}
}
}