☰
SonarQube 7.4 内网离线部署实战:从安装配置到 CI 质量门禁集成
2026/10/18 5:07:45 网站建设 项目流程

简介:SonarQube 7.4 是一款开源代码质量管理工具的完整安装包,面向 Java、Python、C#、JavaScript 等多语言开发者及需要搭建代码质量平台的团队。它可帮助发现代码漏洞、代码异味与复杂度问题,并支持与 Jenkins、GitLab CI/CD 等持续集成工具对接,实现自动化质量检查。压缩包为 rar 格式,整体约 161.38MB,内含 bin、conf、extensions、lib、web、libexec 等目录及 README、LICENSE 文件,分别用于服务启停脚本、数据库与端口配置、插件扩展、运行库、前端界面资源和辅助工具,结构完整,解压后按 conf/sonar.properties 调整即可部署。目前已有 637 人学习下载,适合需要快速获取 7.4 版本、搭建本地代码质量分析环境的中高级开发者参考使用。

1. 为什么 2024 年还有人把 SonarQube 7.4 装进内网

上周帮一个做军工配套的团队排查代码质量平台,他们内网跑的就是 SonarQube 7.4,一台 4C8G 的 CentOS 7 虚拟机,从 2019 年上线到现在没动过。新来的同事想升级到最新版,结果发现新版要求 JDK 11 以上、数据库必须 PostgreSQL 12+,而他们那台机器上还跑着 JDK 8 和 MySQL 5.7 的老业务。折腾两天后决定不升了,继续用 7.4。

这个场景其实很典型。SonarQube 7.4 是 2018 年底发布的 LTS 版本,支持 JDK 8、MySQL 5.6/5.7、PostgreSQL 9.6-10,对老内网环境极其友好。它的核心能力——静态代码分析、代码异味检测、覆盖率报告、质量门禁——放到今天依然够用。如果你手上有一台不能随便动环境的机器,或者需要给一个离线团队搭一套代码扫描服务,7.4 反而是最省事的选择。

这篇文章面向三类人:一是要在内网离线部署 SonarQube 的运维;二是想给老项目加代码扫描但不想动 JDK 的开发者;三是需要理解 SonarQube 扫描器与服务器交互机制的技术负责人。我会从安装、配置、扫描器对接、质量门禁设置一路讲到踩坑排查,所有步骤都在一台干净的 CentOS 7 虚拟机上验证过。

2. 环境准备与数据库选型:为什么 MySQL 5.7 是 7.4 的甜点区

2.1 版本兼容性矩阵与选型逻辑

SonarQube 7.4 对运行环境有明确的硬性要求,选错了版本连启动都过不去。先看这张表:

组件最低要求推荐版本说明
JDK8Oracle JDK 8u191 或 OpenJDK 8不支持 JDK 11
数据库MySQL 5.6 / PostgreSQL 9.6MySQL 5.7 / PostgreSQL 10内网首选 MySQL 5.7
内存2GB4GB 以上Elasticsearch 内嵌,吃内存
磁盘10GB50GB SSD索引和报告会持续增长
操作系统任意支持 JDK 8 的系统CentOS 7.x内核参数需调整

为什么推荐 MySQL 5.7 而不是 PostgreSQL?不是技术优劣问题,而是内网运维的现实:大多数国内企业的内网数据库运维体系围绕 MySQL 建立,备份脚本、监控模板、权限审批流程都是现成的。SonarQube 7.4 对 MySQL 5.7 的支持已经非常稳定,只要注意字符集和 SQL 模式两个参数就行。

有一个容易被忽略的点:SonarQube 7.4 内置了 Elasticsearch 5.6.3,而 Elasticsearch 对文件描述符和虚拟内存有硬性要求。如果这两项没调,启动时会直接报错退出,日志里写的是max file descriptors [4096] for elasticsearch process is too low。这不是 SonarQube 的问题,是 Elasticsearch 的 bootstrap 检查。

2.2 系统参数调整与数据库初始化

先处理操作系统层面的限制。以下命令在 CentOS 7 上验证通过:

# 查看当前限制 ulimit -n sysctl vm.max_map_count # 永久调整文件描述符限制 echo "sonar soft nofile 65536" >> /etc/security/limits.conf echo "sonar hard nofile 65536" >> /etc/security/limits.conf # 调整虚拟内存映射数(Elasticsearch 要求至少 262144) echo "vm.max_map_count=262144" >> /etc/sysctl.conf sysctl -p # 创建专用用户(不要用 root 跑 SonarQube) useradd sonar passwd sonar

