一、通用优化项
1.缓存错误
问题:
- 原配置缓存了
**/target/。这是构建产物,不仅体积大导致上传/下载慢,而且会导致 Maven 不重新编译代码,可能引发脏构建。
缺失:
- 没有缓存 Maven 依赖库 (
.m2/repository) 。这意味着每次流水线运行,都要从互联网重新下载几百 MB 的 jar 包,这是最耗时的步骤。
cache:
paths:
- "**/target/"
优化建议:
cache:
paths:
- .m2/repository/ # 缓存 Maven 依赖,这是提速的关键
- .sonar/cache/ # 缓存 Sonar 插件
2.任务冗余与 Artifacts 优化
2.1任务冗余
问题:
build和sonarqube分成了两个阶段。(应该将能整合的阶段合并,避免不必要的传输)build阶段打包后,将巨大的target目录上传到 GitLab 服务器。sonarqube阶段再下载这个巨大的target目录,启动一个新的容器,重新配置环境。
优化:
- SonarQube 扫描本身就需要编译类。将构建(Build)和扫描(Sonar)合并为一个任务,既省去了上传/下载产物的时间,也省去了启动第二个 Docker 容器的时间。
# 一条命令完成:清理 -> 编译 -> 测试 -> 扫描
# -Dmaven.test.failure.ignore=false 确保单元测试失败会中断流水线
- mvn clean compile test sonar:sonar -Dsonar.projectKey=test -Dsonar.host.url=http://172.168.20.10:9000/ -Dsonar.login=test --no-snapshot-updates
<<: *common_rules
第一部分:命令详解(可忽略)
-
clean(清理) :- 动作:删除项目根目录下的
target文件夹。 - 目的:确保本次构建是“全新”的,防止上一次构建留下的旧
.class文件干扰本次结果(避免“脏构建”)。
- 动作:删除项目根目录下的
-
compile(编译) :- 动作:把
src/main/java下的源代码编译成.class字节码文件。 - 目的:Java 代码必须编译后才能运行,SonarQube 也需要分析编译后的字节码来提高准确度。
- 动作:把
-
test(单元测试) :-
动作:编译并运行
src/test/java下的单元测试用例。 -
目的:
- 确保新写的代码没有把旧功能改坏。
- 关键点:运行测试会生成“覆盖率报告”(jacoco.exec),SonarQube 需要读取这个报告来告诉你“代码覆盖率”是多少。
-
-
sonar:sonar(扫描) :- 动作:启动 SonarScanner 插件。
- 目的:它会读取源代码、读取第2步生成的
.class文件、读取第3步生成的测试报告,进行静态代码分析(找 Bug、漏洞、代码异味),最后把结果打包上传给 SonarQube 服务器。
第二部分:配置参数(-D 传参)
-
-Dsonar.projectKey=test- 含义:项目唯一标识。
- 解释:在 SonarQube 网页端,每个项目都有一个唯一的 ID。你需要把它改成你项目真实的 Key,否则 SonarQube 会认为这是一个新项目或者找不到项目。
-
-Dsonar.host.url=http://172.168.20.10:9000/- 含义:服务器地址。
- 解释:告诉插件把扫描结果发送给哪台服务器。请确保流水线运行的容器能访问通这个内网 IP。
-
-Dsonar.login=test- 含义:身份认证 Token。
- 解释:这是登录 SonarQube 的“钥匙”。
- 安全建议:直接把 Token 写在代码里(硬编码)是不安全的。通常建议在 GitLab CI/CD 的设置里配置一个变量
$SONAR_TOKEN,然后这里写成-Dsonar.login=$SONAR_TOKEN。
-
--no-snapshot-updates-
含义:不要检查快照更新。
-
解释:如果你的项目依赖了一些公司内部开发的 SNAPSHOT 版本 jar 包(比如
common-utils-1.0-SNAPSHOT)。- 不加这个参数:Maven 默认每天或者每次构建都会去私服( Nexus/Artifactory )询问:“在这个 jar 包有没有新版本呀?”这很浪费时间。
- 加上这个参数:告诉 Maven:“别问了,本地有啥就用啥,除非我强制更新”。这能显著加快构建速度。
-
2.2Artifacts存储优化
问题:
- 保留整个
target目录,非常不建议这样做,除非你有特殊需求 - 未自动清理Artifacts产物,导致存储膨胀,占用大量硬盘空间。
优化:
- 新增
expire_in: 1 week参数(构建频繁的可以配置1 day)
artifacts:
paths:
- "**/target/*.jar" # 只保留 jar 包
# - "**/target/*.war" # 如果是 war 包项目
expire_in: 1 week # 建议稍微久一点,方便一周内回滚
3.克隆优化
问题:
- 有些项目历史版本众多且文件较大,导致拉取代码非常慢
- 除了 SonarQube 需要完整的 git 历史外,其他步骤不需要。
优化:
- 定义全局变量默认浅克隆,加快拉取速度
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
# 定义全局变量和锚点
variables:
# 默认浅克隆,加快拉取速度(Sonar 任务中会覆盖此设置)
GIT_DEPTH: "1"
二、特殊优化项
1.缓存策略优化
缓存策略三种写法:
写法 A:全局共享(最推荐用于 Maven 依赖)
cache:
key: "maven-global-cache" # 共享缓存池的名称
paths:
- .m2/repository/
- 优点:速度最快。
dev分支刚下载的包,master分支立马能用。节省磁盘空间。 - 缺点:如果有两个流水线同时运行并试图写入缓存,可能会冲突(但在 Maven 下载依赖场景下,通常不是大问题)。
写法 B:按分支隔离(最推荐用于 node_modules 或构建产物)
- 基于分支
cache:
key: "$CI_COMMIT_REF_SLUG" # 这是一个变量,代表当前分支名(如 master, dev)
paths:
- node_modules/
-
含义:
master分支有自己名为master的箱子。dev分支有自己名为dev的箱子。
-
优点:绝对安全,分支之间互不干扰。
-
缺点:很慢。当你新建一个
feature-login分支时,因为它是全新的 key,它没有任何缓存,必须从头下载所有依赖。
写法 C:基于分支文件(智能缓存)
cache:
key:
files:
- pom.xml # 只有当 pom.xml 文件内容变了,才生成新的 key
paths:
- .m2/repository/
- 含义:只要
pom.xml没变,大家就一直用同一个缓存。一旦你修改了依赖,系统会自动生成一个新的干净缓存。
总结与建议
针对 Java/Maven 项目:
1.推荐保持的配置(写法 A) :
key: "maven-sonar-cache"
理由:Java 的 jar 包是跨分支通用的。spring-boot-starter-web 在 dev 分支和 master 分支是一模一样的东西。没必要隔离,大家共用一个库,下载一次,全员加速。
2.特性功能:
如果你使用的是 写法 B(基于分支),GitLab 确实有一个高级特性叫 fallback_keys,可以实现“如果 feature 分支没缓存,就去借用 master 的”。
3.前端构建&扫描优化
核心区别对比
| 差异点 | 后端 (Java) | 前端 (Vue/React) |
|---|---|---|
| 基础镜像 | maven:3.6-jdk-11 | node:16 (或 14/18) |
| 构建工具 | mvn (Maven) | npm 或 yarn |
| 依赖缓存 | .m2/repository | node_modules |
| 编译命令 | mvn compile | npm run build |
| 产物形式 | .jar 包 | dist/ 文件夹 (HTML/CSS/JS) |
| 扫描工具 | Maven 的 Sonar 插件 | sonar-scanner (需要独立安装) |
部分示例:
# --- 前端核心任务 ---
frontend-job:
stage: build-and-scan
#注意:请根据你项目的实际 node 版本修改,推荐 node:14 或 node:16
image: node:16
tags:
- edfs
- api
- prod
cache:
key: "frontend-node-modules" # 全局共享缓存
paths:
- node_modules/ # 缓存依赖包 (提速核心)
- .npm/ # 缓存 npm 缓存数据
- .sonar/cache/ # 缓存 sonar 插件
script:
- node -v
- npm -v
# 1. 设置淘宝/腾讯镜像源 (极大提升 npm install 速度)
- npm config set registry https://registry.npmmirror.com
# 2. 安装依赖 (如果缓存里有,这一步会飞快)
- npm install
# 3. 编译打包
- npm run build
# 4. 安装 Sonar 扫描器并执行扫描
# 前端不像 Maven 自带插件,需要临时安装一个扫描器工具
- npm install -g sonarqube-scanner
- sonar-scanner
-Dsonar.projectKey=前端项目的Key_注意修改
-Dsonar.host.url=http://172.6.10.9:9000/
-Dsonar.login=9930
-Dsonar.sources=src
-Dsonar.exclusions=**/node_modules/**,**/dist/**
<<: *common_rules
artifacts:
paths:
- dist/ # 前端通常保留 dist 目录用于部署 Nginx
expire_in: 1 day
前端扫描必须加这个参数: -Dsonar.exclusions=/node_modules/,/dist/ 如果不加,SonarQube 会去扫描 node_modules 里成千上万个第三方库的文件,导致:
- 扫描时间无限拉长(可能跑 1 个小时)。
- 报告里出现几万个不属于你的 Bug。
- 服务器卡死。