尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从零部署SonarQube:Docker Compose实战与中文汉化指南

从零部署SonarQube:Docker Compose实战与中文汉化指南 SonarQube在研发团队里往往不是“要不要上”的问题而是“什么时候上”的问题。代码量过了某个临界点以后靠人肉 Code Review 根本盯不住那些“先记一下以后再说”的坏味道。SonarQube 作为一款成熟的代码质量分析平台核心价值就是把这套事情固化下来让每次提交都过一遍机器审查把重复率、复杂度过高、未处理异常、安全漏洞嫌疑这类问题摊开放在面板上。这篇文章会以一个实际部署者的视角讲清楚 SonarQube 社区版怎样从零开始部署以及中文汉化插件怎么装、装完有哪些容易栽的坑。我也把部署过程中那些文档里不会写、只有自己动手才会遇到的细节一并整理出来。内容覆盖了部署思路、资源准备、Docker Compose 实战、插件汉化和 CI/CD 落地读者可以按顺序操作也可以直接把 compose 文件和命令抄走在自己的环境里跑起来。1. 项目思路拆解先想清楚再动手1.1 为什么是 SonarQube而不是自己写脚本或选其他平台我在给团队搭建这套平台之前想法很简单先找一批静态检查工具比如 Checkstyle、PMD、ESLint然后写脚本把检查结果汇总成报告。但很快发现这条路走不通。首先是规则分散在各工具里报告格式五花八门其次是没有一个统一的“质量门禁”概念检查结果只能给人看没法自动拦截代码合并最后是历史数据不沉淀今天改没改好、趋势是变好还是变差完全看不出来。SonarQube 把这些问题一次解决了。从 7.x 到 9.9 LTS 再到 10.x它已经不是一个单纯的静态分析工具而是一个完整的代码质量分析平台。它对 20 多种主流语言提供内置分析规则覆盖 Java、Python、JavaScript、C#、Go 等支持重复代码率、单元测试覆盖率、复杂度、代码异味、漏洞密度等指标提供 Quality Gate质量门禁机制。更重要的是它有清晰的架构分层扫描器负责采集数据服务端负责汇总展示团队可以用统一的入口管理所有项目的质量状态。选型时我还对比过一些商业产品和自研方案。商业产品在报表和审计功能上确实做得更好但价格对中小团队不友好。自研方案维护成本高规则更新慢而且很少有人愿意长期维护一个“内部质检系统”。社区版的 SonarQube 虽然少了分支分析、报告导出等企业功能但对绝大多数研发团队来说基础的质量管理能力已经完全够用。1.2 一句话说清 SonarQube 的工作架构很多第一次接触 SonarQube 的人会被“服务端 扫描器”这种架构绕晕。我常用一个“体检中心”的类比来解释。SonarQube 服务端就是“体检中心档案室”。它不直接读代码只负责接收扫描结果、存储数据、展示报告、配置规则。数据库默认建议 PostgreSQL存结果数据Elasticsearch 存索引和分析数据。扫描器则是“出诊医生”它跑到你的项目代码里去按照规则逐行检查把发现的问题整理成统一的中间结果再提交给档案室。这种“采集与分析分离”的设计是 SonarQube 能够同时支持几十种语言的根本原因。扫描动作在本地或者 CI 流水线里执行服务端集中管理二者通过网络通信。实际使用中你会发现服务端挂了不影响你跑扫描命令只是扫描结果暂时传不上去。1.3 “部署 汉化”这个任务的难点在哪里只看标题很多人觉得 SonarQube 部署很简单拉个镜像启动容器完事。真上手之后才发现主要难度集中在几个地方。第一是数据库版本匹配。SonarQube 对 PostgreSQL 版本有明确要求9.x 系列对应 PostgreSQL 13 左右10.x 版本又有不同要求。版本不匹配的时候容器能启动但界面会报数据库连接错误日志里全是 SQL 异常。第二是 Elasticsearch 的系统参数要求。SonarQube 内置了 ElasticsearchElasticsearch 对 Linux 系统的vm.max_map_count有最低要求。如果不调整启动后 ES 直接崩溃SonarQube 容器反复重启。第三是汉化插件的版本匹配。中文包不是随便下一个装上就能用插件版本必须和 SonarQube 服务端版本对应。装错版本最典型的症状是插件显示已安装界面却死活不出中文。这些坑都不是看官方文档就能直接避开的尤其汉化这块很多文章只写“下载 jar 放进去重启”不提语言包和版本对应关系也不提用户级语言切换。所以我决定把这些内容单独拉出来逐条给读者讲清楚。2. 部署前准备版本、资源和数据库选型2.1 版本选择LTS 还是特性版第一次部署容易在版本上犹豫不决。我的建议很直接生产环境用 LTS尝鲜才用特性版。版本定位适合场景备注SonarQube 9.9.x Community当前长期支持版本生产部署、团队常规质量管理文档和插件生态最稳定SonarQube 10.x Community新特性版本想用最新规则集、做功能体验的团队插件版本需要跟进部分旧插件不兼容SonarQube Developer Edition商业化版本需要分支分析、PR 分析的团队收费但是功能确实多我这篇文章以 9.9.3-community 为例。原因是 9.9 是 LTS 版本社区维护时间最长汉化插件有对应的稳定版本。如果你用的是 10.x操作思路完全一样只是中文语言包要下载对应 10.x 的版本docker-compose 里的镜像 tag 换成sonarqube:10.6.0-community即可。2.2 硬件资源与系统参数别在第一步就翻车SonarQube 不是特别吃资源但也不是随便一台 1G 内存的小机器就能跑起来的。官方推荐最低 2 核 4G 内存我自己实测2G 内存跑一次全量扫描会明显卡顿多个团队同时使用时会频繁触发 GC甚至直接 OOM。磁盘方面代码库越大历史数据涨得越快。建议给 SonarQube 的数据目录单独分一块空间至少预留 20G 以上。Elasticsearch 的索引文件会随着项目数量线性增长这个很多人没意识到等到磁盘被占满的时候才发现问题。Linux 系统上最关键的参数是vm.max_map_count。SonarQube 内置的 Elasticsearch 需要它至少达到 262144生产环境建议设为 524288。查一下当前值sysctl vm.max_map_count如果小于 262144执行sudo sysctl -w vm.max_map_count524288这个命令只对当前会话有效要永久生效在/etc/sysctl.conf末尾加上一行vm.max_map_count524288然后执行sudo sysctl -p验证。这一步不做SonarQube 容器会反复重启日志里出现类似max virtual memory areas vm.max_map_count [65530] is too low的报错。这个问题在所有 SonarQube 部署场景里几乎都会遇到属于第一优先级要处理的事项。2.3 数据库方案单独部署还是容器编排SonarQube 必须搭配外部数据库才能稳定运行。它内置的 H2 数据库只适合评估试用重启容器数据就会丢团队使用绝对不能用。生产上有两种主流方案一种是数据库独立部署在物理机或云数据库上适合公司已有数据库运维管理体系的情况另一种是数据库和 SonarQube 一起用 Docker Compose 编排适合快速搭建、不想单独维护数据库的环境。我推荐第二种。用 Docker Compose 一次性把 PostgreSQL 和 SonarQube 启动起来两个服务通过内部网络通信不需要额外暴露数据库端口安全性和易用性都兼顾了。数据持久化通过 Volume 实现重启容器也不会丢数据。后面要升级版本只改镜像 tag重新执行 compose 命令就行。3. Docker Compose 部署实操一套能直接抄的配置3.1 完整的 docker-compose 配置下面是我实际使用的docker-compose.yml可以直接复制使用。注意版本和参数我都做了注释方便你根据自己的环境调整。services: db: image: postgres:13 container_name: sonarqube-db restart: unless-stopped environment: POSTGRES_USER: sonar POSTGRES_PASSWORD: sonar POSTGRES_DB: sonar volumes: - sonar_db_data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U sonar -d sonar] interval: 10s timeout: 5s retries: 5 sonarqube: image: sonarqube:9.9.3-community container_name: sonarqube restart: unless-stopped depends_on: db: condition: service_healthy ports: - 9000:9000 environment: SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar SONAR_JDBC_USERNAME: sonar SONAR_JDBC_PASSWORD: sonar volumes: - sonar_data:/opt/sonarqube/data - sonar_logs:/opt/sonarqube/logs - sonar_extensions:/opt/sonarqube/extensions volumes: sonar_db_data: sonar_data: sonar_logs: sonar_extensions:这里有几个设计上的选择值得说明。depends_on加上condition: service_healthy是关键细节。SonarQube 启动时如果连不上数据库会直接报错退出。等 PostgreSQL 健康检查通过再启动 SonarQube能避免第一次启动时的竞争条件。PostgreSQL 的 healthcheck 用的是pg_isready这是官方镜像自带的工具不需要额外安装。环境变量SONAR_JDBC_URL的写法是jdbc:postgresql://db:5432/sonar这里的db是 compose 服务名而不是 IP。Compose 会自动创建一个内部网络服务之间可以通过服务名互相访问。sonar既是数据库名也是数据库用户名和密码这三个值在 PostgreSQL 初始化阶段由POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB定义保持一致可以避免认证问题。有一个参数我没有在 compose 里写SONAR_ES_BOOTSTRAP_CHECKS_DISABLEtrue。网上不少教程会建议加这个环境变量来跳过 Elasticsearch 引导检查但这是治标不治本。ES 的 bootstrap check 是为了保护它不在不满足要求的系统上运行你把它禁了ES 照样会因为vm.max_map_count过低而崩溃。正确做法是调好宿主机参数。3.2 启动前的目录和镜像检查执行docker compose up -d之前我习惯先做三项检查第一确认 Docker 和 Compose 版本。如果你用的是 Docker Desktop通常 Compose 已经集成在里面。服务器上安装的 Docker Engine 需要单独安装 compose 插件执行docker compose version检查。第二确认 9000 端口没被占用。SonarQube 默认监听 9000如果服务器上已经有别的应用占了容器会一直显示 “port is already allocated”。这时把 compose 里的端口映射改成9001:9000访问的时候用http://ip:9001。第三把当前目录整理干净。执行 compose 命令时所有卷数据都会带上项目名作为前缀比如/var/lib/docker/volumes/sonarqube_sonar_db_data/。项目名默认是当前目录名如果你在不同目录下执行过同一份 compose 文件会产生多个孤立的卷占用磁盘空间。我通常把项目文件放在/opt/sonarqube目录下保持项目名固定。三项检查没问题执行docker compose up -d第一次启动会拉取两个镜像时间取决于网速。拉完后观察日志docker compose logs -f sonarqube看到类似SonarQube is up或者访问日志中出现 200 响应就说明启动成功了。3.3 第一次登录和初始化配置浏览器访问http://服务器IP:9000不要加/sonar路径除非你在 compose 里配置了SONAR_WEB_CONTEXT。默认管理员账号是admin密码也是admin。9.9 版本第一次登录会要求修改密码改成管理员的强密码后保存。登录后建议按这个顺序做初始化创建管理员 Token。点击右上角头像选择 “My Account”再进 “Security”生成一个 Token。这个 Token 相当于扫描器的认证凭证后面跑sonar-scanner或者 Maven 插件时要用到。Token 只有生成时显示一次建议复制保存到本地密码管理器。配置项目的质量配置文件。如果你的项目主要是 Java进入 Administration 后在 Quality Profiles 里把 Java 的默认规则集激活。社区版自带 Sonar way 规则集一般不需要手动调整。确认系统日志没有异常。在 Administration 的 System 页面可以看到各组件状态正常情况全是绿色。3.4 创建项目并完成第一次真实扫描初始化完成后我建议立刻拿一个真实项目跑完整流程验证服务端和扫描器链路是通的。这里用 Java 的 Maven 项目举例。在 SonarQube 页面点击 “Create Project”填项目名称和项目标识。项目标识Project Key是唯一标识例如my-service。创建完成后选择 “Locally”页面会提示你用哪种方式执行扫描。如果你用 Maven 项目项目所在目录执行mvn clean verify sonar:sonar \ -Dsonar.projectKeymy-service \ -Dsonar.host.urlhttp://服务器IP:9000 \ -Dsonar.login刚才创建的Token第一次执行会比较慢因为 Maven 需要下载 sonar-maven-plugin 以及相关的分析器。扫描完成后日志会输出结果INFO: ANALYSIS SUCCESS回到 SonarQube 页面刷新项目就能看到代码分析结果Bug、Vulnerabilities、Code Smells、Coverage、Duplications 等指标全部展示在面板上。这个瞬间你会直观明白 SonarQube 这个代码质量分析平台到底在干什么。到这里部署和服务端到扫描端的链路已经全部打通接下来是汉化。4. 汉化操作让整个平台说中文4.1 中文语言包的正确获取方式SonarQube 官方没有内置中文需要安装社区维护的中文语言包插件。名气最大的插件是sonar-l10n-zh作者是社区志愿者。获取方式有两个在 SonarQube 管理后台的 Marketplace 里搜索 “Chinese Pack” 在线安装或者从官方仓库的 Release 页面手动下载 jar 文件。我在生产环境部署时推荐第二种方式。原因很简单在线安装依赖服务器能访问外网插件仓库很多内网环境的服务器根本连不上。而且手动下载 jar 可以根据 SonarQube 版本精确选择对应插件版本避免装错。最关键的一点插件版本必须和 SonarQube 服务端版本匹配。官方仓库的 Release 版本命名是sonar-l10n-zh-plugin-9.x.jar9.9 LTS 就选 9.x 系列10.x 版本就选 10.x 系列。你去网上搜汉化包可能会搜到一些来源不明的聚合包我劝你别用。第三方魔改包可能植入了恶意逻辑同时也可能因为版本不匹配直接导致插件加载失败。下表是常见的版本对应关系复制到你的笔记里SonarQube 版本汉化插件版本9.6 ~ 9.9.xsonar-l10n-zh-plugin-9.x.jar10.0 ~ 10.6sonar-l10n-zh-plugin-10.x.jar8.9 LTSsonar-l10n-zh-plugin-8.9.jar4.2 插件安装与重启验证拿到 jar 文件后安装过程只需要两步把 jar 放进插件目录重启容器。Docker 环境下的插件目录是容器内的/opt/sonarqube/extensions/plugins。我在 compose 文件里挂了sonar_extensions这个卷也就是说容器重启后插件文件不会丢。传文件有两种方式。第一种是直接复制进容器docker cp sonar-l10n-zh-plugin-9.9.jar sonarqube:/opt/sonarqube/extensions/plugins/ docker restart sonarqube第二种是把插件目录从卷里拿出来放到宿主机挂载。这种方式在需要经常更换插件时更灵活。先找到卷的挂载信息docker inspect sonarqube --format{{range .Mounts}}{{.Source}}{{end}}然后把 jar 放到宿主机对应的 SonarQube extensions 目录里再重启容器。重启后稍等一两分钟等容器完成初始化。再刷新浏览器页面正常情况下整个界面就变成中文了。包括项目列表、质量配置、规则详情、问题面板里的各项标签全部汉化。这里有一个很多人不知道的细节SonarQube 的语言偏好是用户级的。也就是说即使管理员装了中文语言包不同用户登录时还可能看到英文。解决方法是在个人账号设置里切换语言。点击右上角头像进入 “My Account”找 “Language” 选项选择 “Chinese (zh-CN)”保存即可。4.3 汉化不生效的五个排查方向汉化装完但界面没变化是出现频率最高的求助问题。我总结过五个排查方向按顺序检查能快速定位。第一插件是否真的加载成功。进入 Administration - Marketplace - Installed如果插件列表里没有 “Chinese Pack”说明 jar 没放对目录或者没加载。再查看日志文件logs/sonar.log搜索Chinese或者l10n看是否有加载成功的记录。第二浏览器缓存。SonarQube 前端资源会做缓存装完插件后页面可能还是旧版本。强制刷新CtrlF5或开一个无痕窗口验证。第三是否每个用户都做了语言设置。上面说过语言偏好是用户级的。管理员设置了中文不代表普通用户也自动是中文。让用户在自己的账号设置里切换。第四插件和服务端版本不匹配。这是最隐蔽的情况。插件加载成功界面却还是英文多半是 jar 版本对应的语言包不兼容当前服务端版本。检查 jar 文件名里的版本号和服务端版本比对。以 9.9.3 为例jar 应该是 9.x 系列不能用 10.x 的包。第五插件 jar 损坏。下载过程中断或文件被压缩软件破坏会导致插件加载失败。重新下载校验文件大小是否和 Release 页面一致。4.4 IDE 端 SonarLint 的中文体验平台汉化完成之后团队成员常用的 IDE 插件 SonarLint 会自动连接 SonarQube 服务端。这里有一个概念需要厘清IDE 插件的菜单文字是跟着 IDE 语言包的比如 VSCode 装中文插件后菜单是中文IntelliJ 同理。SonarLint 插件本身的操作界面不一定全中文但它连接 SonarQube 服务端后从服务端拉取的规则名称、问题描述会自动按服务端语言返回。所以平台装好中文包后你在 IDE 里看到的 SonarLint 提示信息大概率是以中文为主。这也就是为什么很多团队把 “SonarQube 汉化” 当成一个整体优化方案平台汉化只是第一步IDE 端配合设置后从代码编写到服务端扫描整条链路都会变成中文体验。5. 常见问题排查部署中踩过的坑5.1 vm.max_map_count 引发容器反复重启现象docker compose up -d后SonarQube 容器状态一直在 “restarting”日志里出现bootstrap checks failed。原因Elasticsearch 需要宿主机虚拟内存映射数量上限默认 65530 不够。解决sudo sysctl -w vm.max_map_count524288 echo vm.max_map_count524288 | sudo tee -a /etc/sysctl.conf docker restart sonarqube这里我强调过不要用SONAR_ES_BOOTSTRAP_CHECKS_DISABLEtrue跳过检查。跳过之后 ES 虽然没有启动失败但运行中可能因为内存映射不足而崩溃这类问题更难排查。5.2 数据库认证失败或者版本不匹配现象SonarQube 日志中出现PSQLException: FATAL: password authentication failed for user sonar。原因主要有两个。一是 compose 文件里POSTGRES_*变量和SONAR_JDBC_*变量不一致二是 PostgreSQL 容器初始化时用了旧的环境变量把数据库删了重建。解决确认四个变量值全部一致。如果数据库卷是之前用其他密码初始化过的需要清掉重建docker compose down -v docker compose up -d注意-v会把所有命名卷删除包括 SonarQube 的数据。如果已经有历史扫描结果删库前要谨慎操作。5.3 中文语言包装好界面仍然是英文现象插件显示已安装但页面还是英文。解决先把第一个用户的语言设置检查一遍然后确认插件版本对应最后看日志里插件有没有实际加载。这个问题有个很隐蔽的点SonarQube 10.x 版本在插件加载机制上有调整有的浏览器缓存了旧版静态资源需要强制刷新。5.4 Elasticsearch 内存不够导致 SonarQube 反复退出现象服务器内存明明有 8G但容器运行一段时间后自动退出日志里出现unable to allocate memory或 GC overhead。原因Docker 默认不限制容器内存JVM 和 Elasticsearch 在容器里同时吃内存一旦超过宿主机可分配量进程会被 OOM Killer 杀掉。解决限制 JVM 堆内存。在 compose 文件的sonarqube服务里加环境变量environment: SONARQUBE_CE_JAVA_OPTS: -Xmx1g -Xms512m -XX:MaxMetaspaceSize512m SONARQUBE_WEB_JAVA_OPTS: -Xmx1g -Xms512m -XX:MaxMetaspaceSize512m同时给容器加内存上限mem_limit: 4g这套配置在 4G 内存的服务器上实测稳定单项目扫描完全没有问题。5.5 插件离线导入后提示不兼容现象通过 Marketplace 上传 jar提示plugin X is incompatible with this version of SonarQube。原因插件元数据里的sonar.plugin.api.version和目标 SonarQube 版本不一致。这种情况多发生在从网上下载了旧版本插件或者来源不明的包。解决去官方仓库 Release 页面重新下载严格按版本对应表选择。如果确实找不到匹配版本考虑升级 SonarQube 服务端到插件支持的版本但升级前务必备份数据卷。5.6 端口占用检查现象Compose 启动不报错但网页无法访问。原因9000 已经被其他进程占用容器端口映射冲突。执行docker ps看容器状态是否 Up。再用ss -lntp | grep 9000检查端口。如果被占用改 compose 的端口映射为9001:9000。6. 汉化完成后的落地建议把质量平台用起来6.1 把 SonarQube 扫描接入流水线部署完成只是第一步真正产生价值的是让每个项目的每次提交都自动跑扫描。以一次典型的 Git 提交为例团队里最基础的落地方式是在 CI 脚本中加入 SonarQube Scanner 步骤。Jenkins 流水线的关键片段stage(SonarQube Analysis) { steps { withSonarQubeEnv(SonarQube) { sh mvn clean verify sonar:sonar -Dsonar.projectKeymy-service } } }GitLab CI 的.gitlab-ci.yml关键片段sonarqube-check: stage: test script: - mvn clean verify sonar:sonar -Dsonar.projectKeymy-service -Dsonar.host.url$SONAR_HOST_URL -Dsonar.token$SONAR_TOKEN扫描命令本身很简单关键是把 Token 和服务器地址通过环境变量注入不要把密钥写死在代码仓库里。接入 CI 以后每次 MR 触发的流水线都会自动分析代码分析结果直接关联到 MR 页面。提交代码的人可以在一小时内看到问题清单而不是等到代码评审时才被人指出。6.2 质量门禁怎么配置才有实际效果质量门禁是 SonarQube 真正发挥强制约束力的地方。如果扫描结果只是给团队看那和质量报告工具没区别。配置了门禁之后指标不达标就说明扫描不过关整个合并流程被阻断质量问题才会真正被重视。我会为 Java 后端团队这样配置门禁指标门槛值说明新增代码 Bug0新代码不允许引入 Bug新增代码安全漏洞0高危漏洞直接阻断新增代码覆盖率 80%核心服务要求边缘服务可放宽到 70%重复代码密度 3%超过 3% 必须重构圈复杂度 15超过则要求拆方法新增单元测试数 30小步提交必须有测试配套配置位置在 Quality Gates 页面默认的 Sonar way 是一个不错的起点你可以在它的基础上复制一份针对自己团队的技术栈调整阈值。需要提醒的是门禁不是越严越好。刚开始可以把覆盖率要求设为 60%跑一段时间让团队适应再逐步收紧到 80%。如果一上来就要求 80%团队会花大量时间写测试而不是理解质量问题本身效果反而不好。6.3 从历史存量代码到增量控制的演进路线搭好平台之后最先要面对的现实是存量代码问题一大堆门禁一亮红灯整个团队都傻眼。这种时候我的经验是不要试图一次性清零存量问题先把新增代码控制住。SonarQube 的项目面板天然区分了 “新增代码” 和 “存量代码”。把质量门禁只卡在新代码上存量问题单独建任务池每周挑一类问题修复。这样团队的压力不会爆炸平台的价值也能在第一个月就体现出来新提交不会引入新的坏味道存量问题逐步减少。我在实际操作中的体会是汉化做完之后团队成员使用平台的意愿会明显提升。中文界面降低了一部分同事的使用门槛至少他们能直接看懂 “提升了多少覆盖率” 而不是看到一个英文面板发懵。平台部署只是开始真正改变研发习惯的是后续的质量门禁和自动化流水线。别急着把所有规则都打开先跑通一条主流程再慢慢加指标这样整个平台才能在团队里稳扎稳打地落地。最后再分享一个小技巧SonarQube 数据卷记得定期备份。用一个简单的定时任务晚上把数据目录打成 tar 包上传到备份服务器别等到数据丢失了才想起备份这件事。我见过太多团队把质量平台搭得漂漂亮亮结果一次服务器迁移丢了全部历史分析数据项目趋势线一夜回到解放前。
返回列表