vm.max_map_count这个参数控制进程可以拥有的内存映射区域数量。Elasticsearch 的 Lucene 索引在底层大量使用 mmap,默认值 65530 不够用,启动时会抛max virtual memory areas vm.max_map_count [65530] is too low。改成 262144 是官方建议值,改完必须执行sysctl -p让它生效,重启后也会保留。

接下来初始化数据库。SonarQube 7.4 要求数据库使用 UTF-8 字符集,并且不能开启ONLY_FULL_GROUP_BY模式:

-- 创建数据库和用户 CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER 'sonar'@'localhost' IDENTIFIED BY 'Sonar@2024'; GRANT ALL PRIVILEGES ON sonar.* TO 'sonar'@'localhost'; FLUSH PRIVILEGES; -- 检查 SQL 模式(必须去掉 ONLY_FULL_GROUP_BY) SELECT @@sql_mode; -- 如果结果中包含 ONLY_FULL_GROUP_BY,需要在 my.cnf 中移除

ONLY_FULL_GROUP_BY是 MySQL 5.7 的默认 SQL 模式之一,它要求 GROUP BY 查询中 SELECT 的列必须出现在 GROUP BY 中或使用聚合函数。SonarQube 7.4 的部分内置查询不满足这个约束,开启后会在启动初始化阶段报 SQL 语法错误。修改/etc/my.cnf,在[mysqld]段下添加sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,然后重启 MySQL。

注意:数据库密码不要用特殊字符$和!,SonarQube 的配置文件对这两个字符的转义处理有问题,会导致连接失败但报错信息不明确。

3. 安装部署与扫描器对接:从零到第一次扫描成功

3.1 SonarQube 服务端安装与配置

下载 SonarQube 7.4 的发行包(社区版即可,内网代码扫描不需要开发者版的多分支分析)。解压到/opt下,目录结构里需要关注三个位置:conf/sonar.properties是主配置,bin/linux-x86-64/sonar.sh是启动脚本,logs/下是运行日志。

# 解压并设置权限 cd /opt unzip sonarqube-7.4.zip chown -R sonar:sonar /opt/sonarqube-7.4 chmod +x /opt/sonarqube-7.4/bin/linux-x86-64/sonar.sh # 编辑主配置 vim /opt/sonarqube-7.4/conf/sonar.properties

配置文件里需要改动的核心项:

# 数据库连接 sonar.jdbc.username=sonar sonar.jdbc.password=Sonar@2024 sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false # Web 服务端口(默认 9000,如果被占用改这里) sonar.web.port=9000 sonar.web.context=/sonar # 允许匿名访问(内网可选,方便查看报告) sonar.forceAuthentication=false # Elasticsearch 存储路径(默认在 data/ 下,数据量大时建议挂独立磁盘) sonar.path.data=/data/sonar/data sonar.path.temp=/data/sonar/temp

rewriteBatchedStatements=true这个参数很关键。SonarQube 在分析大型项目时会批量写入大量数据,开启这个选项后 MySQL 驱动会把多条 INSERT 合并成一条,写入性能提升明显。useConfigs=maxPerformance是 MySQL 驱动内置的性能优化配置集,配合rewriteBatchedStatements使用效果最好。

启动服务:

# 切换到 sonar 用户启动 su - sonar /opt/sonarqube-7.4/bin/linux-x86-64/sonar.sh start # 查看启动日志 tail -f /opt/sonarqube-7.4/logs/sonar.log

启动过程分三个阶段:先启动 Elasticsearch(日志里能看到Elasticsearch started),再启动 Web Server(Web server started),最后是 Compute Engine(Compute Engine started)。三个都出现才算成功。首次启动会初始化数据库表结构,大概需要 1-2 分钟。浏览器访问http://服务器IP:9000/sonar,默认账号密码都是admin。

3.2 扫描器配置与项目接入

SonarQube 的扫描器(Scanner)是独立于服务端的命令行工具,负责在代码所在机器上执行分析,然后把结果推送到服务端。7.4 时代主流用的是sonar-scanner命令行工具,Maven 项目也可以用sonar-maven-plugin。

下载 sonar-scanner 3.3 版本(与 7.4 服务端匹配),解压后配置conf/sonar-scanner.properties:

# 指向 SonarQube 服务端地址 sonar.host.url=http://192.168.1.100:9000/sonar # 如果服务端开启了强制认证,需要配置 token # sonar.login=your_token_here

然后在项目根目录创建sonar-project.properties:

