导读:本期聚焦于梧桐创作的《如何用 GitLab CI 为 Spring Boot 项目搭建自动化 CI/CD 流水线?》,敬请观看详情。手动打包部署 Spring Boot 应用容易因为环境差异出现构建失败或发布遗漏,引入 GitLab CI 后这些步骤可以被固化到流水线中。本文围绕 Spring Boot 项目从代码提交到镜像推送、远程部署的完整链路,梳理 .gitlab-ci.yml 的写法、Runner 配置要点以及多阶段构建的拆分方式。你会看到如何利用缓存加速 Maven 依赖下载,如何在测试阶段生成报告,以及如何通过 rules 和 tags 控制流水线触发条件。文章还对比了单阶段与多阶段流水线在构建耗时和可维护性上的差异,并给出一个可直接参考的完整配置。读完可以理解 GitLab CI 在 Spring Boot 项目中的落地路径,避免常见的权限、缓存和镜像仓库配置坑。

Spring Boot 项目从代码提交到上线通常要经历编译、测试、打包、构建镜像、推送仓库、服务器拉取并重启等多个环节。如果每次合并到主分支后都靠人工执行这些步骤,不仅耗时,还容易因为环境不一致或操作遗漏导致发布失败。借助 GitLab CI 可以把这些流程写进版本库,让每次推送或合并请求自动触发检查、构建和部署。下面从 Runner 准备、流水线文件编写、镜像瘦身和自动部署几个角度展开。

如何用 GitLab CI 为 Spring Boot 项目搭建自动化 CI/CD 流水线?

一、准备 GitLab Runner 并选择合适的执行器

GitLab Runner 是真正执行流水线任务的组件,需要单独安装并注册到 GitLab。注册时可以根据部署环境选择 executor,如果 Runner 跑在 Linux 服务器上且只负责构建 Java 项目,用 shell 执行器可以直接使用宿主机上的 JDK 和 Maven,配置简单,但环境容易受主机已有工具影响。如果希望每次任务都在干净、可复现的环境中运行,更推荐 docker 执行器,通过镜像声明构建环境,避免版本冲突。

以 Docker executor 为例,安装 Runner 后执行 gitlab-runner register,填写 GitLab 地址、注册 token,执行器选择 docker,默认镜像指定 maven:3.9-eclipse-temurin-17。注册完成后可以在 /etc/gitlab-runner/config.toml 中看到对应的 [[runners]] 配置。给 Runner 设置 tags 很关键,例如 spring-boot,这样流水线里的任务可以通过 tags 精准选中具备 Java 构建能力的 Runner,避免任务被分配到没有 JDK 或 Docker 的环境。

如果项目需要构建并推送 Docker 镜像,Runner 还必须能访问 Docker 守护进程。常见做法有两种:一种是启用 Docker-in-Docker 服务,在流水线里声明 docker:24-dind,隔离性更好;另一种是直接挂载宿主机的 /var/run/docker.sock,构建速度更快,但安全性略弱,适合内部可信网络。对于公开项目或多人共享 Runner 的场景,建议优先使用 DinD,减少宿主机被越权访问的风险。

二、拆分流水线阶段与缓存 Maven 依赖

.gitlab-ci.yml 是 GitLab CI 的核心配置文件。针对 Spring Boot 项目,可以按 test、package、docker-build、deploy 四个 stage 来组织。测试阶段执行单元测试并收集 JUnit 报告,打包阶段生成可执行 jar,镜像构建阶段基于 jar 制作 Docker 镜像,部署阶段推送到目标服务器。这样拆分后,如果单元测试失败,后面的打包和部署不会执行,能快速暴露回归问题。

Maven 依赖下载通常是 CI 流程里最耗时的部分。默认情况下 Docker executor 每次任务都会创建新容器,本地仓库不会保留,导致每次都重新下载全部依赖。解决办法是在流水线中声明 cache,把 .m2/repository 目录缓存起来。GitLab 会在下一次任务时恢复该目录,Maven 检测到已有依赖就不会重复拉取。缓存键可以绑定 pom.xml 的 hash 或 CI_COMMIT_REF_SLUG,防止不同分支使用错误缓存。

下面是一个去掉部署阶段的简化示例,包含测试、打包和镜像构建:

stages:
  - test
  - package
  - docker-build

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  DOCKER_IMAGE: registry.ipipp.com/myapp

cache:
  paths:
    - .m2/repository

test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test
  artifacts:
    reports:
      junit:
        - target/surefire-reports/TEST-*.xml

