有不少朋友私信问我,为什么在2024年还在折腾 SonarQube 7.4 这种老版本,是不是团队技术栈太落后。其实很多时候不是不想用新版,而是环境不允许:生产机锁定了 JDK 8,数据库早就跑着 MySQL,内网又没法随便起 Docker 容器。我在帮某套内部系统做代码质量验收时,就切切实实被这套组合绑住过。这篇文章把 Windows 环境下安装 SonarQube 7.4 + sonar-scanner-cli 的全过程、配置细节和踩坑经验完整写出来,给同样被困在老旧技术栈里的同学一份可以直接抄作业的参考。
SonarQube 7.4 对 JDK8 和 MySQL 的支持非常成熟,7.9 之后的版本开始转向 JDK11,同时也逐步放弃 MySQL 支持,如果你项目里跑的还是大量 JDK8 时代的老工程,用 7.4 反而是最省心的选择。
1. 为什么还要选 SonarQube 7.4:版本兼容性的现实逻辑
1.1 版本升级带来的三个硬门槛
很多人装新版 SonarQube 会忽略一个关键点:升级不只是换个压缩包解压,而是会连带动好几个依赖。SonarQube 自身的 Web 服务和内置 Elasticsearch 都是 Java 进程,对 JDK 版本有严格要求。从 7.9 开始,官方要求 JDK11,从 8.x 的某些版本开始,JDK 版本要求更高,同时数据库支持列表里逐渐把 MySQL 移除。
反过来说,SonarQube 7.4 当时同时支持 JDK8 和 MySQL,而且运行非常稳定。既然你的服务器只肯装 JDK8,数据库也定死是 MySQL 5.7,那 7.4 就是那个时代最合理的选择。还有个现实因素:很多旧项目的构建脚本、持续集成流水线都是按 JDK8 环境写的,你硬换新 SonarQube 就得把整个链路全部升级,问题从"装一个工具"变成"升级一套体系"。
1.2 这套组合适合什么场景
如果你接触的是下面这类环境,SonarQube 7.4 值得用:
- 生产环境强制使用 JDK8,且短期内没有任何升级计划
- 数据库已经有 MySQL 5.7 在跑,不想额外引入 PostgreSQL 等新组件
- 内网隔离,无法使用 Docker 镜像,只能离线下载安装包
- 项目以传统 Java Web 工程为主,只要求静态代码扫描和基础质量门禁
我实战中发现,7.4 在 4G 内存的 Windows 服务器上也能跑,配置得当不会频繁 OOM。新版 SonarQube 对内存的要求明显更高,低配环境跑起来会有点吃力。所以老版本不等于差,只是适合特定约束条件。
1.3 和 sonar-scanner-cli 的版本搭配思路
sonar-scanner-cli 是独立于 SonarQube Server 的扫描器,负责在项目机器上分析代码并把结果上传到服务器。版本搭配有一个朴素原则:扫描器不要比服务器新太多。
我用 7.4 服务器时,习惯选择同时期的 sonar-scanner-cli 3.x,这样 Web API 的接口字段、token 校验方式都很匹配。后来的 4.x 扫描器也能连 7.4,但偶尔会出现某些字段不再被识别的情况。如果你已经在用 7.4 服务器,保守一点,挑 3.x 版本的扫描器最省心。
2. JDK 与 MySQL 的准备细节:回填最容易绕路的地方
2.1 安装 JDK8 时的三个关键注意点
SonarQube 7.4 虽然要求 JDK8,但不是说随便装个 JRE 就行。我在多个环境里试过,最稳的组合是完整安装 JDK 8 而不是精简版 JRE。因为后续 sonar-scanner-cli 本身也要跑 Java 进程,有些启动脚本会去调用 JAVA_HOME 下的工具,环境里只有一个 JRE 容易出问题。
配置 JAVA_HOME 时,建议指向 JDK 的根目录,比如:
JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202 PATH=%JAVA_HOME%\bin;%PATH%有一个特别容易忽略的隐患:JDK 安装路径不能包含中文和特殊符号,如果安装目录是C:\Java\jdk1.8.0_202这种简洁路径会少很多麻烦。Windows 的默认安装路径里带有Program Files空格,大部分情况下问题不大,但一旦 SonarQube 的 wrapper 脚本解析路径出错,你要第一时间怀疑这里。我当时就是在conf/wrapper.conf里直接写死了 java.exe 的绝对路径,才绕开空格问题。
2.2 MySQL 数据库初始化:字符集和授权一步到位
SonarQube 需要自己管理数据库,里面的表结构初始化和数据迁移都靠启动时自动完成。所以 MySQL 侧只需要提前创建库和账号,不需要手动建表。
在 MySQL 5.7 环境里执行下面这几条命令:
CREATE DATABASE sonar DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER 'sonar'@'localhost' IDENTIFIED BY 'sonar_password'; GRANT ALL PRIVILEGES ON sonar.* TO 'sonar'@'localhost'; FLUSH PRIVILEGES;字符集必须指定 utf8,如果遗漏,后续 SonarQube 在初始化时可能出现索引长度超限或者中文乱码。排序规则方面,utf8_general_ci 在大多数场景下已经够用,没必要追求更复杂的排序规则。授权这里直接给了sonar.*的 ALL 权限,这是为了初始化表格时不被权限卡住。线下测试环境可以这样,生产环境如果安全要求高,可以再收窄到建表、增删改查等具体权限,但初始化阶段可能会有坑。
MySQL 8 在写这篇的时候已经被大量使用,但那不是 SonarQube 7.4 的友好伙伴。7.4 自带的 MySQL JDBC 驱动比较旧,连接 MySQL 8 时经常报认证插件错误,如果你只有 MySQL 8 可用,一个勉强可行的办法是在连接串上追加allowPublicKeyRetrieval=true,但我不推荐在 7.4 上硬撑 MySQL 8,直接把数据库降回 5.7 或者换用 Docker 版 MySQL 5.7 会稳定得多。
2.3 防火墙和端口规划
Windows 自带防火墙可能会导致局域网内其他机器访问不了 SonarQube 平台。SonarQube 默认端口是 9000,Elasticsearch 节点间通信用 9001。如果你只是本机扫描,不用关心这些,但团队协作扫描,其他同事的机器也要访问你的平台,就要在防火墙里放行 9000 端口。
我建议在一开始就规划好端口。常见的冲突是 9000 端口被其他 Java Web 项目占用,如果那样可以改sonar.web.port=19000等任意端口,同时在扫描器配置里同步修改 sonar.host.url。改端口这件事本身不复杂,但很容易忘了改扫描器,导致已经装好的平台用不了。
3. 解压部署与 sonar.properties 配置:一次讲完数据库、端口和内存
3.1 下载解压与目录结构的理解
SonarQube 7.4 的发行包是一个 zip 压缩包,名字类似sonarqube-7.4.zip。解压之后你会看到几个核心目录:
bin:Windows 和 Linux 的启动脚本conf:SonarQube 主配置目录lib:各类 Jar 包和 JDBC 驱动logs:运行日志目录web:内置 Web 服务器资源elasticsearch:内置的 Elasticsearch
解压路径尽量避免带空格和中文,比如D:\sonarqube\sonarqube-7.4就很合适。千万不要图省事直接解压在桌面,路径里的空格和中文会导致 Elasticsearch 启动失败,而且报错信息很隐晦。
3.2 sonar.properties 里真正需要改的四项配置
打开conf\sonar.properties,你不需要把所有配置都看懂,但以下四项必须按环境改:
第一是数据库连接。找到被注释掉的sonar.jdbc.url和sonar.jdbc.username、sonar.jdbc.password,改成下面这样:
sonar.jdbc.username=sonar sonar.jdbc.password=sonar_password sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true这里characterEncoding=utf8明确指定编码,避免中文项目名和注释出现乱码。useSSL=false是本地环境省去证书验证,如果你网络环境强制要求 SSL,这行要调整。
第二是 Web 端口:
sonar.web.port=9000如果 9000 被占用,这里改成别的端口。要注意改端口时必须同步扫描器配置,这是我前面强调过的点。
第三是 Web 登录账号在外部认证相关配置,7.4 版本默认用内置账号即可,先把/etc/sonar.properties里的基础配置改好,登录方式后面再说。
第四是访问上下文路径。如果你不打算把 SonarQube 放在 Nginx 子路径下,保持默认即可,不要随便设置sonar.web.context。一旦设置了这个值,整个访问路径都会变化,扫描器上传地址也要跟着变,初学者很容易在这里绕晕。
3.3 内存配置:别让 Elasticsearch 吃光服务器内存
SonarQube 7.4 会同时启动两个 Java 进程:一个是 Web 服务器,一个是内置 Elasticsearch。如果你机器内存只有 4G,默认配置下很容易出现内存不足,表现就是 Web 界面打不开或者启动日志里写 OOM。
Web 侧的内存配置在conf\wrapper.conf里找wrapper.java.maxmemory,建议在 4G 总内存环境下设置为 1024 或 1536。Elasticsearch 侧的内存配置在elasticsearch\config\jvm.options里,把-Xms和-Xmx都设为 1g 或 1.5g。两个进程加起来控制在 2.5G 以内,Windows 系统本身和 MySQL 才有余量。
我之前有台测试服务器一共 4G 内存,一开始没管默认配置,结果 SonarQube 启动后系统直接卡到几十秒才响应一次。调完内存之后就好了,这个环节千万别跳过。
3.4 安装为 Windows 服务的方式
命令行启动适合调试,但要长期运行,最好注册为 Windows 服务。进入bin\windows-x86-64目录,用管理员身份打开命令行,执行:
InstallNTService.bat安装成功后,在 Windows 服务列表里能看到对应服务。启动 SonarQube 时直接启动这个服务,关机重启后也会自动运行。卸载服务时执行UninstallNTService.bat。这里有一个经验:先直接启动一次确认配置没问题,再装成服务,否则服务启动失败时排查窗口一闪而过,反而更难定位。
4. 第一次启动与 Web 界面验证:从日志倒逼问题定位
4.1 启动脚本的正确打开方式
在bin\windows-x86-64目录下双击StartSonar.bat,首次启动时你可能会看到大量日志刷屏,这是正常的。SonarQube 第一次启动要做数据库初始化、创建表结构、加载内置插件,耗时可能比后续启动更久。
如果窗口一闪而过,说明启动脚本在加载阶段就失败了。这时不要重复双击,直接去logs目录下看日志。7.4 版本会生成sonar.log、web.log、ce.log、es.log等文件。其中es.log记录 Elasticsearch 启动情况,web.log记录 Web 服务初始化情况,sonar.log是整体运行的主日志。
4.2 首次访问与默认账号处理
启动完成后,浏览器访问http://localhost:9000。如果页面能打开,说明 Web 服务本身没问题。默认账号是admin/admin,登录后系统会提示你修改默认密码。
这一步一定要做。SonarQube 默认口令在安全扫描工具里属于高危项,如果放到公网内网不进行加固,分分钟被内部安全测试扫出来。改密码之后,后续生成扫描 token 也更安全。
4.3 Web 界面能打开但登录后数据为空
这种情况经常出现在sonar.jdbc.url配置错误但 Web 服务还能启动的场景。SonarQube 连接数据库失败不会导致 Web 进程崩溃,而是让你看到一个没有项目、没有历史记录的空白界面。排查方法是看logs\sonar.log里有没有数据库连接异常,同时用命令行简单测试一下 MySQL 连接。
我第一次搭的时候,就是因为 MySQL 授权写成了sonar@'%',但 JDBC 连接串用的是 localhost,实际匹配不上,登录进去一片空白。把授权改成sonar@'localhost'之后立即好了。
5. sonar-scanner-cli 的下载、配置与一次完整项目扫描
5.1 扫描器安装与环境变量
sonar-scanner-cli 是独立的命令行扫描器,下载解压后同样建议放到无空格路径。以 3.x 版本为例,解压后目录包含bin、conf等目录。把bin目录加入 PATH,命令行里就能直接执行sonar-scanner。
Windows 下确认执行:
sonar-scanner -h如果提示找不到命令,检查JAVA_HOME和 PATH 是否配置正确。扫描器也是 Java 程序,没有正确的 Java 环境就跑不起来。
5.2 扫描器与服务器的连接配置
扫描器连接服务器的地址配置在conf\sonar-scanner.properties:
sonar.host.url=http://127.0.0.1:9000 sonar.sourceEncoding=UTF-8127.0.0.1写死成 localhost 也行。如果 SonarQube 服务器不是本机,把 IP 换成服务器地址。sonar.sourceEncoding=UTF-8很重要,项目里有中文注释和中文文件名时,不指定编码扫描结果会出现大量乱码问题。
5.3 创建 token 代替密码登录
在 SonarQube Web 界面右上角点击用户头像,进入我的账号,可以生成一个 token。扫描器执行上传时用 token 比用账号密码更安全,而且 token 失效也能单独吊销。
使用 token 有两种方式:一种是在sonar-scanner.properties里配置sonar.login=你的token,另一种是在命令行里通过-Dsonar.login=你的token传入。我建议在本地调试用命令行传入,避免 token 泄露到公共配置仓库。
5.4 扫描一个最简单的 Java 项目
假设你项目目录是D:\demo\order-service,结构大概是这样:
D:\demo\order-service ├── pom.xml ├── sonar-project.properties └── src └── main └── java └── com └── demo └── OrderService.java在项目根目录新建sonar-project.properties:
sonar.projectKey=order-service sonar.projectName=订单服务 sonar.projectVersion=1.0 sonar.sources=src sonar.java.binaries=target/classes sonar.sourceEncoding=UTF-8这里sonar.projectKey是整个 SonarQube 平台里的唯一标识,sonar.java.binaries指向编译后的 class 文件目录。因为 sonar-scanner 不是 Maven 插件,它无法自己完成 Java 编译,所以扫描前要先构建项目。
我习惯先执行:
mvn clean compile然后再执行:
sonar-scanner扫描完成后命令行会返回结果,Web 界面里刷新就能看到订单服务这个项目,包含代码异味、bug、重复代码、安全漏洞等指标。
如果分析报告里看不到问题,先检查sonar.sources=src是否写对。很多人默认写成sonar.sources=.结果把 target 目录也扫进去,反而出现大量没意义的报告内容。扫描路径精确到源码目录,报告才会干净。
6. 安装过程中的真实坑位清单:从日志反推故障
6.1 端口冲突导致的 Elasticsearch 启动失败
SonarQube 的 Elasticsearch 除了自身占用 9001 端口,还会占用一些额外端口。最常见的报错是BindException或Address already in use,在es.log里能看到。
解决方法很简单:查一下是哪个进程占用了端口,然后要么杀掉冲突进程,要么改掉 SonarQube 的 Web 端口。如果你只想临时启动一次检查配置,也可以先把其他 web 服务停掉。
6.2 MySQL 连接失败时的典型日志特征
假设sonar.jdbc.url写错或者账号密码不对,sonar.log会出现类似Cannot connect to database的提示。遇到这种情况,先不要急着改数据库账号,把下面几项逐项检查:
- MySQL 是否真的启动成功
- 账号密码里是否有特殊字符需要转义
- 数据库字符集是否为 utf8
- 连接串里的库名是否和
CREATE DATABASE sonar完全一致
有一次我排查了一个多小时,最后发现是密码里包含&符号,在 properties 文件里没有做转义,连接串被解析错了。所以这种老版本工具,密码还是用纯字母数字组合最省心。
6.3 扫描器上传失败与 token 权限问题
扫描器执行到最后弹出Not authorized之类的错误,通常不是扫描器问题,而是 token 没有访问权限。7.4 版本里,如果你用全局管理员账号生成的 token,扫描完会自动创建项目。如果你用的是普通用户 token,可能需要先在 Web 界面里手动创建项目。
最简单的调试方式是先用管理员账号生成一个 token,放到sonar.login里跑一遍,通了之后再按实际权限收敛。
6.4 系统内存不足导致的启动卡死
如果启动日志里出现native memory allocation failed或者进程非常卡顿,基本就是内存分配不合理。前面提到过,把 Web JVM 和 Elasticsearch 的堆内存都调到一个保守值,不要贪心。有同学觉得服务器有 16G 内存就大胆给 Elasticsearch 分配 8G,结果 Windows 预留内存和其他进程叠加,一样不稳定。
6.5 中文乱码和编码不一致
代码里的中文注释、中文项目名,只要 SonarQube 服务器端数据库字符集是 utf8,扫描器端也默认 UTF-8,一般不会乱码。如果出现乱码,修改sonar-scanner.properties里的sonar.sourceEncoding=UTF-8,然后重新扫描。以前老项目如果是 GBK 编码,就相应改成GBK,关键是要和源码实际编码一致。
6.6 日志文件就是你最好的排错手册
遇到问题先别到处问,我总结了一个快速定位思路:
先看logs\sonar.log有没有明显的错误堆栈,再看logs\es.log确认 Elasticsearch 是否启动成功,接着看logs\web.log确认 Web 容器是否完成初始化。很多时候问题都集中在数据库连接或者内存分配,日志里都会明确写出来。把完整堆栈贴到搜索引擎搜索,比你重新装一遍快得多。
7. 装机之后的日常维护与几条真心建议
SonarQube 7.4 跑起来之后,不是放着不管就行。它的数据全部存在 MySQL 里,所以数据库备份是第一优先级。我通常会写一个简单的计划任务,定期执行 MySQL 的mysqldump备份,备份到独立磁盘。不要只盯着 SonarQube 本身的目录备份,那些配置文件和一个重装包没有太大区别,真正有价值的质量报告历史数据全在数据库里。
内存观察也重要。SonarQube 长时间运行后,Web 进程的内存使用会缓慢上升,这属于正常现象。但如果有一天发现页面响应极慢,优先看服务器可用内存和logs目录是否被日志文件撑爆。日志文件不清理,磁盘满了之后扫描任务会莫名其妙失败。
关于版本升级,如果以后环境允许,从 7.4 跳到新版时要先检查 JDK 和数据库兼容性,不要直接在原目录上覆盖解压。旧版本的配置目录结构和新版差异很大,直接覆盖等于把脏配置带到了新环境。我建议先用一台测试机从零部署新版,把插件、扫描器都验证通过,再考虑替换生产环境。
最后分享一个个人习惯:每次安装完 SonarQube 平台,我都会把下载的 zip 包、JDK 版本、MySQL 版本、扫描器版本完整记录在一个备忘文档里。这类老版本工具对环境非常敏感,隔几个月再回头看,光靠记忆很难还原当时的组合。把版本钉死,后续无论排查问题还是复现环境,都会快很多。
如果你现在正在为了 JDK8 和 MySQL 的环境折腾 SonarQube 7.4,别急着放弃。这套组合跑熟之后非常稳定,而且项目质量数据沉淀下来之后,对团队带来的价值远比工具本身大。按上面这些步骤走一遍,基本都能顺利跑起来。