个人亲自录制全套DevOps系列实战教程 :
手把手教你玩转DevOps全栈技术
质量安全审计:Sonarqube
Sonarqube(声呐)大家应该不陌生,通过扫描代码分析代码质量与代码安全,方便我们快速定位代码缺陷、潜在风险。
个人建议: 作为项目质量智能分析工具,他是个双刃剑,在公司规模足够大并且足够重视代码质量时,sonar会有一个不错的位置;当如果公司规模小型,并且公司不足以把重点放在代码质量上,那么sonar可能会成为拖后腿的工具,一句话就是是否有必要上sonar完全看公司的需求以及成本。
作用阶段: 我们讨论下sonar应该在什么阶段起作用
- 代码开发阶段实时检测【sonarlint插件,为sonar 8.5版本后提供,需要集成到开发工具如Idea,配置时需要sonarqube服务支持,分析结果会提示在控制台,类似前端eslint作用】
- 代码提交前进行sonar扫描【需集成到本地开发工具,如Idea或Eclipse】
- 提交代码时进行sonar扫描【需集成到gitlab,如sonar-gitlab-plugin,也可结合Gitlab CI进行提交流程控制】
构建代码时进行sonar扫描【需集成到jenkins,如SonarQube Scanner插件】
- 由sonar定期自主扫描代码生成报告【可以用jenkins的定时job】
具体应该部署哪种方案,也需要大家根据自身情况适当选择,没有完美的方案,选择最适合自己的方案即可。
此处我们集成到jenkins做演示。其他方式大家有兴趣可以找我咨询。
Docker容器部署
官网:https://docs.sonarqube.org/latest/setup/install-server/
根据官方文档可知,sonar是支持docker部署的,并且非常简单,sonar默认使用H2数据库,我们也可以指定自己的mysql等数据库。
选用版本:8.9 该版本为LTS长期支持版本,从7.9版本开始sonar必须有jdk11支持并且不再支持Mysql数据库。sonar默认采用H2数据库。
官方推荐配置:SonarQube扫描器需要版本8或11的JVM,SonarQube服务器需要版本11和最少2G内存,具体大家可以官网看。
Sonar的社区版免费
Sonar包括3个组件: Scanner负责扫描代码并分析生成报告->报告交给Sonar服务进行计算->最终结果存入数据库。下边我们通过docker-compose方式启动sonar容器。
注意:
sonar不能以root身份运行在基于Unix系统上,我们这里使用的是基于Debian内核,所以没问题。
# vi /docker/sonarqube/docker-compose.yml
# 此处我们使用默认的H2数据库,如果外接数据库,可参考官网docker-compose.yml文件
version: "3"
services:
sonarqube:
# 使用一下私服拉取
image: 10.10.1.199:9083/sonarqube:8.9-community
restart: always
container_name: 'sonarqube'
hostname: 'sonarqube'
networks:
- 'exist-net-bloom'
volumes:
# 配置文件
- '/docker/sonarqube/conf:/opt/sonarqube/conf'
# 保存H2数据和ES索引文件
- '/docker/sonarqube/data:/opt/sonarqube/data'
# 保存第三方插件
- '/docker/sonarqube/extensions:/opt/sonarqube/extensions'
# 日志
- '/docker/sonarqube/logs:/opt/sonarqube/logs'
ports:
- "9097:9000"
networks:
exist-net-bloom:
external:
name: devops
# 如果需要自行修改配置,比如使用其他数据库等,可以在conf目录增加sonar.properties配置文件,具体可到官方获取
# 官方下载地址:https://www.sonarqube.org/downloads/
访问:10.10.1.199:9097,注意以上docker-compose.yml并未指定上下文,默认为/,可以自行指定。
输入:admin,admin即可
不过下边有一个黄色警告,他的意思是嵌入式数据库应该只用于测试不能用于生产,那样不利于扩展,并且不支持升级到最新版本的sonarqube,我们这里用的默认H2所以会有提示,如果大家想尝试连接自己的数据,当然不能是Mysql,如果要用mysql可以使用7.9以下的版本,如果要使用单独数据库,通过docker-compose.yml指定几个环境变量就行了:
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
中文插件安装:
结果安装失败了,点击按钮后,页面无反应
报错原因是到github上下载插件失败,超时了:docker logs -f sonarqube 可看到报错日志,那理所当然我们认为是网络问题,手动下载,地址如下:https://github.com/xuhuisheng/sonar-l10n-zh/releases/download/sonar-l10n-zh-plugin-8.9/sonar-l10n-zh-plugin-8.9.jar
诡异的事情:
出于好奇,想到当前用的H2,会不会跟这个有关呢?于是我尝试了使用postgresql[结果出乎意料
]
version: "3"
services:
sonarqube:
# 使用一下私服拉取
image: 10.10.1.199:9083/sonarqube:8.9-community
restart: always
container_name: 'sonarqube'
hostname: 'sonarqube'
networks:
- 'exist-net-bloom'
volumes:
# 配置文件
- '/docker/sonarqube/conf:/opt/sonarqube/conf'
# 保存H2数据和ES索引文件
- '/docker/sonarqube/data:/opt/sonarqube/data'
# 保存第三方插件
- '/docker/sonarqube/extensions:/opt/sonarqube/extensions'
# 日志
- '/docker/sonarqube/logs:/opt/sonarqube/logs'
depends_on:
- postgressql
environment:
# 避免ip变更,使用hostname连接
SONAR_JDBC_URL: jdbc:postgresql://postgressql:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
ports:
- "9097:9000"
postgressql:
image: 10.10.1.199:9083/postgres:12
restart: always
container_name: 'postgressql'
hostname: 'postgressql'
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
volumes:
- '/docker/sonarqube/postgresql:/var/lib/postgresql'
- '/docker/sonarqube/postgresql/data:/var/lib/postgresql/data'
networks:
- 'exist-net-bloom'
networks:
exist-net-bloom:
external:
name: devops
# 删除原有容器
docker-compose down
# 重新启动容器
docker-compose up -d
启动sonar报错:
ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] ERROR: Elasticsearch did not exit normally - check the logs at >/opt/sonarqube/logs/sonarqube.log
解决方法: 在宿主机的/etc/sysctl.conf中增加该配置即可,注意因为容器也是复用宿主的系统配置,所以直接改宿主机即可。
vi /etc/sysctl.conf # 新增如下配置
vm.max_map_count=262144
# 更新启动容器
docker-compose up -d
出乎意料,安装成功了!!!
这。。。,就不是github网络问题吧?
推测:
其实还有一个问题,就是下载插件后无法保存到插件目录,即无法保存到/opt/sonarqube/extensions/plugins,因为被映射到宿主机了,如果无权写数据也可能会超时,所以修改宿主机目录权限:chmod -R 777 /docker/sonarqube/extensions
那为什么H2数据库就不行,PostgreSQL就可以呢?
我查了下文档,并没有找到答案,可能这就是亲儿子效应吧,H2都不推荐你用你非要用,出问题了吧 。。。,还是乖乖用PostgreSQL才是王道啊!
Sonar客户端配置
由官网文档得知,客户端需要使用Scanner工具完成扫描和上报(sonar早期版本还单独提供有sonarqube runner工具,和scanner类似),并且Scanner有多重实现方式
官方地址:https://docs.sonarqube.org/8.9/analysis/overview/
我们这里演示两种方式:
Maven和Jenkins
- Springboot工程本地集成Scanner插件
- Jenkins集成Scanner插件
Maven配置
既然是maven当然可以配置到全局settings.xml,也可以配置到springboot项目的pom.xml中。
注意:
我们的sonar是需要登录的,所以事先我们先把token生成一下,直接使用用户名密码也可以,用token可以防止密码泄露
配置到settings.xml
<settings>
<pluginGroups>
<pluginGroup>org.sonarsource.scanner.maven</pluginGroup>
</pluginGroups>
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
# 指定token,如果使用用户名密码,需要增加<sonar.password>属性
<sonar.login>0226e22e60902a670f8c706e12e5ceee86c51f9e</sonar.login>
<sonar.host.url>http://10.10.1.199:9097</sonar.host.url>
</properties>
</profile>
</profiles>
</settings>
配置到Springboot项目的pom.xml
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.7.0.1746</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.login>0226e22e60902a670f8c706e12e5ceee86c51f9e</sonar.login>
<sonar.host.url>http://10.10.1.199:9097</sonar.host.url>
</properties>
</profile>
</profiles>
测试: 在工程根目录执行 mvn sonar:sonar
错误:
你的工程包含java文件,请使用sonar.java.binaries属性指定class文件目录或使用sonar.exclusions属性排除java文件。
# 修正后执行命令,也可以在pom.xml中增加该属性
mvn sonar:sonar -Dsonar.java.binaries=target/
# 关于属性大家可以到官网查看:https://docs.sonarqube.org/8.9/analysis/analysis-parameters/
覆盖率:
这里延伸一下sonar覆盖率的概念,他会在scanner之前将汇总报告生成到target目录,然后由scanner一起上报给sonar服务。
覆盖率的概念是单元测试的覆盖面囊括了我们源代码的比例,更多的在测试中使用。
我们看图中覆盖率是0,其实覆盖率要生效需要使用另一个插件,对于java代码的统计汇总需要的是jacoco,其他语言大家也可参考官网:https://docs.sonarqube.org/8.9/analysis/coverage/
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
<configuration>
<!--指定生成.exec文件的存放位置-->
<destFile>target/coverage-reports/jacoco-unit.exec</destFile>
<!--Jacoco是根据.exec文件生成最终的报告,所以需指定.exec的存放路径-->
<dataFile>target/coverage-reports/jacoco-unit.exec</dataFile>
<!-- 如果以上都不指定,默认jacoco-unit.exec会存入target/目录,report也会从target目录读取-->
<!-- 并且report会将报告存入target/site/jacoco/index.html -->
</configuration>
<executions>
<execution>
<id>jacoco-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<!-- 指定生成报告的maven目标 -->
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
# 执行先生成覆盖率报告,在scanner扫描
mvn clean verify sonar:sonar
Jenkins改造
在这里我们主要演示让sonar集成到jenkins,这样jenkins不论是单独的定时任务job还是目前我们demo项目的job,都可以进行按需的分析代码。
我们还是以demo为例,目标:maven构建打包的同时进行sonar分析完成扫描代码并上报。
思考:
jenkins需要修改吗?要怎么修改?有几种方案?不修改行吗?
- 不修改: 当然行,因为demo工程的pom.xml已经配置了Sonar Scanner,可以通过mvn命令直接使用
缺点:
没有配置Scanner的其他job无法实现通过Scanner扫描上报 - 修改方案1: 给jenkins中的maven配置文件settings.xml做全局配置
缺点:
由于settings.xml配置能力有限,有些特殊配置无法实现 - 修改方案2: 与Maven集成Jenkins类似,将Sonarqube-Scanner的安装包装入容器,然后全局工具中配置,再安装对应的jenkins插件,这样在job中就可以单独去使用Scanner功能了,而不必依赖于job个体。
第一个方案很简单:
只需要将job的Maven构建脚本改成:-DskipTests=true clean package verify sonar:sonar
打包后进行Scanner扫描上报Sonar。
根据jenkins日志片段可知,Scanner已经生效了,并且将代码扫描后上传到了Sonar服务器,此时我们打开Sonar控制台也可以看到上报的demo工程。
我们可以修改下工程中代码并且提交gitlab,在用jenkins重新构建,可以发现sonar的新上报。
第三种方案:
Jenkins中彻底集成Scanner 【
第二种也比较简单,大家自行验证下,我试了是没问题的
】
①首先下载Scanner安装包:
以下哪个地址能下用哪个,我下载的是:sonar-scanner-cli-4.7.0.2747-linux.zip
官方地址:https://docs.sonarqube.org/8.9/analysis/scan/sonarscanner/
二进制地址:https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
注意需要使用:
unzip解压,如果要构建到Dockerfile,则需先通过yum install -y unzip,我这里直接贴出来Dockerfile文件
这里我们就不把他构建到Dockerfile了,而是直接解压到jenkins根目录,根目录已经映射出来,所以操作也很方便
包括jdk、git、maven如果大家觉得没必要打入镜像,都可以这样操作。
②将安装包解压到/docker/jenkins/home目录# apt install unzip 我用的omv是基于Debian yum install -y unzip # 解压 unzip sonar-scanner-cli-4.7.0.2747-linux.zip # 改下文件夹名字 mv sonar-scanner-4.7.0.2747-linux sonar-scanner
③Jenkins中安装sonar插件:【SonarQube Scanner For Jenkins】
配置sonar路径:
系统管理 -> 系统配置 -> SonarQube servers
④全局配置工具:设置sonar-scanner环境目录
⑤修改job配置:在maven构建之后增加sonar scanner,即放在推送镜像到私服环节之前
添加后我们什么都不配运行看下效果:
依次尝试后,我们把必要参数全部配置好:
再看sonarqube控制台,已经发布上来了。