ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SonarQube 7.9部署与扫描实战:低配环境下的代码质量管理指南

SonarQube 7.9部署与扫描实战:低配环境下的代码质量管理指南

简介:SonarQube 7.9压缩包是一份面向代码质量管理场景的开源工具部署资源,适合需要搭建或升级SonarQube服务、持续检测源码漏洞与坏味道的开发及运维人员。压缩包整体约196.67MB,解压后包含server启动脚本、data数据存储、extensions插件扩展、web前端资源、conf配置目录、内置Elasticsearch核及logs日志等模块,可支撑从安装配置到运行维护的完整流程。目前已累计472人学习下载。通过bin目录的管理脚本可快速启停服务,在sonar.properties中可调整数据库连接、端口与日志级别;将第三方语言插件放入extensions即可扩展分析范围。内置的Elasticsearch能高效检索质量度量数据,配合web界面查看分析结果,有助于团队在开发早期发现潜在缺陷、统一编码规范,持续降低维护成本。

1. 为什么还在用 SonarQube 7.9:低配服务器和老项目的最优解

接手一个两年没人做静态检查的老 Java 项目,我第一件事就是把 SonarQube 拉起来跑一批坏味道数据。试了最新版,4G 内存的服务器直接起不来,规则集和接口也变了不少,折腾两小时没出报告。换回下载目录里的 sonarqube-7.9 镜像,一条 Docker 命令五分钟出结果。SonarQube 7.9 是官方 LTS 版本,规则集完整、运行门槛低、配套插件生态成熟,大量老项目至今还在用它做质量基线。这个资源适合两类人:维护老系统、只想把质量数据跑出来的开发者;第一次接触 SonarQube、不想在环境配置上花太多时间的新手。它解决的问题很纯粹——在低成本环境下把代码坏味道量化出来,规则条条可见,改完能立刻复扫验证。

2. 用 Docker 拉起 7.9:一条 Compose 搞定服务端与数据库

2.1 为什么 7.9 必须配 PostgreSQL:数据库选型的硬约束

SonarQube 7.9 官方支持的数据库是 PostgreSQL、Oracle、SQL Server 和内嵌 H2。生产环境里主流做法是配 PostgreSQL,因为安装最省事、权限模型也清晰。很多人第一次用 7.9 时拿 MySQL 去连,启动日志直接报Unsupported database mysql,这是因为从 7.9 开始官方正式移除了 MySQL 支持。如果你只是临时体验一下,用内置 H2 也能跑,但重启后数据容易丢,不适合长期管理。

数据库选型上我一般推荐 PostgreSQL 10 或 11。7.9 对 PostgreSQL 的支持范围覆盖 9.3 到 11,选 10 的镜像最稳,既有 JSON 支持又不带 12 之后的新特性风险。用 Docker Compose 把服务端和数据库一起拉起,是最省心的方式。

version: '2' services: sonarqube: image: sonarqube:7.9.6-community container_name: sonarqube ports: - "9000:9000" environment: - sonar.jdbc.url=jdbc:postgresql://db:5432/sonar - sonar.jdbc.username=sonar - sonar.jdbc.password=sonar depends_on: - db db: image: postgres:10.4-alpine container_name: sonardb environment: - POSTGRES_USER=sonar - POSTGRES_PASSWORD=sonar - POSTGRES_DB=sonar volumes: - sonardb:/var/lib/postgresql/data volumes: sonardb: driver: local

这段 Compose 里的关键参数是sonar.jdbc.url,它决定了服务端连哪个数据库。jdbc:postgresql://db:5432/sonar里的db是 Compose 内部主机名,对应下面的db服务;后面三个环境变量分别指定了数据库用户名、密码和库名。depends_on保证数据库先启动,但这只是进程级别的等待,极端情况下数据库还没就绪服务端就启动了,稍后会提到怎么处理。

postgres 镜像里的POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB三个变量必须和上面的 JDBC 参数保持一致,不然服务端连不上数据库。卷sonardb用来持久化数据,删容器不影响数据,删卷才会彻底清空。端口映射9000:9000是 SonarQube 默认 Web 端口,如果你本机 9000 被占用,改成19000:9000这类映射即可。

2.2 容器起不来时先查这两个参数:内存映射与日志等待

启动完等待一分钟左右,访问http://localhost:9000如果迟迟打不开,去查容器日志是最直接的手段。7.9 内置了 Elasticsearch,常见报错是max virtual memory areas vm.max_map_count [65530] is too low,这是宿主机的内核参数限制,不是容器配置问题。在宿主机执行:

sudo sysctl -w vm.max_map_count=262144

这个值指定了进程能拥有的内存映射区域数量,Elasticsearch 默认要求不低于 262144。临时修改立刻生效,但重启后失效,建议写进/etc/sysctl.conf持久化。

