前言

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:12
    container_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 -w vm.max_map_count=524288
sysctl -w fs.file-max=131072
ulimit -n 131072
ulimit -u 8192

在docker-compose.yml 文件更目录执行:

docker compose up -d

3. 访问SonarQube

URL: http://localhost:9000
用户名: admin
密码: admin

在这里插入图片描述

4. 配置SonarQube

4.1 安装中文插件

  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 omitted
    Caused 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
    

    其他插件也可在应用市场安装。

  2. 离线安装
    下载好的插件直接扔到 sonarqube安装目录下的 extensions/plugins
    重启sonarqube即可。

    如果是先查找对应sonarqube_extensions 卷路径,插件路径默认在
    /var/lib/docker/volumes/sonarqube_sonarqube_extensions/_data/plugins

4.2 导入规则集

目前国内ali-p3c-pmd规则集比较流行,适用于没有自己规则的中小企业。

  1. 下载ali-p3c-pmd插件 源码
    https://github.com/caowenliang/sonar-pmd-p3c

  2. 打包部署插件

    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
    
  3. 重启完成可以在插件市场看到已安装的规则集插件
    在这里插入图片描述

  4. 进入代码规则页面,过滤器输入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 安装多分支检查插件

  1. 下载插件

    https://github.com/mc1arke/sonarqube-community-branch-plugin/releases

  2. 离线 安装到插件目录 extensions/plugins/

  3. 修改config
    进入docker容器内部

    docker exec -it sonarqube bash
    

    修改sonar.properties

    vi conf/sonar.properties
    

    在文件末尾加入两行:

    sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=web
    
    sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=ce
    

    ${version}:你所下载的jar包的版本,本文因SonarQube版本为9.7所以是填入1.12.0
    插件作者已更新:
    ${version}:你所下载的jar包的版本,本文因SonarQube版本为9.7所以是填入1.13.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社区版,或者等待插件升级
    在这里插入图片描述

  4. 登录sonarqube,忽略风险提示
    在这里插入图片描述

    修改maven 构建命令,添加:

    -Dsonar.branch.name=${CI_COMMIT_BRANCH}
    

    选择对应分支扫描后就能看到
    在这里插入图片描述

三、SonarQube使用步骤

1. 创建项目

  1. 创建项目

    创建项目

    输入项目名称
    在这里插入图片描述

    选择本地构建
    在这里插入图片描述

    创建令牌,默认即可
    在这里插入图片描述

    在这里插入图片描述
    测试项目为java maven项目,选择maven
    在这里插入图片描述

    复制maven执行命令
    在这里插入图片描述

2. 启动本地扫描

  1. 进入IDEA maven构建菜单,copy命令回车执行(注意删除输入栏的mvn)
    在这里插入图片描述

  2. 等待执行完成,登录sonarqube项目页面查看结果。
    在这里插入图片描述
    点击问题个数进入详情

    p3c规则都属于异味,sonar 扫描代码后,在类型 “异味” 可以找到,分“阻断”、“严重”、“主要” 3个严重等级

    在这里插入图片描述

  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仓库的项目

  1. 在sonarqube配置-ALM集成-gitlab 创建配置
    在这里插入图片描述

    配置名称:gitlab
    GitLab网址: http://localhost/api/v4
    个人访问令牌: 在gitlab中设置

    在这里插入图片描述

    Gitlab个人访问令牌创建:

    在这里插入图片描述

    复制令牌

    在这里插入图片描述

    配置成功

    在这里插入图片描述

  2. 新建项目=>更多=>来自gitlab
    在这里插入图片描述
    输入需要访问项目的仓库管理员用户令牌,需要read_api权限
    在这里插入图片描述
    保存后可以看到该用户名下的gitlab仓库
    在这里插入图片描述
    点击设置,配置对应仓库的代码检查项目

2. 配置gitlab流水线作业

2.1 选择设置好的项目,使用Gitlab CI来分析项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2 配置gitlab-runner

  1. 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
    
  2. gitlab注册runner
    在这里插入图片描述
    点击注册一个实例runner=>显示runner安装与注册说明
    在这里插入图片描述

    复制 注册runner的命令
    进入刚才启动好的runner 容器

    docker exec -it gitlab-runner bash
    

    执行命令,一路回车确定

    gitlab-runner register --url http://localhost/ --registration-token D8pXEqBH6nRrRsNCRSk_
    
  3. 配置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镜像私有化配置

  1. gitlab添加变量引入自定义settings.xml

    键:MVN_SETTINGS_XML
    值:settings.xml文件内容复制进来
    类型:文件
    # MVN_SETTINGS_XML变量在GitLab的设置=>CI/CD=>变量中定义,值就是整个settings.xml的内容(文本),变量类型设置成了"文件"

    在这里插入图片描述

  2. maven构建脚本引入变量

    -s ${MVN_SETTINGS_XML}

      script: 
        - mvn -s ${MVN_SETTINGS_XML}
    
  3. 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-11
  tags:
    - docker-runner  
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  script: 
    - 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: true
  only:
    - 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设置的门禁时,流水线运行阻塞,不进行后续作业。

  1. 创建sonarqube质量阀
    在这里插入图片描述

  2. 如果没有创建,sonarque有默认值,如果需要自定义门禁值,创建规则后按需添加条件
    在这里插入图片描述

  3. gitlab流水线如果需要sonarqube检查成功后才可执行下阶段作业,需要修改gitlab-ci.yml

    allow_failure: false    
    

    在这里插入图片描述

  4. 当流水线未通过代码检查时
    在这里插入图片描述

    点击sonarqueb-check job查看详情
    在这里插入图片描述
    点击链接跳转sonarqube查看代码质量详情
    在这里插入图片描述

2.6 Gitlab查看SonarQube报告

  1. SonarQube配置
    盗的图在这里插入图片描述
  2. 即可从GITLAB MR跳转

五、代码质量

在这里插入图片描述

异味

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完成自动化代码质量检测。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