1 项目背景原因
1.1 升级价值
1.2 升级挑战
1.3 升级策略
1.4 准备内容与检查清单
2 升级方案与技术实现
2.1 版本升级要点
3 升级过程中的问题与解决方案
3.1 多JDK服务问题
3.2 用户登录问题
3.3 新版sonar引入的新概念–参考分支(Reference Branch)
3.4 Ali-P3C插件兼容性问题阻碍
4 升级效果展示
4.1 成功支持扫描公司内部的JDK8-JDK21的JAVA服务的扫描
4.2 增量代码问题展示
5 项目总结与展望
5.1 结果总览
5.2 经验总结
5.3 展望未来
1 项目背景原因
随着 Java 生态的演进,JDK 21 已成为公司企业级应用开发的主流。然而,转转内部工作流的静态代码扫描平台 SonarQube V7 及其依赖的 Ali-P3C 规范,均已无法支持对高版本 JDK 的代码进行扫描,这直接制约了对 JDK 21 服务的质量监控。
为此,SonarQube平台升级势在必行。在选型时,我充分考虑到第三方插件的兼容性是升级成功的关键。最终,选定 V10.7 版本,因为它提供了选型当时最全面的插件生态支持。
考虑到从 V7 到 V10 版本跨度巨大,直接升级将面临插件兼容性复杂、历史数据迁移风险高等挑战。因此,我制定了 “V7→V8→V9→V10” 的渐进式升级策略。通过对每个中间版本进行充分的测试与验证,逐步升级,确保实现一次零数据丢失的平滑升级。
1.1 升级价值
升级后SonarQube 可覆盖JDK8 – JDK 24的版本的Java代码扫描。
新版的SonarQube提升了扫描性能和准确性。
新版的SonarQube更新了最新的代码质量规则和安全漏洞检测能力
确保内部的JDK8—-JDK21的服务,都能接入静态扫描,避免问题累积到生产环境
1.2 升级挑战
版本跨度大:从V7到V10跨越3个大版本,需要逐步迁移
数据迁移复杂:历史项目数据、质量门禁配置、用户权限等需要完整保留
兼容性风险:插件版本、API接口、集成流程可能存在不兼容
业务连续性:升级期间不能中断日常代码扫描任务
1.3 升级策略
升级路线图
升级路线图
按照官方推荐[1], 使用渐进式升级路径:V7 → V8 → V9 → V10
升级路线图
升级路线图
每个版本应该在测试环境单独验证,阅读官方文档熟悉升级流程,确保数据完整性和功能可用性
正式升级时,建立回滚机制,出现问题可快速恢复
每个版本都测试插件版本、API接口的兼容接口
周末升级,避免影响业务工作日的代码扫描任务。
1.4 准备内容与检查清单
升级前准备内容
升级前准备流程
升级前准备流程
数据库备份与环境准备
插件兼容性检查,提前下载准备好第三方插件
2 升级方案与技术实现
2.1 版本升级要点
2.1.1 V7.9.6 LTS → V10.7 LTS 升级方案
SonarQube服务器的JDK限制要求
当我们逐步升级到V10的时候,此时运行Sonarqube服务器要求的最低JDK版本已经是JDK17+,而使用的SonarScanner也需要匹配Sonarqube服务器相应的JDK版本,否则会出现兼容性问题。
JDK要求
SonarQube
SonarScanner
Sonar V8
JDK11 or Higher
JDK11 or Higher
Sonar V9
JDK17 or Higher
JDK17 or Higher
Sonar V10
JDK17 or Higher
JDK17 or Higher
但是为了Sonar官方为了减少Scanner对于运行时环境的依赖,从SonarQube V8版本开始,官方推荐使用自动JRE适配的SonarScanner[2],这样可以避免由于JDK版本不匹配导致的扫描失败问题。因此在升级到SonarQube V8及以上版本时,建议使用自带JRE的SonarScanner版本。
下面以SonarQube V10为例,展示自动JRE适配的各类SonarScanner版本:
表现
表现
升级前,务必仔细阅读官方升级指导文档,并做好数据备份,确保万无一失。
各版本升级前必做事项
1. 备份数据库或者联系DBA同学为你操作
pg_dump -U sonar sonarqube > sonarqube_v7_backup_$(date +%Y%m%d).sql
2. 备份旧版的SONAR配置文件
cp -r /opt/sonarqube/conf /opt/sonarqube/conf_backup
3. 备份数据目录
tar -czf sonarqube_data_backup.tar.gz /opt/sonarqube/data
各版本通用的升级步骤:
1. 停止旧版本服务
systemctl stop sonarqube 或者 /your_path/sonarqube/bin/linux-x86-64/sonar.sh stop
2. 解压新版本
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-your_new_version.zip
unzip sonarqube-your_new_version.zip -d /your_path/
3. 迁移配置文件
cp /your_path/sonarqube-your_old_version/conf/sonar.properties /your_path/sonarqube-your_new_version/
4. 调整配置
vm.max_map_count大于或等于 524288
fs.file-max大于或等于 131072
5. 启动新版本
/your_path/your_new_version/bin/linux-x86-64/sonar.sh start
6. 访问 http://yourSonarQubeServerURL/setup 执行数据库升级,需要耐心等待
V7升级V8关键要点:
数据库升级: 参考官方文档,PostgreSQL需从9+版本,建议直接升级到PostgreSQL 11
插件兼容性: 部分V7插件不再兼容V8,需要安装新版三方插件或寻找替代方案
Java版本: 确保运行环境使用JDK 11
数据库迁移: 首次启动会自动执行schema升级,约耗时30-60分钟(视已有的数据量而定)
V8升级V9关键要点:
Java版本升级: 启动Sonar服务器环境要求强制JDK 17或更高版本,这是硬性要求
质量门禁重构: Quality Gates规则体系重大调整,部分规则被删除。
API接口变更: 部分API接口被废弃,引入新API,需验证集成流程
V9升级V10关键要点:
Java版本升级: 启动Sonar服务器环境要求强制JDK 17或更高版本,这是硬性要求
API接口变更: 部分API接口被废弃,引入新API,需验证集成流程
用户认证变更: 内置对GitLab OAuth的支持,需重新配置用户登录方式
验证要点:
确认正常启动sonar服务
访问Web界面,确认版本号为你升级的版本号
检查项目列表,确认所有项目数据完整
测试扫描功能: 选择一个小项目执行完整扫描
检查旧项目的数据是否完整
API接口测试: 由于大版本升级,大量API已变更,需验证新接口是否正常工作
删除不兼容插件,寻找兼容版本的替代插件
使用符合SonarQube版本的Sonar Scanner
V10版本检查是否支持JDK21语法
2.1.2 正式环境升级方案
正式环境升级采用与测试环境相同的步骤,也必须逐步的升级每个版本,为了应对可能的升级失败风险,因此我设计了以下的步骤:
隔离服务: 在正式环境中,原有的SonarV7及其数据库主节点不改动,保证正式环境有一个Sonar V7可以持续提供服务,不受任何影响。
备份和升级: 断开并独立原有的数据库从节点,提升为主节点,保证有完整的备份历史数据,然后进行渐进的版本升级。
失败回滚: 如果升级过程中出现任何问题,都不会影响之前的V7服务,因为升级完全是独立Sonar环境和数据库。
成功切换: 如果升级成功,则将原有的V7服务下线,切换到新的V10服务,并将新的数据库提升为主节点,继续提供服务。
验证功能: 升级完成后,进行全面的功能验证,确保所有项目数据完整,扫描功能正常,用户登录无误。
数据补偿: 升级过程中,可能会有部分服务在V7服务上进行了扫描。需要在升级成功后,针对这些代码在V10服务上补偿扫描,确保数据一致性。
3 升级过程中的问题与解决方案
3.1 多JDK服务问题
问题描述:
由于不同版本的SonarQube对JDK版本有严格要求,在同一台服务器上运行多个版本时,可能会出现JDK冲突问题。例如使用JDK17/21 扫描JDK8服务 由于JDK升级后删除了一些内部库 导致扫描失败
问题表现:
在扫描JDK8服务时,可能会出现类找不到、方法未定义等问题,导致扫描失败。
问题表现
问题表现
解决方案:分离多版本JDK编译和扫描
Sonar V10 扫描
构建
扫描
JDK8服务
JDK8
JDK17
JDK17服务
JDK17
JDK17
JDK21服务
JDK21
JDK21
由于升级到V10版本后,SonarQube要求JDK17或更高版本
但我们仍需扫描JDK8项目,因此需要区分构建和扫描,
JDK8项目使用JDK8环境构建,JDK17环境扫描
if [ “$JDK_VERSION” = “JDK1.8” ]; then
# JDK8项目:默认环境下构建,使用JDK17扫描但引用JDK8的tools.jar
echo”— JDK8项目:使用JDK8环境构建,JDK17扫描 (引用JDK8 tools.jar) —“
# 使用当前环境(JDK8)构建
BUILD_CMD=”mvn package -Dmaven.test.skip=true -Dmaven.compiler.source=1.8 -Dmaven.compiler.target=1.8″
# 设置扫描时使用的JDK
SONAR_JAVA_HOME=”/opt/soft/jdk/jdk17″
# 设置JDK8的tools.jar路径,供扫描时使用
TOOLS_JAR=”$JDK8_HOME/lib/tools.jar”
# 扫描时传递tools.jar路径
SONAR_ADDITIONAL_PARAMS=”-Djdk.tools.jar=$TOOLS_JAR”
elif [ “$JDK_VERSION” = “JDK17” ]; then
# JDK17项目:保持不变
echo”— JDK17项目:使用JDK17环境构建和扫描 —“
BUILD_CMD=”JAVA_HOME=/opt/soft/jdk/jdk17 mvn package -Dmaven.test.skip=true”
SONAR_JAVA_HOME=”/opt/soft/jdk/jdk17″
SONAR_ADDITIONAL_PARAMS=””
export MAVEN_OPTS=”根据你的需求设置相应的参数”
export JAVA_OPTS=”根据你的需求设置相应的参数”
elif [ “$JDK_VERSION” = “JDK21” ]; then
# JDK21项目:保持不变
echo”— JDK21项目:使用JDK21环境构建和扫描 —“
BUILD_CMD=”JAVA_HOME=/opt/soft/jdk/jdk21 mvn package -Dmaven.test.skip=true”
SONAR_JAVA_HOME=”/opt/soft/jdk/jdk21″
SONAR_ADDITIONAL_PARAMS=””
export MAVEN_OPTS=”根据你的需求设置相应的参数”
export JAVA_OPTS=”根据你的需求设置相应的参数”
else
echo”不支持的JDK版本: $JDK_VERSION”
exit 1
fi
定义SonarQube扫描命令,包含额外的工具参数
SONAR_CMD=”JAVA_HOME=$SONAR_JAVA_HOME mvn $SONAR_PARAMS $SONAR_ADDITIONAL_PARAMS”
执行构建和扫描
iftest -d service
then
cd service
# 先构建
echo”开始项目构建…”
eval”$BUILD_CMD”
# 再扫描
echo"开始SonarQube扫描..."
eval"$SONAR_CMD"
3.2 用户登录问题
问题描述:
原先工作流中的旧版本SonarV7登录,其实是使用的一个GITHUB开源项目开源插件[3],基于这个插件进行了修改,使用了LDAP & OAuth 2进行了用户的验证,通过内部devops平台和GITLAB的配置,完成了用户注册登录到Sonar系统里。
但是升级进入到V10版本后, 此时GITLAB登录能力,已经被Sonar官方内置支持了,不再需要插件的实现。因此需要探究别的登录方案。
问题表现:
V10内置GITLAB支持
V10内置GITLAB支持
根因分析:
V7版本使用的登录插件不兼容V10版本的Sonar。
V10版本的Sonar内置了对GITLAB OAuth的支持,但配置方式不同
解决方案:
借助委托认证机制 验证登录:
标头原理
标头原理
用户登录Sonar系统,是必须的需求,再修改原有的登录插件成本较高,且不兼容新版Sonar。 我通过调研Sonar对于用户验证支持,发现Sonar是支持委托认证机制的。借助转转内部的SSO系统, 在SSO系统完成用户验证后,通过在http请求头内添加用户信息,将用户信息传递给Sonar系统,Sonar系统通过读取http请求头内的用户信息,实现用户的自动登录。
这个方案的核心是实现认证(Authentication)与授权(Authorization)分离:
认证(Who are you?): 由转转SSO 系统负责验证用户身份
授权(What can you do?): 由 SonarQube 内部根据可信身份信息决定权限
实施过程中的问题与解决:
在实际部署时,我发现存量用户无法正常登录。经过排查定位到根本原因:
由于V7 时代使用插件登录,系统里所有的历史存量用户在数据库中都有一个“GITLAB”标识,标记其身份来源。当使用委托认证机制时,会将用户标记为“SONAR”用户, 系统校验身份来源的一致性, 存量用户的“GITLAB”标识导致不一致,进而登录失败。
解决方法:
通过数据库update脚本,将用户标识从 GITLAB 更新为 SONARQUBE:将 GITLAB标记的用户,改成 SONARQUBE 标记,便可以直接无缝衔接登录,无需删除旧用户。
3.3 新版sonar引入的新概念–参考分支(Reference Branch)
问题描述:
旧版本SonarQube V7中没有参考分支的概念,所以无法通过简单的方式来区分历史遗留问题和新增问题,导致用户在查看代码质量时,难以聚焦于新增代码的问题。
参考分支:新版本引入了参考分支(Reference Branch)的概念,允许用户指定一个特定分支作为扫描分支的基准线。扫描分支与参考分支进行对比,以突出显示新增的代码质量问题。
参考分支的概念引入也彻底解决了V7版本中一直存在的问题。 即无法很方便区分历史遗留问题和新增问题,历史采取的解决方案是基于GitDiff的思路, 借助Gitlab平台,明确一个分支新增的diff行内容,从而只关注新增行的质量问题。
但是这种方案除了要维护一套逻辑代码外,还有两个缺点,第一个是需要Sonar全量扫描,然后再过滤在新增行中的Issue问题,第二个问题就是无法关注新增行引发的附近行中的问题。
进入新版本后,参考分支[4] 的引入彻底解决了这两个问题,可以直接指定主分支作为参考分支,进行增量扫描和关注引发的次生问题。 可以轻松的借助新版的API接口获取 开发分支相对于主分支新增的质量问题,无需编写复杂的GitDiff逻辑代码,从而大大简化了增量扫描的实现难度。
V7版本截图
V7版本截图
3.4 Ali-P3C插件兼容性问题阻碍
问题描述:
升级到SonarQube V10后,由于阿里开源的的Ali-P3C插件停留在历史版本不再维护, 历史版本是基于PMD-V6开发的,无法解析JDK21的服务,导致扫描失败。但是转转对于P3C相关的规则使用程度很是较高的,因此需要寻找一种解决方案来实现兼容JDK21的P3C规则的扫描。
解决方案:
解决方案有两个方向:
寻找替代插件: 经过调研,发现GITHUB社区有一个开源插件 sonar-pmd-plugin[5],这个插件本质上还是基于PMD-V6开发的,只是保证了对P3C规则的支持和扫描JDK21时静默处理,不抛出异常。因此可以满足基本的P3C规则扫描需求。
基于PMD-V7二次开发P3C插件: 考虑到PMD-V7对JDK21的支持更好,可以基于PMD-V7进行二次开发,将P3C规则集成进去,实现对JDK21的全面支持。但是这个方案需要投入较多的开发和测试资源,时间成本较高,因此优先选择了第一种方案。
4 升级效果展示
4.1 成功支持扫描公司内部的JDK8-JDK21的JAVA服务的扫描
升级到SonarQube V10.7后,V10本身支持了JDK8到JDK24的Java服务的静态代码扫描。
4.2 增量代码问题展示
问题展示
问题展示
5 项目总结与展望
5.1 结果总览
成功完成SonarQube V7.9.6到V10.7的跨版本升级
数据迁移准确率100%,3961个项目完整保留
支持了公司内部JDK8-JDK21服务的扫描
解决了用户登录、JDK版本兼容等关键问题
降低了JDK21项目之前没有静态扫描所所隐藏的生产环境风险
升级SonarQube,节省了后续接入其他三方插件的成本
5.2 经验总结
充分评估: 提前调研各版本差异和已知问题,制定详细的升级计划、时间表和风险预案,预留足够的测试时间
分步实施: 采用渐进式升级策略(V7→V8→V9→V10),避免一次性跨越多个大版本,每个版本单独验证
数据为王: 升级前后务必做好多层级数据备份(数据库+文件系统),建立快速回滚机制,确保数据安全
充分测试: 在测试环境完整模拟生产场景,验证所有功能,特别是用户登录、项目扫描、质量门禁等核心功能
5.3 展望未来
一、替换掉P3C规则,解决掉长尾升级成本
P3C 长期方案:
近期:继续使用社区兼容插件,确保基本规则覆盖与稳定性;
中期:减少对于P3C规则的使用,转向使用Sonar自带规则,FindBug等已经存在的成熟规则,逐渐摆脱对于P3C的依赖。
远期:彻底废弃P3C规则使用,将业务检查的规则全部迁移到 转向使用Sonar,FindBug的成熟规则,再引入少量符合需求的自研规则。
二、新语言支持(Kotlin / Python /C++等)
预研与选型:对规则成熟度、生态活跃度 选取符合需求的各类编程语言Sonar扫描插件。
低成本的保证服务的质量:借助SonarQube平台和社区开源的各类编程语言Sonar扫描插件,快速接入新语言的静态代码扫描,在保证低成本接入的同时,提升服务的代码质量和安全性。
通过这次SonarQube平滑升级实践,不仅解决了JDK 21的Java服务的兼容性问题,也为不同的编程语言的静态代码扫描能力奠定了基础。未来,我们将继续探索和引入更多编程语言的静态代码扫描支持,提升整体的代码质量和安全水平。
渐进升级Sonarqube的步骤是可以复用的,未来无论是SonarQube继续升级还是其他系统的大版本升级场景,做好数据备份,设计好失败时的回滚计划,充分的准备和测试,都能有效降低升级风险。
做好计划,让升级工作更加从容、可控和高效。
引用链接:
推荐路径: https://docs.sonarsource.com/sonarqube-server/10.7/server-upgrade-and-maintenance/upgrade/upgrade-the-server/determine-path
自动适配JRE: https://docs.sonarsource.com/sonarqube-server/10.7/analyzing-source-code/scanners/scanner-environment/general-requirements
gitlab登录开源插件: https://github.com/SonarSource/sonar-auth-github
参考分支: https://docs.sonarsource.com/sonarqube-server/9.8/project-administration/defining-new-code
P3C开源插件: https://github.com/wuweiit/sonar-pmd-p3c
关于作者
刘希宁,工程效率组,主要负责DevOps平台与工具链优化
想了解更多技术实践,欢迎关注我们的技术公众号!
声明:来自转转QA,仅代表创作者观点。链接:https://eyangzhen.com/3993.html