package:
  stage: package
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn package -DskipTests
  artifacts:
    paths:
      - target/*.jar

docker-build:
  stage: docker-build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $DOCKER_IMAGE:$CI_COMMIT_SHORT_SHA

这个配置里 cache 负责加快依赖解析,artifacts 则负责在不同阶段之间传递文件。测试阶段产生的 JUnit 报告会显示在 GitLab 的合并请求页面上,打包阶段的 jar 产物会被 docker-build 任务下载并使用。每个任务的运行环境都是独立容器,需要共享的变量统一放在 variables 全局区,例如镜像仓库地址。

实际执行时,如果测试用例失败,test 任务会以非零状态码退出,GitLab 会标记流水线失败,后续的 package 和 docker-build 都不会触发。这种快速失败机制对 Spring Boot 项目很有价值,诸如服务层逻辑回归、依赖注入缺失、配置错误等问题,往往在测试阶段就能被发现,不需要等到部署到服务器之后再回滚。

三、用多阶段 Docker 构建减小镜像体积

Spring Boot 可执行 jar 已经内置了 Tomcat,但 Docker 镜像的构建方式不同,最终体积和构建速度差别很大。如果直接使用 Maven 镜像作为最终运行镜像,会把完整的 JDK 与编译工具一起打进镜像,体积可能超过 700MB,传输和启动都更慢。多阶段构建可以把编译和运行拆开,第一阶段用 Maven 镜像产出 jar,第二阶段只使用 JRE 运行镜像,复制产物并启动。

下面给出一个适合 Spring Boot 3.x 的 Dockerfile:

FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]

第一阶段先复制 pom.xml 并执行 mvn dependency:go-offline,这样能提前拉取依赖,后续源码变动不会重复下载。第二阶段选择 eclipse-temurin:17-jre,只带运行环境,不再包含 javac 等开发工具。最终镜像通常可以降到 200MB 以下,同时减少攻击面,更适合生产环境发布。

如果构建时发现通配符匹配到多个 jar 文件导致 COPY 失败,可以在 Maven 中固定最终文件名。在 pom.xml 里给 spring-boot-maven-plugin 配置 finalName,例如 app,这样打包产物就是 app.jar,Dockerfile 里可以直接写 COPY --from=build /app/target/app.jar app.jar,避免歧义。对于追求更小体积的团队,可以进一步评估 GraalVM Native Image,但需要额外处理反射配置和构建时间,不适合所有项目。

四、自动部署与触发策略控制

镜像推送到仓库后,部署阶段需要把新版本拉取到目标服务器并重启容器。可以在 GitLab CI 中使用 SSH 命令连接远程主机,依次执行 docker pull、docker stop、docker rm 和 docker run。SSH 私钥应保存在项目的 CI/CD 变量中,并开启 Protected 和 Masked,绝对不要提交到版本库。部署脚本尽量拆成多个独立命令,避免在单引号里堆叠复杂逻辑,便于阅读和排错。

下面是一个部署阶段的示例:

deploy:
  stage: deploy
  script:
    - ssh $SSH_USER@$SSH_HOST "docker pull $DOCKER_IMAGE:$CI_COMMIT_SHORT_SHA"
    - ssh $SSH_USER@$SSH_HOST "docker stop app || true"
    - ssh $SSH_USER@$SSH_HOST "docker rm app || true"
    - ssh $SSH_USER@$SSH_HOST "docker run -d --name app -p 8080:8080 $DOCKER_IMAGE:$CI_COMMIT_SHORT_SHA"
  only:
    - main

这里 DOCKER_IMAGE、SSH_USER 和 SSH_HOST 都来自 GitLab 的 CI/CD 变量,不会暴露在配置文件里。镜像仓库如果需要登录,建议使用 docker login 配合密码输入重定向,并且把令牌类型的密码也放到变量里,避免明文打印到流水线日志。部署完成后可以加一个健康检查步骤,例如休眠几秒后请求 /actuator/health,接口返回非 200 时让流水线失败,方便及时回滚。

不是所有提交都需要触发完整流水线。日常开发分支往往只执行测试和打包,合并到 main 分支后才构建并部署。通过 rules 可以对任务做细粒度控制:

deploy:
  stage: deploy
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: always
    - when: manual
  script:
    - echo "Deploying to production"

这个配置表示只有在 main 分支提交时自动执行部署,其他分支需要手动触发。预发布环境也可以用 when: manual 实现人工确认,减少误操作。流水线跑通后,日常提交流程变为:开发推送到特性分支,自动运行测试和打包;合并到 main 后触发镜像构建和部署。应用更新频率提高后,建议把敏感配置从 application.yml 迁移到环境变量或配置中心,保证同一镜像在不同环境中的行为一致。

Spring BootGitLab CICI/CD修改时间:2026-09-23 18:52:23

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0923/61009.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。