多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

SonarQube 7.9实战:从Docker部署到升级迁移避坑指南

SonarQube 7.9实战:从Docker部署到升级迁移避坑指南 简介SonarQube 7.9 是一款面向开发团队与运维人员的开源代码质量管理工具安装包用于检测漏洞、代码异味和编码规范偏差帮助团队在开发早期定位并修复问题。该压缩包整体大小约 196.67MB同时采用 SonarQube 服务器标准目录结构包含完整的启动脚本bin、核心配置conf/sonar.properties、数据与索引目录data、插件扩展目录extensions、Web 界面资源web、依赖库lib、内置 Elasticsearch 搜索引擎以及日志目录logs可直接用于部署或升级已有实例。目前已获得 472 人学习/下载适合需要搭建代码质量平台的中高级开发者、测试或运维人员参考。通过解压部署并配置数据库连接与 sonar.properties读者可以掌握 SonarQube 7.9 的安装、启动、插件扩展和日志排查流程同时内置 Elasticsearch 的目录设计也有助于理解海量质量数据的存储与检索机制为后续持续代码审查提供落地基础。1. 还在用 SonarQube 7.9 的人到底在纠结什么SonarQube 7.9 是 2019 年发布的 LTS长期支持版本到今天依然能在不少老团队的生产环境里见到。它承载着大量 Java 8/11 时代项目的质量门禁很多团队不是不想升级而是被两个现实问题卡住MySQL 数据库暂时迁不走自定义插件和大量历史规则集换了版本就不兼容。这里从一线部署角度讲清楚 7.9 能做什么、怎么跑起来、扫描接入要注意什么以及最让人头痛的升级路径问题。适合正在维护老平台、或接手了别人留下的 SonarQube 实例的开发者帮你少走弯路。2. 7.9 能做什么活七个质量维度与质量门禁部署之前先把能力边界说清楚。7.9 能做的核心事就两件分析代码并把结果量化成指标然后按质量门禁给出通过或不通过的结论。其余的功能比如项目管理、权限、插件都是围绕这两件事服务的。2.1 七个质量维度不是摆设从看板到项目视图SonarQube 7.9 的项目首页是一个仪表盘核心指标分成七类可靠性Bug、安全性漏洞、可维护性坏味道、覆盖率、重复代码、复杂度以及代码规模。这些指标不是装饰而是官方分析器按语言规则直接算出来的。每一类背后都有具体的规则文档点进去能看到触发规则的代码片段和修改建议。可靠性指标里统计的是会导致程序崩溃或结果错误的缺陷比如空指针、资源不关闭安全性统计的是可能被外部利用的漏洞比如 SQL 注入、硬编码凭据可维护性指的是不违反正确性、但会让后续维护成本变高的写法比如超长方法、重复块。三者都按 Blocker、Critical、Major、Minor、Info 五档分严重程度质量门禁里可以按等级分别设阈值。项目视图支持按标签、语言、负责人筛选。团队常见的做法是给每个微服务建一个项目再用标签区分后端和前端。某研发小组的做法是三个服务各建一个项目打上 service-a、service-b 的标签质量门禁统一用一套但不同语言的项目单独设覆盖率下限。7.9 的权限模型还是老式角色授权全局权限和项目权限分开配Anyone 的默认权限在生产环境建议关掉不然任何人都能看代码摘要。把指标用好还有个细节7.9 的仪表盘可以自定义但操作入口藏得比较深。常用做法是让项目首页保持默认只在质量门禁页看门禁通过率数据统计交给 API 拉出去做报表。如果团队每天要晨会看质量趋势写成脚本调 /api/measures/search 拉历史数据比看界面更可靠。2.2 质量门禁把规则转成合并请求的硬门槛质量门禁是 7.9 最值钱的功能。它把“代码行数、通过率”这种模糊标准换成一组硬性条件每次扫描结束时给一个 PASSED 或 FAILED 的结论。默认的 Sonar way 门禁卡的是新代码的 Bug 数、漏洞数、坏味道数没有把覆盖率塞进去需要团队自己加条件。这里的关键概念叫泄漏周期Leak Period用来界定什么是“新代码”。7.9 默认口径是 Since previous version也就是从上一次版本分析之后算起也可以设成固定天数比如最近 30 天。很多团队配了门禁却一直不生效基本都是泄漏周期口径没搞对这个坑在第 5 章还会专门展开。配置路径是 Quality Gates 菜单新建或复制一个门禁然后逐条添加条件。常见做法是把新代码的 Bug 和漏洞都设为 0覆盖率下限先设 50%坏味道按工程能力逐步收紧。质量门禁条件我一般建议按下面的初始值起步条件项建议初始值备注新代码 Bug 数0有 Blocker 必须处理新代码漏洞数0安全相关不商量新代码覆盖率下限50%接入早期别设 80%新代码坏味道数0 或不限制依赖规则集先看分布再定门禁定得太严会让扫描全红太松又形同虚设。标准做法是先按默认门禁跑两周打开 Measures 页看各类指标的真实分布再把阈值调到比当前中位数略严一点。门禁和 CI 联动时扫描结果写回服务端CI 根据 API 返回的质量门禁状态决定构建继续还是中断这一步在 7.9 里效果稳定是把质量问题挡在合并前的关键。2.3 7.9 与新版的核心差距知道边界才能做决定同为 LTS7.9 和后面的 8.9、9.9 相比差距主要在三处。第一是语言分析器版本旧内置分析器对新语法支持不全Java 17 的 class 文件解析不了这个在 5.2 会看到具体报错。第二是分支分析能力弱7.9 免费版里 Long-Lived Branch 支持很有限PR 分析基本不可用很多团队只能靠多项目或 CI 里手动切换分支来模拟。第三是插件生态停在 2019 年近两年社区新出的插件大多要求更高版本能装的插件列表在肉眼变少。这三条差距并不代表 7.9 不能用。它对你的价值取决于团队现状如果代码栈主要是 Java 8/11、前端是 ES5/ES6质量门禁卡的是基础规范和覆盖率那 7.9 完全够用如果已经在用 Java 17 或者开始大规模写 TypeScript那就要认真考虑升级路线第 6 章会讲迁移前必须做的准备。3. 本地跑通 7.9Docker 最小部署命令与 JVM 配置进入实操。7.9 的部署方式基本就三种官方安装包、容器镜像、已有云平台。我在本地和测试环境都用容器镜像最省事也最容易复现生产环境用安装包的人也不少配置逻辑其实一样差异只在进程管理和数据目录。3.1 用 Docker 起一个 7.9 的最小命令第一步先确认 Docker 可用内存建议至少 4G。7.9 自带 Elasticsearch对内存和系统参数都很敏感内存不够会启动失败或运行一段时间后进程被系统杀掉。# 拉取 7.9 的社区版镜像具体 tag 以 Docker Hub 实际列表为准 docker pull sonarqube:7.9-community # 启动容器把 9000 端口暴露出来并传入 PostgreSQL 连接信息 docker run -d --name sonarqube \ -p 9000:9000 \ -e SONARQUBE_JDBC_USERNAMEsonar \ -e SONARQUBE_JDBC_PASSWORDsonar \ -e SONARQUBE_JDBC_URLjdbc:postgresql://localhost/sonar \ sonarqube:7.9-community先说明第一个参数SONARQUBE_JDBC_USERNAME 和 PASSWORD 是 SonarQube 访问数据库的账号密码不是 Web 登录账号。SONARQUBE_JDBC_URL 指向数据库实例等号后面要按实际地址改。如果本地没有 PostgreSQL这三行环境变量可以全部删掉7.9 会退回内置的 H2 数据库能跑通界面但数据不持久只适合第一次体验。启动后等待一两分钟访问 http://localhost:9000。默认账号是 admin/admin第一次登录会强制改密码。容器日志里看到 SonarQube is up 才算真正就绪如果一直停在 waiting for Elasticsearch十有八九是 3.3 节的内核参数问题先看日志再折腾镜像。提示容器方式下 docker rm 会连同数据一起删掉长期使用务必把数据目录挂载到宿主机。docker run -d --name sonarqube \ -p 9000:9000 \ -v /opt/sonarqube/data:/opt/sonarqube/data \ -e SONARQUBE_JDBC_URLjdbc:postgresql://localhost/sonar \ sonarqube:7.9-community挂载参数 -v 的左边是宿主机目录右边是容器内数据目录路径保持 /opt/sonarqube/data 不会错。生产环境还建议把 logs 和 conf 一并挂出来不然升级或排错时非常被动这是很多团队吃了亏之后补上的习惯。3.2 数据库选型与 sonar.properties 必调参数7.9 官方支持的数据库有 PostgreSQL、Oracle、SQL Server 和 MySQL。MySQL 的支持在这个版本之后逐步弱化社区讨论也基本转向 PostgreSQL。我一般选 PostgreSQL理由很直接免费、资源少、迁移路径干净新版 SonarQube 也只推荐它。数据库要提前建好字符集用 UTF-8并建一个专用账号。建库语句CREATE USER sonar WITH PASSWORD sonar; CREATE DATABASE sonar OWNER sonar;这里用专用账号而不是 root理由是隔离权限。SonarQube 会建一堆业务表如果账号权限过大出问题时排查范围会很广。容器方式已经用环境变量传了连接信息安装包方式则要改 conf/sonar.properties 里的三行sonar.jdbc.usernamesonar sonar.jdbc.passwordsonar sonar.jdbc.urljdbc:postgresql://localhost:5432/sonar这三行分别是数据库账号、密码和连接串连接串里 localhost 要换成数据库实际地址。特别提醒7.9 对数据库版本有兼容范围别用一个太新的 PG 版本因为 JDBC 驱动和 SQL 语法都可能对不上启动阶段最容易暴露。JVM 参数与 Elasticsearch 堆设置是 7.9 的高发问题区。7.9 内嵌了 Elasticsearch它和主进程各自持有 JVM 堆内存预算必须先过一遍# 主进程堆官方建议 1G 起步但别超过物理内存一半 sonar.web.javaOpts-Xmx1024m -Xms512m # Elasticsearch 堆512m 到 1g 足够不要贪大 sonar.search.javaOpts-Xmx512m -Xms512m这两个是 7.9 里最容易忽略的参数。不设置时它会用默认值容器内存受限时经常出现主进程或 ES 进程被系统杀掉的现象。看到 Killed 或容器退出码 137优先检查这里的堆设置而不是去看业务日志。3.3 启动排错内嵌 ES 的 vm.max_map_count 坑部署完最常见的启动失败日志里出现max virtual memory areas vm.max_map_count [65530] is too low。这是 Elasticsearch 的经典问题内核参数限制了进程能创建的虚拟内存映射区数量ES 起不来SonarQube 也就一直卡在启动早期。解决方案# 临时修改当前内核参数 sudo sysctl -w vm.max_map_count262144 # 永久生效写入 /etc/sysctl.conf echo vm.max_map_count262144 | sudo tee -a /etc/sysctl.confsysctl -w 只对当前内核生效重启后失效所以必须写进 /etc/sysctl.conf。这个配置在容器里也要注意如果 SonarQube 跑在容器内而内核参数属于宿主机要在宿主机上改改完重启容器即可。另一个常见现象是容器起来了但 9000 端口一直拒绝连接。正确排查顺序是先看启动日志确认有没有 SonarQube is up 或异常栈。70% 的情况是数据库连接串写错、账号密码不对、或者 ES 堆大小超过容器内存限制。还有一类是系统时钟漂移ES 对时钟非常敏感虚拟机宿主机不同步会让索引写入失败这个原因藏得深遇到莫名其妙的 ES 报错先跑一下 date 对比时间。内嵌的 Elasticsearch 像个黑匣子平时不用管出问题只能看日志。7.9 的日志目录下 search 相关日志会有更具体的信息排错时别只看 Web 日志把 ES 日志一起看很多玄学问题其实是线索没找全。4. 接入扫描器让 Java 和前端代码真正被检查服务起来了项目也建好了下一步是把代码接进来扫描。7.9 支持的接入方式不少最常见的是命令行扫描器和 CI 流水线里调用API 触发也有但绝大多数团队用的是前两种。4.1 SonarScanner 命令行扫描的最小流程先下载 SonarScanner CLI 并解压到本地把 bin 目录加进 PATH。然后在项目根目录放一个 sonar-project.propertiessonar.projectKeymy-service sonar.projectNamemy-service sonar.projectVersion1.0.0 sonar.sourcessrc sonar.java.binariestarget/classesprojectKey 是项目的唯一标识创建后不建议改projectName 只用于展示projectVersion 要每次构建变化这个直接影响“新代码”口径后面会专门说。sources 指向源码根目录java.binaries 指向编译产物目录这两个路径都是相对于项目根目录的。执行扫描sonar-scanner \ -Dsonar.host.urlhttp://localhost:9000 \ -Dsonar.logintoken \ -Dsonar.languagejavasonar.login 传的是用户在 SonarQube 界面上生成的令牌比账号密码安全。令牌的生成位置在 7.9 的用户头像菜单里选 My Account - Security填个名字生成一串。如果用 CI把令牌通过管道环境变量传入别写死在命令行里。Java 项目最容易翻车的就是sonar.java.binaries。之前 A 同学第一次接入时漏了这行扫描照样跑完但覆盖率显示 0、很多类型推断相关的规则全部失效。原因很简单Java 分析器需要读字节码做类型解析和数据流分析没有编译产物等于盲扫。接入前先确认 target/classes 存在或者改成 Maven 的 target 目录。扫描完成后刷新项目页就能看到结果。如果显示 No data 或 Missing blame information基本就是源码目录或二进制目录没找对。加-X参数重跑一次看日志打印的 source dirs 和 binaries 实际值比瞎猜快得多。4.2 分析配置与语言参数让扫描贴近真实不同语言要传的参数不一样一个比较完整的 sonar-project.properties 模板# Java 项目必配 sonar.sourcessrc/main/java sonar.java.binariestarget/classes sonar.sourceEncodingUTF-8 # 排除生成代码避免噪音 sonar.exclusions**/generated/**,**/build/** # 前端项目排除依赖目录和构建目录 sonar.exclusions**/node_modules/**,**/dist/** # 覆盖率报告路径JaCoCo 生成后 sonar.jacoco.reportPathtarget/jacoco.exec sonar.coverage.jacoco.xmlReportPathstarget/site/jacoco/jacoco.xmlsonar.sourceEncoding强烈建议显式设置 UTF-8不然后续中文注释和字符串规则的结果会乱。sonar.exclusions是坑点集中地Java 项目要排除 generated 和 build前端项目必须排除 node_modules 和 dist否则扫描时间暴涨第三方库的坏味道全堆到你的项目头上门禁永远红着。前端项目在 7.9 时代用的是 sonar.javascript 插件它依赖 Node.js 运行时扫描机上必须装 node。TypeScript 项目更要注意插件版本与 TS 版本兼容遇到过分析器抛内部异常导致整个扫描失败的情况最后是把 TS 版本降到插件支持的范围内解决。前端项目建议在 CI 机器上装一个固定的 Node 版本别让版本漂移引入偶发失败。覆盖率导入也在这里配置。JaCoCo 的 exec 或 xml 生成后把上面的两个路径配好扫描器会自动读取。如果没有生成覆盖率报告就配路径扫描会报文件不存在更坑的是路径配错了不报错覆盖率显示 0%看 Web 界面根本发现不了。每次扫描后应该先看一眼 Coverage 列再去看规则报告。CI 接入时还有两个习惯值得养成。一是把 sonar-scanner 的版本固定在项目里别随意更新因为扫描器版本和分析器版本有匹配关系乱升会导致误报。二是扫描参数尽量集中在 sonar-project.properties 里管理命令行的 -D 参数只留 host 和 login这样换人接手时能看到完整的项目配置。5. 30 天实战避坑7.9 最常见的五个问题与排查路径7.9 跑了 30 天真正影响日常工作的坑就那么几个这里按排查顺序整理成一个清单。每条都按现象、原因、解决来讲遇到问题可以直接跳着看。5.1 现象一扫描报告一直显示 No data现象项目页里所有指标都是空的或者只有项目名没有结果。原因最常见的是 sonar.sources 路径配错、项目 key 撞车或者 SonarScanner 与分析器版本不匹配。第三种情况多发生在手动升级了扫描器、但服务端还是 7.9 的团队里。解决先加 -X 参数重跑一次扫描日志里会打印实际解析的源码目录。确认 sources 路径相对项目根目录正确projectKey 全局唯一然后看扫描器版本是否在 7.9 支持范围内。路径错误时修改 properties 文件比在命令行传参更直观。5.2 现象二JDK 17 项目扫描直接报 Unsupported class version现象扫描日志里出现Unsupported class file major version 61随后分析失败。原因7.9 内置的 Java 分析器只能解析到某个字节码版本JDK 17 编译出来的 class 的 major version 是 61超过了解析上限。这是硬边界调参数解决不了。解决三个方向选一个。最优先的是让 CI 里的编译和分析任务都跑在 JDK 11 环境下用 7.9 扫低版本编译产物其次是项目本身降级到 JDK 11最后是平台升级。这里值得强调升级平台并不是简单换版本要按第 6 章的思路走别在没准备的情况下直接动生产。5.3 现象三MySQL 字符集导致中文乱码现象界面上中文路径、中文错误信息变成问号扫描报告里的注释乱码。原因7.9 以 UTF-8 写入数据库但 MySQL 库表或连接串没指定 utf8mb4中文被截断或变成乱码。解决建库时显式指定字符集连接串加 characterEncodingutf8库表改成 utf8mb4。已经乱码的数据别在界面上一个个改直接把该项目的分析数据清掉重新扫描数据比修库更快。这个问题在用 PostgreSQL 时基本不会遇到也算当初选库的一个隐性收益。5.4 现象四增量更新泄漏周期不生效现象新代码的门禁条件永远不触发或者昨天修完的坏味道今天还在。原因泄漏周期默认口径是 Since previous version如果每次扫描的 sonar.projectVersion 都一样上一版本和当前版本的分析数据就重叠了增量判断自然失效。解决CI 每次构建都传不同的版本号比如-Dsonar.projectVersion1.0.0-${BUILD_NUMBER}或者基于 Git 提交号生成。这样每个构建都形成一个新的泄漏周期新代码统计才可靠。这是 7.9 使用中最常被忽略的配置但直接影响质量门禁是否可信。5.5 现象五插件装错版本导致平台起不来现象上传或升级某个插件后SonarQube 启动失败日志里有插件相关异常Web 界面打不开。原因插件与 7.9 的 API 版本不兼容。7.9 时代插件生态对版本非常敏感装高于目标版本的插件可能直接让平台起不来。解决先删掉出问题的插件 jar重启平台让它回到能起来的状态。操作前备份 extensions 目录这是后悔药。之后安装插件务必对照兼容性矩阵锁定版本能不动就不动。7.9 使用中最后一条经验插件版本锁死升级时连同插件清单一起评估别只升平台不升插件。6. 从 7.9 升级迁移前必做的三件准备7.9 的边界都摸清了最后回答那个常见问题要不要升级、怎么升。SonarQube 官方只支持当前 LTS 升级到下一个 LTS7.9 的下一站是 8.9不能直接跳到 10.x。升级前确认三件事数据库是否已迁到 PostgreSQL、插件是否在新版有替代、扫描器版本是否跟着升。这三件不齐升级到一半大概率失败。项目7.9 时代升级到 8.9 之后数据库MySQL / PG官方推荐 PostgreSQL插件需精确匹配 7.9需匹配目标版本扫描器旧版 CLI必须同步升级权限模型老角色新版权限体系需重配先做一次完整演练。把 7.9 的数据 dump 下来在临时环境装 8.9导入数据升级插件跑一轮扫描对比指标。确认历史数据迁移后不丢失、门禁判定口径一致再动生产。如果升级过程中改了数据库 schema 又中途失败回滚会很麻烦所以演练里要验证“失败后能回到 7.9”这条退路。规则集和自定义规则在升级前导出。新版默认规则有变化门禁条件要跟着调历史分析数据能迁但某些旧指标在新版里可能显示缺失属正常现象。数据库迁移这件事别拖到最后一天MySQL 到 PostgreSQL 的转换工具有专门的坑字段类型和索引差异都会影响结果。注意升级前先备份 7.9 的数据目录和数据库 dump至少保留到新环境稳定运行两周以上再清理。如果 7.9 跑得稳、团队没有新语言需求它完全可以继续服役如果开始上 Java 17 或要接入更多语言升级是迟早的事。把数据库和 CI 扫描参数提前准备好真到升级那几天你要关注的只是指标对比和门禁差异而不是临场学迁移。这个方向我踩过希望帮到你。本文还有配套的精品资源点击获取
返回列表