# 项目唯一标识(不能重复) sonar.projectKey=my-java-app sonar.projectName=My Java Application sonar.projectVersion=1.0.0 # 源码目录(多个用逗号分隔) sonar.sources=src/main/java sonar.tests=src/test/java # 编码 sonar.sourceEncoding=UTF-8 # 排除目录 sonar.exclusions=**/generated/**,**/node_modules/**,**/*.min.js # 覆盖率报告路径(如果接了 JaCoCo) sonar.jacoco.reportPaths=target/jacoco.exec

执行扫描:

# 在项目根目录执行 /path/to/sonar-scanner/bin/sonar-scanner \ -Dsonar.projectKey=my-java-app \ -Dsonar.sources=src/main/java \ -Dsonar.host.url=http://192.168.1.100:9000/sonar \ -Dsonar.login=admin \ -Dsonar.password=admin

扫描完成后,服务端会自动触发质量门禁计算。如果项目是第一次扫描,需要等几秒钟让 Compute Engine 处理完报告,然后在 Web 界面就能看到代码异味、Bug、漏洞的统计。

注意:sonar.login和sonar.password用默认 admin 账号只适合测试。生产环境应该在 SonarQube 界面生成专用 Token(用户头像 → My Account → Security → Generate Tokens),然后用-Dsonar.login=token值的方式认证,避免密码明文出现在命令行历史里。

3.3 质量门禁与规则集定制

SonarQube 7.4 默认的质量门禁叫 "Sonar way",核心指标是:新代码覆盖率不低于 80%、新代码重复率不高于 3%、新代码没有 Blocker 级别问题。这个门禁对老项目改造来说太严了,直接套用会导致所有项目都是红色。

我一般会新建一个质量门禁,针对存量项目放宽标准:

指标Sonar way 默认值存量项目建议值说明
新代码覆盖率≥ 80%≥ 60%老项目补测试成本高
新代码重复率≤ 3%≤ 5%容忍少量复制粘贴
Blocker 问题00这个不能松
Critical 问题0≤ 5给修复缓冲期
代码异味无要求不设门禁只做统计不卡流程

在 Web 界面Quality Gates→Create新建门禁,然后到Rules→Quality Profile里激活或关闭特定规则。比如 Java 项目中squid:S106(用日志代替 System.out.println)这条规则,如果项目里大量使用System.out做调试输出,可以先降级为 Minor 而不是直接报 Critical。

规则集调整有个原则:先跑一遍全量扫描,看问题分布,再决定关哪些规则。不要一上来就关规则,那样等于把 SonarQube 当摆设。正确的做法是看Issues页面按规则分组,找出误报率最高的几条规则,针对性关闭或调整阈值。

4. 避坑排查:7.4 版本特有的五个翻车现场

4.1 启动报错 "max file descriptors too low"

现象:执行sonar.sh start后进程立刻退出,sonar.log里出现max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]。

原因:Elasticsearch 启动时检查当前用户的文件描述符限制,默认的 1024 或 4096 不满足要求。虽然/etc/security/limits.conf里改了,但sonar.sh脚本启动时可能没有加载 PAM 限制。

解决:除了改limits.conf,还要在sonar.sh脚本开头手动设置ulimit -n 65536。或者用 systemd 管理服务,在 unit 文件里加LimitNOFILE=65536。最直接的办法是在启动命令前加ulimit -n 65536 &&。

4.2 数据库连接失败但报错信息模糊

现象:启动日志里写Cannot connect to database. Please check your JDBC URL and credentials,但用 mysql 客户端能正常连接。

原因:SonarQube 7.4 使用的 MySQL 驱动版本较老(5.1.x),不支持 MySQL 8 的默认认证插件caching_sha2_password。如果数据库是 MySQL 8,即使端口密码都对也连不上。