另一个小坑是日志里反复出现Process [elasticesearch] is stopped,原因常是容器内存不够。7.9 的 Docker 镜像默认把 ES 堆内存设为 1G,如果你的服务器只有 2G 内存,再跑 PostgreSQL 很容易触发 OOM。这时需要给容器限内存,同时调低 ES 堆内存。在 Compose 的 sonarqube 服务里加两行:

environment: - sonar.search.javaAdditionalOpts=-Xms512m -Xmx512m

sonar.search.javaAdditionalOpts直接控制 Elasticsearch JVM 参数,把堆内存从默认降到 512M,换稳定性。不过降到 512M 之后,大型项目的索引性能会受影响,适合几百个文件的仓库。

2.3 不用 Docker 的手动部署:最容易漏的目录与权限

如果你的服务器上不方便装 Docker,手动部署其实也就三步:下载 7.9 发行包、改conf/sonar.properties、启动bin/下的脚本。关键配置集中在conf/sonar.properties文件里:

sonar.jdbc.url=jdbc:postgresql://localhost:5432/sonar sonar.jdbc.username=sonar sonar.jdbc.password=sonar sonar.web.port=9000

注意手动部署时数据库连接串的写法是jdbc:postgresql://localhost:5432/sonar,和 Docker 里的差别就在主机名部分。改动后不要用 root 用户直接跑启动脚本,SonarQube 官方明确要求非 root 运行,否则 Elasticsearch 拒绝启动。创建专用用户并授权数据目录是我推荐的做法:

useradd sonar chown -R sonar:sonar /opt/sonarqube-7.9 su sonar -c "/opt/sonarqube-7.9/bin/linux-x86-64/sonar.sh start"

访问时还需要确认防火墙有没有放行 9000 端口,以及sonar.web.port是否被占用。手动部署比 Docker 多出的几个变量就是这些——运行用户、目录权限、端口冲突,排查时按这个顺序来基本不会卡住。

3. 把扫描器接到项目:从本地 sonar-scanner 到 CI 集成的完整路径

3.1 本地扫描第一个项目:sonar-project.properties 配置拆解

服务端起来之后,需要安装扫描器才能分析代码。我习惯用 sonar-scanner-cli 的 4.x 版本,和 7.9 服务端的兼容性最好,不需要额外加参数。解压后先改conf/sonar-scanner.properties,把服务端地址和认证信息写进去:

sonar.host.url=http://localhost:9000 sonar.login=你的Token

这里的sonar.login在 7.9 里推荐用 Token,而不是账号密码。登录 SonarQube 后,在右上角头像菜单里进入「我的账号 → 安全」,生成一个 Token,复制出来填进去。Token 比密码安全的地方在于可以单独撤销,即使泄露也不影响账号密码。

然后在项目根目录创建sonar-project.properties,这是扫描器的项目级配置:

