到了当前阶段流水线阶段,我们需要配置mvn去打包,sonarqube,以及容器的镜像构建,这些东西都会被安排到流水线上,直到docker镜像构建完成,此阶段,我将一个docker镜像构建完成视作为一个制品的完成。这些流程被放置在一起,因此称作持续集成。当然,这在这里只是一个非常简单的模型。
阅读此篇,你将了解如下列表中简单的实现方式:
- jenkins和gitlab触发(上一章实现)
- jenkins凭据使用(上一章实现)
- juit配置(本章实现)
- sonarqube简单扫描(本章实现)
- sonarqube简单分支扫描(本章实现)
- sonarqube覆盖率(本章实现)
- sonarqube与gitlab关联
- 配置docker中构建docker
- mvn打包
- 打包基于java的skywalking agent(上一章实现)
- 基于gitlab来管理kustomize的k8s配置清单
- kubectl部署
- kubeclt deployment的状态跟踪
- 钉钉消息的构建状态推送
开始
- 下载一个java程序包
另外,为了演示这个效果,我们需要一个合适的jar包来测试,而不是在前面提供的那个hello-world的包。于是在https://start.spring.io/页面默认选择,选择java 8,而后点击CENERATE下载demo包,解压这个包将代码推送到gitlab
而后选择ADD
最后点击GENERATE,下载一个java-demo的包
错误修改
如果构建失败,mvn使用aliyun的直接构建即可
<mirrors>
....
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
而后,我们创建一个新分支来存放
cd /tmp
git clone git@172.16.100.47:java/java-demo.git
cd java-demo
git checkout -b web
mkdir linuxea
而后将java-demo.zip解压复制进去
unzip java-demo.zip
cp java-demo/* /tmp/java-demo/linuxea/
上传到git仓库
git add .
git commit -m "first commit"
git push -u origin web
另外还需要将Dockerfile放入
4.1 配置凭据
你可以使用密钥或者账号密码来进行配置,如果是账号密码需要配置一个Credentials后来进行引用。因此,需要安装Credentials插件
install plugins "Credentials
"
在Manage Jenkins
-> Manage Credentials
-> 选择全局
,而后添加凭据
而后复制创建完成的id,将会在拉取代码时候用到,如下
//阶段1 获取代码
stage("CheckOut"){
steps {
script {
println("下载代码 --> 分支: ${env.branch}")
checkout( [$class: 'GitSCM',
branches: [[name: "${branch}"]],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'gitlab-mark',
url: "${BASEURL}"]]])
}
}
}
总的如下
try {
if ( "${onerun}" == "gitlabs"){
println("Trigger Branch: ${info_ref}")
RefName="${info_ref.split("/")[-1]}"
//自定义显示名称
currentBuild.displayName = "#${info_event_name}-${RefName}-${info_checkout_sha}"
//自定义描述
currentBuild.description = "Trigger by user ${info_user_username} 自动触发 \n branch: ${RefName} \n commit message: ${info_commits_0_message}"
BUILD_TRIGGER_BY="${info_user_username}"
BASEURL="${info_project_git_http_url}"
}
}catch(e){
BUILD_TRIGGER_BY="${currentBuild.getBuildCauses()[0].userId}"
currentBuild.description = "Trigger by user ${BUILD_TRIGGER_BY} 非自动触发 \n branch: ${branch} \ngit: ${BASEURL}"
}
pipeline{
//指定运行此流水线的节点
agent any
//管道运行选项
options {
skipDefaultCheckout true
skipStagesAfterUnstable()
buildDiscarder(logRotator(numToKeepStr: '2'))
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps {
script {
println("下载代码 --> 分支: ${env.branch}")
checkout( [$class: 'GitSCM',
branches: [[name: "${branch}"]],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'gitlab-root',
url: "${BASEURL}"]]])
}
}
}
}
}
但是这里面涉及到两个变量,分别是:
$branch: 分支
这里我们修改为: web
$BASEURL: git地址
这个就是这个项目地地址
这两个参数化构建过程中需要在选项参数中进行添加
4.2 配置mvn源地址
如果没有配置mvn的,参考如下
.m2下的settings.xml文件不好用了,或者反正就不好用了,我们直接配置绝对路径
找到mirrors字段,字段内全部删除,复制下面的粘贴进去即可
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
像这样,而后存放在一个位置
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<pluginGroups>
</pluginGroups>
<proxies>
</proxies>
<servers>
<server>
<id>maven-releases</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>admin</password>
</server>
</servers>
<mirrors>
<!-- <mirror>
<id>nexus</id>
<mirrorOf>local</mirrorOf>
<name>nexus</name>
<url>http://172.16.15.136:8081/repository/maven-public/</url>
</mirror>-->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://172.16.15.136:8081/repository/maven2-group/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<profiles>
</profiles>
</settings>
4.3 juit测试
pom文件增加依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
我们的目录结构中,首先是一个Linuxea的目录,于是我们每次都需要cd进去
stage("unit Test"){
steps{
script{
sh """
cd linuxea && mvn test -s /var/jenkins_home/.m2/settings.xml
"""
}
}
post {
success {
script {
junit 'linuxea/target/surefire-reports/*.xml'
}
}
}
}
正常情况下会在surefire-reports下创建一个xml文件,jenkins读取此文件
[root@linuxea-48 /data/jenkins-latest/jenkins_home/workspace/linuxea-2022/linuxea/target]# ll
total 0
drwxr-xr-x 3 root root 47 Jul 3 18:31 classes
drwxr-xr-x 3 root root 25 Jul 3 01:30 generated-sources
drwxr-xr-x 3 root root 30 Jul 3 01:45 generated-test-sources
drwxr-xr-x 3 root root 35 Jul 3 01:40 maven-status
drwxr-xr-x 2 root root 257 Jul 3 18:32 surefire-reports
drwxr-xr-x 3 root root 17 Jul 3 18:31 test-classes
如果代码里没有单元测试,这里是没有报告产生的,并且有可能因为版本问题会报错
现在我们将web合并到master,开始构建。最终如下
4.4 sonarqube
简单使用,安装插件即可,SonarQube Scanner,或者下载SonarQube Scanner安装挂载到容器内
1.首先我们配置token信息和Jenkins互联
复制token
01c2f60766bd896fe82a378bb105e1a73d9161c3
2.回到jenkins添加凭据
- 插件配置
如果此时用的插件就可以这么配置,在Manage Jenkins->Configure System
流水线阶段如下
stage('SonarQube analysis') {
// sonarqube installation name
steps{
withSonarQubeEnv( installationName: 'sonarqube-servers') {
sh """
cd demo && mvn clean verify sonar:sonar -s /var/jenkins_home/.m2/settings.xml
"""
}
}
}
- 不使用插件(现在就是)
不用插件就需要下载sonar-scanner-cli包使用,如下
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip
unzi sonar-scanner-cli-4.6.2.2472-linux.zip -d /usr/local/
ln -s /usr/local/sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner /usr/local/sbin/
sed -i 's/use_embedded_jre=true/use_embedded_jre=false/g' /usr/local/sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner
这个包最终是被挂载到容器的/usr/local/package/下
如果不用插件,用命令组合变量,因此需要生成一下命令的格式
在流水线语法中-选中"withCredentials; Build credentials to variables",而后绑定到"sonarqube-token"变量中
将生成的流水线脚本复制,并进行修改
stage("coed sonar"){
steps{
script {
withCredentials([string(credentialsId: 'sonarqube-token', variable: 'SONAR_TOKEN')]) {
sh """
cd linuxea && \
/usr/local/package/sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner \
-Dsonar.host.url=http://172.16.100.47:9000 \
-Dsonar.projectKey=${JOB_NAME}_${branch} \
-Dsonar.projectName=${JOB_NAME}_${branch} \
-Dsonar.projectVersion=${BUILD_NUMBER} \
-Dsonar.login=${SONAR_TOKEN} \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=${env.BASEURL} \
-Dsonar.links.ci=${BUILD_URL} \
-Dsonar.sources=src \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports
"""
}
}
}
}
此阶段运行后如下
现在在sonarqube生成的就是master分支的
4.5 代码覆盖率
在8.9.2的版本里面jacoco默认是有的,因此我们不需要额外插件
但是仍然需要配置pom.xml中的dependency,如下
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<scope>test</scope>
</dependency>
还有一个plugins
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<destFile>target/jacoco.exec</destFile>
<detaFile>target/jacoco.exec</detaFile>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
修改完成的pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.linuxea</groupId>
<artifactId>java-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<destFile>target/jacoco.exec</destFile>
<detaFile>target/jacoco.exec</detaFile>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
而后在构建的命令中添加如下
-Dsonar.core.codeCoveragePlugin=jacoco \
-Dsonar.jacoco.reportPaths=target/jacoco.exec
添加到流水线
stage("coed sonar"){
steps{
script {
withCredentials([string(credentialsId: 'sonarqube-token', variable: 'SONAR_TOKEN')]) {
sh """
cd linuxea && \
/usr/local/package/sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner \
-Dsonar.host.url=http://172.16.100.47:9000 \
-Dsonar.projectKey=${JOB_NAME}_${branch} \
-Dsonar.projectName=${JOB_NAME}_${branch} \
-Dsonar.projectVersion=${BUILD_NUMBER} \
-Dsonar.login=${SONAR_TOKEN} \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=${env.BASEURL} \
-Dsonar.links.ci=${BUILD_URL} \
-Dsonar.sources=src \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports \
-Dsonar.core.codeCoveragePlugin=jacoco \
-Dsonar.jacoco.reportPaths=target/jacoco.exec
"""
}
}
}
}
构建后sonarqube的覆盖率将会出现值
- 如果没有配置测试用例,这里是0
评论