文章目录
前言
CI/CD流水线完善计划, 增加代码质量检查作业,在开发代码合入前提前发现不安全问题,因此引入代码质量检测-SonarQube服务。
一、SonarQube是什么?
Sonar是一个用于代码质量管理的开源平台,用于管理Java源代码的质量。通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具,比如pmd-cpd、checkstyle、findbugs、Jenkins。通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。同时 Sonar 还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用 Sonar。 此外,Sonar 的插件还可以对 Java 以外的其他编程语言提供支持,对国际化以及报告文档化也有良好的支持。
二、SonarQube安装步骤
当前最新发布 SonarQube 社区版9.7,以下步骤以此为例。
1.docker安装
快速安装,仅限于测试或则体验:
docker run -d --name sonarqube --restart always -p 9000:9000 sonarqube
2.docker-compose安装
可用于持久化,私有化部署使用。
docker-compose.yml 配置:
version:"3"services:sonarqube:image: sonarqube:9.7-community
container_name: sonarqube
depends_on:- db
environment:SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
volumes:- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
ports:-"9000:9000"db:image: postgres:12container_name: postgres
environment:POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
volumes:- postgresql:/var/lib/postgresql
- postgresql_data:/var/lib/postgresql/data
volumes:sonarqube_data:sonarqube_extensions:sonarqube_logs:postgresql:postgresql_data:
如果是非volume安装,注意给本地文件权限
chmod 777 -R xxxx
修改系统资源:
sysctl-wvm.max_map_count=524288sysctl-w fs.file-max=131072ulimit-n131072ulimit-u8192
在docker-compose.yml 文件更目录执行:
docker compose up -d
3. 访问SonarQube
URL: http://localhost:9000
用户名: admin
密码: admin
4. 配置SonarQube
4.1 安装中文插件
- 在线安装:> 插件在GitHub,因为网络原因可能会安装失败,多试几次。
Caused by: org.sonar.api.utils.SonarException: Fail to download: https://github.com/xuhuisheng/sonar-l10n-zh/releases/download/sonar-l10n-zh-plugin-9.7/sonar-l10n-zh-plugin-9.7.jar (no proxy) at org.sonar.core.util.DefaultHttpDownloader.failToDownload(DefaultHttpDownloader.java:157) at org.sonar.core.util.DefaultHttpDownloader.download(DefaultHttpDownloader.java:152) at org.sonar.server.plugins.PluginDownloader.downloadRelease(PluginDownloader.java:145) at org.sonar.server.plugins.PluginDownloader.download(PluginDownloader.java:118)... 131 common frames omittedCaused by: java.net.SocketTimeoutException: connect timed out at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:412) at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:255) at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:237) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.base/java.net.Socket.connect(Socket.java:609) at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:305) at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:177) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569) at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266) at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:373) at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:203) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187) at java.base/sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1071) at java.base/sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1069) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.AccessController.doPrivilegedWithCombiner(AccessController.java:795) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1068) at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:189) at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:168) at org.sonar.core.util.DefaultHttpDownloader$BaseHttpDownloader$HttpInputSupplier.getInput(DefaultHttpDownloader.java:274) at org.sonar.core.util.DefaultHttpDownloader.download(DefaultHttpDownloader.java:149)... 133 common frames omitted
安装完成重启也可以通过docker 重启容器docker restart sonarqube
其他插件也可在应用市场安装。 - 离线安装 下载好的插件直接扔到 sonarqube安装目录下的 extensions/plugins 重启sonarqube即可。如果是先查找对应sonarqube_extensions 卷路径,插件路径默认在 /var/lib/docker/volumes/sonarqube_sonarqube_extensions/_data/plugins
4.2 导入规则集
目前国内ali-p3c-pmd规则集比较流行,适用于没有自己规则的中小企业。
- 下载ali-p3c-pmd插件 源码 https://github.com/caowenliang/sonar-pmd-p3c
- 打包部署插件
mvn clean install-Dmaven.test.skip=true
将{仓库目录}\sonar-pmd-plugin\target\ 下生成的sonar-pmd-plugin-3.2.1.jar copy到 sonarqube的{安装目录}/extensions/plugins下.。如果是docker数据卷安装可以直接扔到对应数据卷目录下。/var/lib/docker/volumes/sonarqube_sonarqube_extensions/_data/plugins
重启sonarqube容器docker restart sonarqube
- 重启完成可以在插件市场看到已安装的规则集插件
- 进入代码规则页面,过滤器输入p3c,在仓库下可以看到PMD规则一共56条,为ali-p3c-pmd全部规则
4.3 配置规则集
创建质量配置
输入名称和代码语言
为新创建的配置添加规则
进入到规则页面,左侧过滤器显示当前选择的规则集,有系统自带e.g.:xxxx(内置)的规则集,和我们导入的外部规则集(ali-p3c-pmd)。
这里选择我们导入的规则集PMD(过滤器输入p3c >>选择仓库下的PMD(56条))
弹出框激活—选择我们的质量配置all-check----应用
ali-p3c-pmd一共56条规则,排除了PMD默认规则(因为没有中文描述)
4.3 安装多分支检查插件
- 下载插件https://github.com/mc1arke/sonarqube-community-branch-plugin/releases
- 离线 安装到插件目录 extensions/plugins/
- 修改config 进入docker容器内部
dockerexec-it sonarqube bash
修改sonar.propertiesvi conf/sonar.properties
在文件末尾加入两行:sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=websonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=ce
${version}:你所下载的jar包的版本,本文因SonarQube版本为9.7所以是填入1.12.0保存文件,重启sonarqueb。> 9.7社区版安装1.12.0有问题:> 10:40:30.202 [main] INFO com.github.mc1arke.sonarqube.plugin.CommunityBranchAgent - Loading agent> Exception in thread “main” java.lang.reflect.InvocationTargetException> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)> at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)> at java.base/java.lang.reflect.Method.invoke(Method.java:566)> at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:513)> at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:525)> Caused by: java.lang.ClassNotFoundException: org.sonar.server.almsettings.MultipleAlmFeatureProvider> at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)> at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)> at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)> at java.base/java.lang.Class.forName0(Native Method)> at java.base/java.lang.Class.forName(Class.java:315)> at com.github.mc1arke.sonarqube.plugin.CommunityBranchAgent.redefineEdition(CommunityBranchAgent.java:93)> at com.github.mc1arke.sonarqube.plugin.CommunityBranchAgent.premain(CommunityBranchAgent.java:56)> … 6 more> *** java.lang.instrument ASSERTION FAILED ***: “result” with message agent load/premain call failed at src/java.instrument/share/native/libinstrument/JPLISAgent.c line: 422> FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed> 安装9.6社区版,或者等待插件升级> - 登录sonarqube,忽略风险提示修改maven 构建命令,添加:
-Dsonar.branch.name=${CI_COMMIT_BRANCH}
选择对应分支扫描后就能看到
三、SonarQube使用步骤
1. 创建项目
- 创建项目输入项目名称选择本地构建创建令牌,默认即可 测试项目为java maven项目,选择maven复制maven执行命令
2. 启动本地扫描
- 进入IDEA maven构建菜单,copy命令回车执行(注意删除输入栏的mvn)
- 等待执行完成,登录sonarqube项目页面查看结果。 点击问题个数进入详情> p3c规则都属于异味,sonar 扫描代码后,在类型 “异味” 可以找到,分“阻断”、“严重”、“主要” 3个严重等级
- 注意事项
org/sonar/batch/bootstrapper/EnvironmentInformation has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
> 当前项目为JDK1.8,sonarqube 9.7 在jdk11上运行,所以本地编译会报错; > 解决方法:> 修改本地JDK环境为jdk11 > 安装低版本sonarqube7.8(最后一个支持jdk1.8的版本)—不推荐> 我们目标是流水线构建,本地构建可以采用idea插件,这里暂不介绍。
四、GitLab流水线集成Sonarqube扫描
1. sonarqube创建关联gitlab仓库的项目
- 在sonarqube配置-ALM集成-gitlab 创建配置> 配置名称:gitlab> GitLab网址: http://localhost/api/v4> 个人访问令牌: 在gitlab中设置> Gitlab个人访问令牌创建:> 复制令牌> 配置成功
- 新建项目=>更多=>来自gitlab 输入需要访问项目的仓库管理员用户令牌,需要read_api权限 保存后可以看到该用户名下的gitlab仓库 点击设置,配置对应仓库的代码检查项目
2. 配置gitlab流水线作业
2.1 选择设置好的项目,使用Gitlab CI来分析项目
2.2 配置gitlab-runner
- docker创建gitlab-runner的步骤
docker run -d--name gitlab-runner --restart always \-v /var/run/docker.sock:/var/run/docker.sock \-v gitlab-runner-config:/etc/gitlab-runner \ gitlab/gitlab-runner:latest
- gitlab注册runner 点击注册一个实例runner=>显示runner安装与注册说明复制 注册runner的命令 进入刚才启动好的runner 容器
dockerexec-it gitlab-runner bash
执行命令,一路回车确定gitlab-runner register --url http://localhost/ --registration-token D8pXEqBH6nRrRsNCRSk_
- 配置gitlab-runner config.toml> [[runners]]> name = “”> url = “http://localhost/”> token = “D8pXEqBH6nRrRsNCRSk_”> executor = “docker”> [runners.custom_build_dir]> [runners.cache]> [runners.cache.s3]> [runners.cache.gcs]> [runners.cache.azure]注意修改 executor = “docker”
2.3 maven镜像私有化配置
- gitlab添加变量引入自定义settings.xml> 键:MVN_SETTINGS_XML> 值:settings.xml文件内容复制进来> 类型:文件> # MVN_SETTINGS_XML变量在GitLab的设置=>CI/CD=>变量中定义,值就是整个settings.xml的内容(文本),变量类型设置成了"文件"
- maven构建脚本引入变量> -s ${MVN_SETTINGS_XML}
script:- mvn -s ${MVN_SETTINGS_XML}
- docker镜像配置本地仓库缓存 配置gitlab-ci缓存
script:- mvn -s ${MVN_SETTINGS_XML}-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository cache:key:"${CI_JOB_NAME}"paths:- .m2/repository
2.4 启动流水线
完整gitalab-ci.yml配置
sonarqube-check:stage: build
image: maven:3.6.3-jdk-11tags:- docker-runner
variables:SONAR_USER_HOME:"${CI_PROJECT_DIR}/.sonar"# Defines the location of the analysis task cacheGIT_DEPTH:"0"# Tells git to fetch all the branches of the project, required by the analysis taskscript:- mvn -s ${MVN_SETTINGS_XML}-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository verify sonar:sonar -Dsonar.projectKey=test
cache:key:"${CI_JOB_NAME}"paths:- .sonar/cache
- .m2/repository
allow_failure:trueonly:- master # or the name of your main branch
运行流水线完毕到sonarqube查看检测报告
注意事项
当前配置仅支持master分支检测,需要切分支,需要装插件
stage 和 tags值按照自己项目配置定义
目前缓存还不是很完美,每次需要从gitlab应用所在环境copy缓存到执行机,存在一些延迟。
如果放到runner执行机本地更好,但不灵活。
效率分析:
TODO 总用时59s
Analysis total time: 9.997
Total time: 29.079 s
pull images 59-29~= 20s
docker镜像下载还有必要优化
2.5 流水线门禁设置
我们期望当代码质量不满足sonarqube设置的门禁时,流水线运行阻塞,不进行后续作业。
- 创建sonarqube质量阀
- 如果没有创建,sonarque有默认值,如果需要自定义门禁值,创建规则后按需添加条件
- gitlab流水线如果需要sonarqube检查成功后才可执行下阶段作业,需要修改gitlab-ci.yml
allow_failure:false
- 当流水线未通过代码检查时点击sonarqueb-check job查看详情 点击链接跳转sonarqube查看代码质量详情
五、代码质量
异味
ali-p3c-pmd问题都归属异味
点击数量进入
严重程度细分为: 阻断=>严重=>主要=>次要=>提示
其中阻断、严重需要解决
覆盖率
单元测试覆盖率,行覆盖率
pom.xml引入jacoco插件,注意版本不行就换
<build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.8</version><executions><execution><goals><goal>prepare-agent</goal><goal>report</goal></goals></execution></executions></plugin></plugins></build>
重复率
新增代码质量
本次推送或者MR的新增部分代码质量
全部代码质量
仓库全部代码当前质量
质量阀
质量阀俗称门禁值,根据项目要求设置各类指标,如不了解,用默认值。
超过门禁值,检测失败
总结
本文介绍了sonarqube的docker安装及使用,结合gitlab-ci完成自动化代码质量检测。
版权归原作者 懒死洛特 所有, 如有侵权,请联系我们删除。