sonar.projectKey=my-project sonar.projectName=My Project sonar.projectVersion=1.0 sonar.sources=src sonar.java.binaries=target/classes sonar.java.libraries=**/lib/*.jar sonar.sourceEncoding=UTF-8

sonar.projectKey是项目的唯一标识,在同一台 SonarQube 上不能重复;sonar.sources指向源码目录;sonar.java.binaries指向编译后的 class 目录,这个参数在 7.9 里特别容易漏,漏了会报java files can't be analyzed。sonar.java.libraries指定依赖 jar 的路径,如果项目有多级依赖目录,可以用通配符。最后执行:

sonar-scanner

扫描结束会输出BUILD SUCCESS和一个http://localhost:9000/dashboard?id=my-project的链接。打开就能看到行数、坏味道、覆盖率这些基础指标。第一次跑扫描时我一般会盯着日志里的WARN看,很多参数问题不会让扫描失败,但会直接导致某些指标缺失。

3.2 接入 Maven:先编译再扫描,顺序别搞反

Maven 项目接 SonarQube 是最省事的场景,不需要手动建sonar-project.properties,因为pom.xml里已经包含坐标信息。推荐的做法是在pom.xml里配置插件属性,或者直接在命令行传参:

mvn clean verify sonar:sonar \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login=你的Token

这里顺序有讲究:先clean verify生成最新的 class 文件和测试报告,再执行sonar:sonar做分析。如果直接跑mvn sonar:sonar,当源码有编译错误时,分析器拿不到完整的字节码,结果会少一部分规则检查。sonar:sonar这个参数里的 host 地址写的是外部访问地址,如果你在 Docker 容器里跑扫描器,注意不要写localhost,要写宿主机 IP。

多模块项目还有一个常见问题:默认只会分析当前模块。如果有父子模块,需要在父pom.xml里加:

<properties> <sonar.modules>module-a,module-b</sonar.modules> </properties>

sonar.modules是逗号分隔的模块列表,指定后扫描器会依次分析各模块并汇总到同一个项目看板。不加这个参数时,7.9 会把子模块的代码分析结果算到各自独立的 projectKey 下,质量门禁的汇总数据就是错的。

3.3 接入 Jenkins:用 Token 认替代密码,构建步骤只保留两行

Jenkins 接入时我见过不少团队在系统配置里填账号密码,这种做法在 7.9 上也能通,但一遇到密码轮换就要改 Job。用 Token 就干净得多。先在 Jenkins 的凭据管理里添加一个 Secret text,把 SonarQube Token 填进去,然后在构建步骤里执行:

mvn clean verify sonar:sonar \ -Dsonar.host.url=http://sonarqube:9000 \ -Dsonar.login=${SONAR_TOKEN}

${SONAR_TOKEN}是从 Jenkins 凭据注入的环境变量。需要注意的是sonar.host.url这里写了http://sonarqube:9000,这是 Jenkins 和 SonarQube 在同一个 Docker 网络时用的主机名,如果你的 Jenkins 和 SonarQube 不在同一网络,改成实际 IP。还有一点:7.9 的 Webhook 配置在「项目 → 管理 → Webhook」里,Jenkins 的 SonarQube 插件依赖它接收分析完成通知,没配的话流水线会卡在等待阶段直到超时。

4. 质量门禁不是默认值:把阈值调到团队能落地的程度

4.1 先弄懂五个核心指标:Bug、漏洞、坏味道、覆盖率、重复度

SonarQube 7.9 的看板页默认展示的指标是 Bug、漏洞、坏味道、覆盖率、重复度,中文版界面也沿用这套翻译。这五个指标对应不同的质量维度:Bug 反映代码里可能导致运行时错误的问题,比如空指针、数组越界;漏洞集中在安全层面,比如 SQL 注入、硬编码密码;坏味道是代码结构问题,像过长方法、命名不规范;覆盖率衡量的是测试对代码行的覆盖情况;重复度表示相同代码块被复制的比例。

7.9 里还有一个概念叫「新增代码」(New Code),默认以最近 30 天为周期。质量门禁分了两套规则——新增代码一套、整体代码一套。这套设计对老项目特别友好,你可以让整体代码的坏味道存量慢慢还债,但新增代码必须满足门槛,防止问题继续积累。很多团队第一次配门禁时只盯着全局指标,结果老项目永远红灯,反而没人去管新增代码的质量了。

4.2 规则集配置:复制默认规则再裁剪,别直接改官方模板

7.9 默认把规则集和质量门禁都设为「Sonar way」,直接拿去跑老项目,大概率会遇到大量误报。比如某些命名规范规则,在旧代码里普遍存在,但改起来要动几百个类,团队根本不接受。这时候正确的做法不是删规则,而是复制一份默认规则集再调整。

操作路径是:在界面顶部点「质量配置」,找到 Java 对应的 Sonar way 规则集,点「复制」,命名成「My Java Rules」。然后在新的规则集里逐个查看规则,把确实不适合当前团队的规则停用。常见的误报规则包括java:S100(方法名必须符合规范)、java:S115(常量命名规范)这些,具体停哪些要看项目历史和团队约定。复制规则集后,要把项目关联切到新规则集上:「项目 → 管理 → 质量配置」,选择刚建好的规则集。

这里要注意一个 7.9 的行为:修改规则集后,已经分析过的历史数据不会自动重新计算,需要在项目首页点「重新分析」或者等下一次扫描触发。如果规则改动比较大,我一般直接重新跑一次全量扫描,让数据对齐。

4.3 质量门禁参数参考:一套能直接落地的小团队阈值

质量门禁在「质量门禁」菜单里配置,同样可以复制默认模板再改。我整理过一套适合 5-20 人小团队的阈值,直接用「条件」按钮添加即可:

指标整体代码新增代码
Bug00
漏洞00
覆盖率不低于 50%不低于 50%
重复度不高于 5%不高于 3%
坏味道无硬性限制不高于 5

这套配置的核心逻辑是:安全类问题零容忍,新增代码必须控制覆盖率,但坏味道存量不做刚性考核。你可能会问覆盖率 50% 是不是太低了?对于刚接上 SonarQube 的老项目,80% 的默认要求会让团队直接在门外止步。先跑通流程,后续再一个模块一个模块地提升阈值,比一次性卡死更实际。

配置完后点「应用」到项目,在 Pull Request 或合并代码前跑一次扫描,门禁结果是挂在每次分析记录上的。7.9 的门禁失败状态会在扫描结果里明确标红,提醒开发者处理后才允许合入,这就是把质量卡进流程的落地方式。

5. 避坑指南:SonarQube 7.9 最常见的五个翻车点

5.1 现象:启动日志报Unsupported database mysql,进程直接退出

原因:7.9 版本官方移除 MySQL 支持,但很多从旧版本升级上来的团队还沿用 MySQL 配置。解决:切换到 PostgreSQL,或者把sonar.jdbc.url改回 PostgreSQL 连接串并重新初始化数据库。血的教训是:不要试图用连接池中间件把 MySQL 伪装成 PostgreSQL,服务端启动时会校验数据库特性,绕过校验也会在后续索引创建时失败。从旧版本升级前,先把 MySQL 数据用工具迁移到 PostgreSQL,再启动 7.9。

5.2 现象:容器反复重启,日志出现max virtual memory areas vm.max_map_count [65530] is too low

原因:Elasticsearch 需要大量内存映射区域,默认内核限制不够。这个报错在裸机部署和容器部署里都会遇到,和镜像无关。解决:在宿主机执行sudo sysctl -w vm.map_map_count=262144。有些云服务器镜像默认值只有 65530,改了之后容器内 ES 才能正常分配内存。这个参数不会影响其他应用,放心调。

5.3 现象:扫描显示BUILD SUCCESS,但项目看板里一个文件都没有,日志里出现java files can't be analyzed

原因:sonar.java.binaries没有指向编译输出目录。7.9 分析 Java 代码需要读取 class 文件,只给源码路径是不够的。解决:先确认target/classes存在,再在sonar-project.properties里配置sonar.java.binaries=target/classes。如果项目是纯源码没有编译环境,可以在分析前执行mvn compile或javac输出 class 文件。这个参数漏配是新手最常见的坑,没有之一。

5.4 现象:装了汉化包后登录页面能打开,但登录成功就无限刷新/白屏

原因:汉化包版本和 7.9 服务端版本不匹配。中文语言包分版本对应不同的 SonarQube 主版本,拿新版汉化包塞进 7.9 会因为接口不兼容导致前端渲染异常。解决:删除extensions/plugins下的语言包 jar 文件,重启服务端恢复登录;然后到官方插件仓库下载与 7.9 完全匹配的汉化包版本,重新放入插件目录并重启。这个坑我踩过之后形成了一个习惯:安装任何 SonarQube 插件前,先确认插件标注的兼容版本范围,绝不在生产环境直接尝试未知版本的插件。

5.5 现象:Java 项目覆盖率一直显示 0%,测试明明有几十个用例

原因:SonarQube 本身不做覆盖率采集,需要读取 JaCoCo 生成的覆盖率报告文件。默认规则集没配报告路径时,服务端拿不到数据。解决:在sonar-project.properties里加一行:

sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

前提是 Maven 构建时已经配置了 JaCoCo 插件并生成了报告文件。前端项目则用sonar.javascript.lcov.reportPaths=lcov.info指向 lcov 报告。覆盖率一直为 0 时,先确认报告文件真实存在,再检查路径写没写对,最后回头看看BUILD SUCCESS日志里有没有Coverage information was not collected这种提示词。

6. 从 7.9 升级到新版:先备份再验证的三步走

如果你不是非 7.9 不可,而是想要新版的规则集和性能优化,升级前先把迁移路径规划好。SonarQube 官方支持跨 LTS 版本升级,7.9 的下一步官方建议是 8.9 LTS,再往后才考虑 9.x。直接跨两个 LTS 版本升级会出现数据模型不兼容报错。以下三步走我每次升级都会执行。

第一步是备份。停止 SonarQube 服务,备份数据库和配置文件:

pg_dump -U sonar sonar > sonar_backup.sql tar czf sonarqube_conf_backup.tar.gz /opt/sonarqube-7.9/conf /opt/sonarqube-7.9/extensions

第二步是替换发行包。把新版 SonarQube 解压到新目录,拷贝备份的extensions插件目录和conf/sonar.properties,再把数据库指向同一个 PostgreSQL 库,启动后服务端会自动执行数据迁移脚本。

第三步是验证。访问首页确认所有项目还在,点进项目看历史曲线是否保留;再用 sonar-scanner 跑一次全量扫描,对比 Bug、覆盖率等指标是否与旧版一致。迁移过程中如果出现Database migration failed,直接恢复备份重新来,不要试图手工改数据库表结构。

升级 8.9 之后你会发现质量门禁、规则集配置界面有变化,项目数据本身不受影响。我经历过一次跳过 8.9 直接升 9.x 失败后,每次升级前都会先查一遍 LTS 版本的兼容矩阵,再动手。从那以后,升级这种事我再也不依赖直觉,而是老老实实按验证清单走完。希望这份 7.9 的部署、扫描到迁移的踩坑整理能帮到你,我平时用到的配置模板也都打包在下载目录里,直接拿去对照能省不少排查时间。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进