gitlab构建&扫描优化

32 阅读6分钟

一、通用优化项

1.缓存错误

问题

  • 原配置缓存了 **/target/。这是构建产物,不仅体积大导致上传/下载慢,而且会导致 Maven 不重新编译代码,可能引发脏构建。

缺失

  • 没有缓存 Maven 依赖库 ( .m2/repository ) 。这意味着每次流水线运行,都要从互联网重新下载几百 MB 的 jar 包,这是最耗时的步骤。
  cache:
    paths:
      - "**/target/"

优化建议:

  cache:
    paths:
      - .m2/repository/  # 缓存 Maven 依赖,这是提速的关键
      - .sonar/cache/    # 缓存 Sonar 插件

2.任务冗余与 Artifacts 优化

2.1任务冗余

问题

  • buildsonarqube 分成了两个阶段。(应该将能整合的阶段合并,避免不必要的传输
  • 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
第一部分:命令详解(可忽略)
  1. clean (清理)

    1. 动作:删除项目根目录下的 target 文件夹。
    2. 目的:确保本次构建是“全新”的,防止上一次构建留下的旧 .class 文件干扰本次结果(避免“脏构建”)。
  2. compile (编译)

    1. 动作:把 src/main/java 下的源代码编译成 .class 字节码文件。
    2. 目的:Java 代码必须编译后才能运行,SonarQube 也需要分析编译后的字节码来提高准确度。
  3. test (单元测试)

    1. 动作:编译并运行 src/test/java 下的单元测试用例。

    2. 目的

      • 确保新写的代码没有把旧功能改坏。
      • 关键点:运行测试会生成“覆盖率报告”(jacoco.exec),SonarQube 需要读取这个报告来告诉你“代码覆盖率”是多少。
  4. sonar:sonar (扫描)

    1. 动作:启动 SonarScanner 插件。
    2. 目的:它会读取源代码、读取第2步生成的 .class 文件、读取第3步生成的测试报告,进行静态代码分析(找 Bug、漏洞、代码异味),最后把结果打包上传给 SonarQube 服务器。
第二部分:配置参数(-D 传参)
  1. -Dsonar.projectKey=test

    1. 含义项目唯一标识
    2. 解释:在 SonarQube 网页端,每个项目都有一个唯一的 ID。你需要把它改成你项目真实的 Key,否则 SonarQube 会认为这是一个新项目或者找不到项目。
  2. -Dsonar.host.url=http://172.168.20.10:9000/

    1. 含义服务器地址
    2. 解释:告诉插件把扫描结果发送给哪台服务器。请确保流水线运行的容器能访问通这个内网 IP。
  3. -Dsonar.login=test

    1. 含义身份认证 Token
    2. 解释:这是登录 SonarQube 的“钥匙”。
    3. 安全建议:直接把 Token 写在代码里(硬编码)是不安全的。通常建议在 GitLab CI/CD 的设置里配置一个变量 $SONAR_TOKEN,然后这里写成 -Dsonar.login=$SONAR_TOKEN
  4. --no-snapshot-updates

    1. 含义不要检查快照更新

    2. 解释:如果你的项目依赖了一些公司内部开发的 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-11node:16 (或 14/18)
构建工具mvn (Maven)npm 或 yarn
依赖缓存.m2/repositorynode_modules
编译命令mvn compilenpm 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. 扫描时间无限拉长(可能跑 1 个小时)。
  2. 报告里出现几万个不属于你的 Bug。
  3. 服务器卡死。