解决:确认数据库版本。如果是 MySQL 8,要么把用户认证插件改成mysql_native_password(ALTER USER 'sonar'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码'),要么换 MySQL 5.7。7.4 官方不支持 MySQL 8,强行用会有各种兼容问题。

4.3 扫描大型项目时 Compute Engine 卡死

现象:扫描器显示ANALYSIS SUCCESSFUL,但 Web 界面一直显示Pending,报告出不来。查看ce.log发现处理线程卡在某个任务上。

原因:项目文件太多(超过 10 万个文件),Compute Engine 的默认堆内存不够,或者数据库写入超时。

解决:调整sonar.properties里的 Compute Engine 内存参数:sonar.ce.javaOpts=-Xmx2g -Xms512m -XX:+HeapDumpOnOutOfMemoryError。同时检查数据库连接池配置,适当增大sonar.jdbc.maxActive(默认 10,可以调到 20)。如果还是卡,在扫描器端加-Dsonar.scm.disabled=true关闭 SCM 信息采集,能减少大量数据写入。

4.4 中文乱码与编码问题

现象:扫描包含中文注释的 Java 文件后,Web 界面显示的代码片段里中文变成问号或乱码。

原因:扫描器默认使用系统编码读取源文件,如果服务器 locale 是 POSIX 或 C,中文会被错误解码。

解决:在sonar-project.properties里显式指定sonar.sourceEncoding=UTF-8,同时在扫描器启动脚本里设置export LANG=en_US.UTF-8或zh_CN.UTF-8。数据库连接 URL 里也要带characterEncoding=utf8。三个地方都对了才不会乱码。

4.5 质量门禁不生效或状态不更新

现象:扫描完成后质量门禁一直显示None或停留在上一次的状态,新提交的代码问题没有触发门禁失败。

原因:SonarQube 7.4 的质量门禁计算依赖 Compute Engine 的任务队列。如果 CE 进程异常或队列积压,门禁状态不会刷新。另外,如果项目没有关联到正确的 Quality Gate(比如新建的门禁没有设为默认),也会出现这个问题。

解决:先检查ce.log是否有异常堆栈。然后在项目设置里确认Quality Gate选的是正确的门禁。如果是队列积压,重启 SonarQube 服务清空队列。还有一个隐蔽原因:扫描时没有传sonar.projectVersion,导致新代码和老代码无法区分,门禁只统计新代码的指标就失效了。

5. 进阶技巧:用 Web API 把扫描结果接进 CI 流水线

SonarQube 7.4 的 Web API 是它最被低估的能力。很多团队只把它当网页看板用,其实通过 API 可以把扫描结果直接卡在 CI 流水线的构建步骤里,实现「质量门禁不通过则构建失败」。

核心 API 是/api/qualitygates/project_status,传入项目 key 就能拿到门禁状态:

# 查询项目质量门禁状态 curl -s -u admin:admin \ "http://192.168.1.100:9000/sonar/api/qualitygates/project_status?projectKey=my-java-app" \ | python -m json.tool

返回的 JSON 里status字段是OK或ERROR。在 Jenkins 或 GitLab CI 的构建脚本里加一段判断:

#!/bin/bash # 在扫描完成后检查质量门禁 SONAR_URL="http://192.168.1.100:9000/sonar" PROJECT_KEY="my-java-app" TOKEN="your_token_here" STATUS=$(curl -s -u "${TOKEN}:" \ "${SONAR_URL}/api/qualitygates/project_status?projectKey=${PROJECT_KEY}" \ | grep -o '"status":"[^"]*"' | head -1 | cut -d'"' -f4) if [ "$STATUS" != "OK" ]; then echo "质量门禁未通过,当前状态:${STATUS}" # 拉取具体失败指标 curl -s -u "${TOKEN}:" \ "${SONAR_URL}/api/qualitygates/project_status?projectKey=${PROJECT_KEY}" \ | python -m json.tool exit 1 fi echo "质量门禁通过"

这段脚本的逻辑是:扫描完成后调 API 查门禁状态,如果不是 OK 就打印详细失败指标并返回非零退出码,CI 流水线收到非零退出码就会标记构建失败。-u "${TOKEN}:"的写法是 curl 的 basic auth 语法,冒号后面留空表示只用 token 不用密码。

还有一个实用 API 是/api/measures/component,可以拉取指定项目的具体指标值:

# 获取代码覆盖率、代码异味数、Bug 数 curl -s -u "${TOKEN}:" \ "${SONAR_URL}/api/measures/component?component=${PROJECT_KEY}&metricKeys=coverage,code_smells,bugs,vulnerabilities" \ | python -m json.tool

这个接口适合做自定义报表。比如每周跑一次定时任务,把各项目的指标拉下来存到自己的数据库里,做趋势分析。SonarQube 自带的趋势图只能看单个项目,跨项目对比还是要自己动手。

我一般会在 CI 脚本里加一个「扫描后等待」的逻辑:扫描器返回成功后,Compute Engine 处理报告需要几秒到几十秒不等,如果立刻调 API 可能拿到的是上一次的状态。稳妥做法是轮询/api/ce/task?id=xxx直到任务状态变成SUCCESS,再查门禁。扫描器输出里会带ceTaskId,用grep提取出来就行。

从那以后我每次配 CI 流水线,都会强制走一遍「扫描 → 等 CE 完成 → 查门禁 → 失败则阻断」的完整链路,不再只看扫描器返回的 SUCCESS。因为扫描成功只代表分析完成,不代表质量达标。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询