Git-7.添加执行管道CI-CD

什么是CICD

CI/CD 是由 CI (Continuous Integration 持续整合) 以及 CD (Continuous Delivery/Deployment 持续交付/部署) 两个字所组成,其核心概念是持续集成、持续交付和持续部署。
alt text
CI/CD 可让持续自动化和持续监控贯穿于应用的整个生命周期(从集成和测试阶段,到交付和部署)。

CI/CD的产生

软件开发的早期,软体的更新都是一次大版本的更新。对于开发者来说,是一次把完整的功能都做完、测试完,才会上线交付给使用者。
但是近些年,软件开发的模式在发生转变,尤其是自 2001 年,软体开发业界有 17 位资深专家,齐聚一堂发布了敏捷宣言(The Agile Manifesto) 倡议,进而衍伸出后来的敏捷开发,而 CI/CD 也可说是这之后出来的词汇。

敏捷宣言十二项原则

  1. 我们最优先的任务,是透过及早并持续地交付有价值的软体来满足客户需求。
  2. 竭诚欢迎改变需求,甚至已处开发后期亦然。 敏捷流程掌控变更,以维护客户的竞争优势。
  3. 经常交付可用的软体, 频率可以从数周到数个月, 以较短时间间隔为佳。
  4. 业务人员与开发者必须在专案全程中天天一起工作。
  5. 以积极的个人来建构专案, 给予他们所需的环境与支援, 并信任他们可以完成工作。
  6. 面对面的沟通是传递资讯给开发团队及团队成员之间效率最高且效果最佳的方法。
  7. 可用的软体是最主要的进度量测方法。
  8. 敏捷程序提倡可持续的开发。赞助者、开发者及使用者应当能不断地维持稳定的步调。
  9. 持续追求优越的技术与优良的设计, 以强化敏捷性。
  10. 精简 ── 或最大化未完成工作量之技艺 ── 是不可或缺的。
  11. 最佳的架构、需求与设计皆来自于能自我组织的团队。
  12. 团队定期自省如何更有效率,并据之适当地调整与修正自己的行为。
    在这个宣言下,软体开发不再是一次完成一整包后才交付,而是“及早”交付,且开发者需要持续接收回馈,根据持续演进与变化的需求持续地开发。在这个概念下,我们需要一个能够落地的具体方式,而 CI/CD 正是落地的手段之一。

CI 持续集成(Continuous Integration)

协同开发是目前主流的开发方式,也就是多位开发人员可以同时处理同一个应用的不同模块或者功能。
因为涉及到多人开发,所以不可避免的需要在开发结束后进行整体代码的即成合并,而随着开发单元增加,代码合并面临的代码冲突和环境不兼容问题会急剧增加。持续集成(CI)可以帮助开发者在完成推送后,自动进行整合,可以更早的返现冲突,进而更高效的发现和解决冲突。
现代的 CI 工具,会在代码推到远端分支后,由 CI 的伺服器完整跑过整个 CI 流程。而现代软体开发团队的 CI 流程,做的不仅仅是确保代码合并没有冲突。而是可以通过配置实现包含格式化检查、静态检查、自动化测试(单元测试和集成测试)等相关发版前的测试工作。

  • 格式化比如代码的缩进、空行、注释等等校验;
  • 静态检查可以设计团队内部的一些规则和要求,比如代码风格、代码质量、代码规范等;
  • 自动化测试,包含单元测试、整合测试、E2E 测试来确保准确性;
  • 编译与构建,确保编译和构建的顺利,是CI过程中最重要的环节,部分团队还会针对安全、效能进行监控。
    CI 最核心的作用,是透过自动化的方式,让工程师可以在把代码推到远端分支后,不用自己手动,就能完成这些重要的检测,并完成代码的整合。

CD 持续交付/部署(Continuous Delivery/Deployment)

CI 在完成了构建、单元测试和集成测试这些自动化流程后,持续交付可以自动把已验证的代码推送至仓库默认分支、部署至产品环境。 持续交付旨在建立一个可随时将开发环境的功能部署到生产环境的代码库。
对于一个完整、成熟的 CI/CD 管道来说,最后的阶段是持续部署。持续部署是持续交付的延伸,持续部署意味着开发人员对应用的改动,在编写完成后的几分钟内就能部署到生产环境及时生效(前提是它通过了自动化测试)。
总而言之,这些 CI/CD 的关联步骤,都极大地降低了应用的部署风险。
不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期工作量还是很大的。

几个概念

  • 持续集成(Continuous Integration):频繁地(一天多次)将代码集成到主干。让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。“持续集成并不能消除 Bug,而是让它们非常容易发现和改正。”
  • 持续交付(Continuous Delivery):频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。
  • 持续部署(continuous Deployment):代码通过评审以后,自动部署到生产环境。是持续部署是持续交付的下一步,持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。

如何实现CICD

持续集成工具

[Jenkins](https://www.jenkins.io/)
[GitLab CI](https://docs.gitlab.com/ci/)
[GitHub Actions](./Git-10.GitHub-Actions-CI-CD.md)
TeamCity
Travis CI
Bamboo
CircleCI

GitLab CI 工作逻辑框架

文档对齐版本(2026-07 更新)

组件 参考版本 官方文档
GitLab 19.2 Release Notes
GitLab Runner 19.2.0 Install
.gitlab-ci.yml 语法 18.6+ YAML 参考

语法变更说明

  • only / except:自 GitLab 13.0 起弃用,GitLab 19.0 已移除;本文示例统一使用 rules
  • Runner 注册:改用 Runner 认证 Token(前缀 glrt-);旧版 Registration Token 计划于 GitLab 20.0 移除
  • 同一 Pipeline 内不要混用 only/exceptrules,否则易出现重复 Pipeline 等难以排查的问题

GitLab CI/CD 是 GitLab Continuous Integration(GitLab 持续集成)的简称。GitLab 自 8.0 起内置 CI/CD,且对项目默认开启。在仓库根目录添加 .gitlab-ci.yml 并配置 Runner(运行器)后,push 或合并请求(Merge Request,MR)即可触发 Pipeline。

GitLab Runner

GitLab Runner 是一个开源项目,可以运行在 GNU / Linux,macOS 和 Windows 操作系统上。每次push的时候 GitLab CI 会根据.gitlab-ci.yml配置文件运行你流水线(Pipeline)中各个阶段的任务(Job),并将结果发送回 GitLab。GitLab Runner 是基于 Gitlab CI 的 API 进行构建的相互隔离的机器(或虚拟机)。GitLab Runner 不需要和 Gitlab 安装在同一台机器上,且考虑到 GitLab Runner 的资源消耗问题和安全问题,也不建议这两者安装在同一台机器上。
Gitlab Runner 分为三种:
共享Runner(Shared runners)
专享Runner(Specific runners)
分组Runner(Group Runners)

Pipelines

Pipelines 是分阶段(stage)执行的构建任务。如:安装依赖、运行测试、打包、部署开发服务器、部署生产服务器等流程。每一次push或者Merge Request都会触发生成一条新的Pipeline。若一次推送包含了多个提交,则管道与最后那个提交相关联,管道(pipeline)就是一个分成不同阶段(stage)的作业(job)的集合
下面是流水线示例图:

Stages

Stages 表示构建阶段,可以理解为上面所说“安装依赖”、“运行测试”等环节的流程。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:

  • 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始(当然可以在.gitlab-ci.yml文件中配置上一阶段失败时下一阶段也执行)
  • 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
  • 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败
    下面是一个流水线内的阶段任务示例图:
    Pipeline Status

Jobs

Jobs 表示构建的作业(或称之为任务),表示某个 Stage 里面执行的具体任务。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

  • 相同 Stage 中的 Jobs 无执行顺序要求,会并行执行
  • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
  • 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 也失败(可以在.gitlab-ci.yml文件中配置允许某 Job 可以失败,也算该 Stage 成功)

.gitlab-ci.yml

GitLab 中默认开启了 Gitlab CI/CD 的支持,但是要是用这个功能,我们需要告诉系统,我们需要执行什么样的pipeline,在gitlab里面,这通过 .gitlab-ci.yml 来实现。
且使用YAML文件.gitlab-ci.yml来管理项目构建配置。该文件需要存放于项目仓库的根目录(默认路径,可在 GitLab 中修改),它定义该项目的 CI/CD 如何配置。所以,我们只需要在.gitlab-ci.yml配置文件中定义流水线的各个阶段,以及各个阶段中的若干作业(任务)即可。
下面是.gitlab-ci.yml文件的一个简单的Hello World示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 定义 test 和 package 两个 Stages
stages:
- test
- package
# 定义 package 阶段的一个 job
package-job:
stage: package
script:
- echo "Hello, package-job"
- echo "I am in package stage"
# 定义 test 阶段的一个 job
test-job:
stage: test
script:
- echo "Hello, test-job"
- echo "I am in test stage"

以上配置中,用 stages 关键字来定义 Pipeline 中的各个构建阶段,然后用一些非关键字来定义 jobs。每个 job 中可以再用 stage 关键字来指定该 job 对应哪个 stage。job 里面的script关键字是每个 job 中必须要包含的,它表示每个 job 要执行的命令。

Badges

Badges(徽章)可在 Pipeline 运行中或完成后展示构建状态,嵌入 README.md 便于从仓库主页查看。GitLab 项目可在 Settings → CI/CD → Pipeline status badge 复制 Markdown 片段;也可使用 shields.io 自定义样式。

GitLab Pipeline 徽章示例(替换 <namespace>/<project> 与分支名):

1
[![pipeline status](https://gitlab.com/<namespace>/<project>/badges/main/pipeline.svg)](https://gitlab.com/<namespace>/<project>/-/commits/main)

GitLab CI 实践

如上所述,自动化 Pipeline 需要 Runner 提供执行环境,第一步是在目标机器上安装 GitLab Runner。

GitLab Runner 配置

安装 GitLab Runner

以下以 RHEL/CentOS 为例,其他平台参考 官方安装指南(文档对齐 Runner 19.2.0)。

1
2
3
4
5
6
7
8
9
10
11
12
# 添加官方 yum 源
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash

# 安装最新版 GitLab Runner(与 GitLab 主版本保持同代际,如 19.x)
sudo yum install gitlab-runner

# 查看已安装版本
gitlab-runner --version

# 离线安装:从 Release 页下载对应 rpm 后安装(示例版本号请按实际替换)
# https://gitlab.com/gitlab-org/gitlab-runner/-/releases
sudo rpm -ivh gitlab-runner-19.2.0-1.x86_64.rpm

注册 Runner(认证 Token 方式,GitLab 16.0+ 推荐)

旧版 Registration Token 注册方式已弃用。当前流程:

  1. 在 GitLab UI 创建 Runner:Settings → CI/CD → Runners → New project runner
  2. 配置标签(tags)、Executor(如 shelldockerkubernetes
  3. 创建后获得 Runner 认证 Token(前缀 glrt-
  4. 在 Runner 机器上执行注册:
1
2
3
4
5
6
sudo gitlab-runner register \
--url "https://gitlab.example.com/" \
--token "glrt-xxxxxxxxxxxxxxxxxxxx" \
--executor "shell" \
--description "my-runner" \
--tag-list "deploy,shell"

交互式注册时,在提示 Enter the runner authentication token 处粘贴 glrt- Token 即可。

段末注释:Runner 认证 Token 与旧 Registration Token 不同;同一 Token 可在多台机器注册为同一 Runner 配置的不同 manager(通过 system_id 区分)。

GitLab Runner 常用命令汇总

下面的表格中列出了一些常用的 GitLab Runner 命令,以供参考:

命令 描述
gitlab-runner run 运行一个runner服务
gitlab-runner register 注册一个新的runner
gitlab-runner start 启动服务
gitlab-runner stop 关闭服务
gitlab-runner restart 重启服务
gitlab-runner status 查看各个runner的状态
gitlab-runner unregister 注销掉某个runner
gitlab-runner list 显示所有运行着的runner
gitlab-runner verify 检查已注册的运行程序是否可以连接到GitLab,但它不验证GitLab Runner服务是否正在使用运行程序。

任务配置

任务配置的一个示例

接下来,用一个实际项目来演示 GitLab CI/CD 的配置和使用,其中主要包括:编译测试、项目打包、部署服务、Sonar手动检查、Sonar定时检查五个阶段。
下面用一个传统的 Java Web 项目(cidemo)和 Tomcat 作为示例。每次 push 或 MR 会触发 Pipeline;Sonar 手动检查通过 when: manual 触发,定时检查通过 Pipeline Schedules 触发。

敏感变量(SONAR_HOST_URLSONAR_TOKEN)请在 Settings → CI/CD → Variables 中配置,并勾选 Mask variable。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 定义 stages
stages:
- test
- install
- run
- sonar

# 全局变量;敏感项建议在 GitLab CI/CD Variables 中配置
variables:
CIDEMO_PACKAGE_DIR: '/home/gitlab-runner/packages/cidemo/'
SERVER_HOME_DIR: '/home/gitlab-runner/tomcat/cidemo-tomcat/'
MAVEN_OPTS: '-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository'

###################### 构建编译和单元测试的 job #######################
编译测试任务:
stage: test
image: maven:3.9-eclipse-temurin-17
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
cache:
key: maven-$CI_COMMIT_REF_SLUG
paths:
- .m2/repository/
script:
- mvn -B clean test

###################### Maven 安装得到 war 包的 job #######################
打包任务:
stage: install
image: maven:3.9-eclipse-temurin-17
rules:
- if: $CI_COMMIT_BRANCH == "develop" && $CI_PIPELINE_SOURCE == "push"
cache:
key: maven-$CI_COMMIT_REF_SLUG
paths:
- .m2/repository/
script:
- mvn -B install -DskipTests
- echo '准备将最新的 war 包复制到供部署使用的目录'
- rm -rf $CIDEMO_PACKAGE_DIR/*.war
- cp target/*.war $CIDEMO_PACKAGE_DIR/cidemo.war
artifacts:
paths:
- target/*.war
expire_in: 1 week

####################### 部署运行 war 包的 job #######################
部署运行任务:
stage: run
rules:
- if: $CI_COMMIT_BRANCH == "develop" && $CI_PIPELINE_SOURCE == "push"
tags:
- deploy # 匹配带 deploy 标签的 Shell Runner
script:
- echo '准备部署和运行 war 包(部署到 Tomcat)'
- cd $SERVER_HOME_DIR
- sh bin/shutdown.sh || true
- rm -rf webapps/cidemo.war webapps/cidemo
- cp $CIDEMO_PACKAGE_DIR/cidemo.war $SERVER_HOME_DIR/webapps/cidemo.war
- nohup sh ./bin/startup.sh > logs/cidemo_nohup.log 2>&1 &

###################### Sonar 手动构建的 job #######################
Sonar手动检查:
stage: sonar
image: maven:3.9-eclipse-temurin-17
rules:
- if: $CI_COMMIT_BRANCH == "develop"
when: manual
script:
- echo '准备对项目代码做 Sonar 质量检查'
- mvn -B compile org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_TOKEN

###################### Sonar 定时构建的 job #######################
Sonar定时检查:
stage: sonar
image: maven:3.9-eclipse-temurin-17
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- echo '开始定时对项目代码做 Sonar 质量检查'
- mvn -B compile org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_TOKEN

定时任务需在 GitLab Build → Pipeline schedules 中创建 Schedule,并指定目标分支(如 develop)。

GitLab CI/CD YAML 常用配置介绍

.gitlab-ci.yml 中每个 Job 以自定义名称为键,且至少包含 script(或使用 trigger 触发下游 Pipeline)。Job 名称不可与 YAML 保留关键字冲突。

Keyword Required Description
script yes Runner 执行的命令或脚本
rules 推荐 控制 Job 何时加入 Pipeline(替代 only/except,GitLab 19.0+ 已移除后者)
extends no 继承父 Job 配置(GitLab 11.3+)
include no 引入外部 YAML 或 CI/CD Component
image no Job 使用的 Docker 镜像
services no 附加 Docker 服务(如数据库)
stage no Job 所属 stage(默认 test
variables no Job 级变量
tags no 指定 Runner 标签
allow_failure no 允许 Job 失败而不阻断 Pipeline
when no rules 联用:on_successon_failurealwaysmanualdelayed
needs no 跨 stage 依赖,可 DAG 编排并提前传递 artifacts
dependencies no 指定 artifacts 来源 Job
artifacts no Job 产出文件,供后续 Job 或下载
cache no 跨 Pipeline 缓存目录
before_script / after_script no Job 前/后执行的命令
environment no 部署环境名称与 URL
coverage no 代码覆盖率正则提取
retry no 失败自动重试次数与间隔
parallel no 矩阵/并行 Job 实例数
workflow no 顶层 Pipeline 级 rules,控制是否创建整条 Pipeline
timeout no Job 超时时间

已弃用关键字(勿在新项目中使用)onlyexcepttypestage 别名)、Runner Registration Token 注册方式。详见 Deprecated keywords

接下来对其中的一些重要关键字进行补充说明。

rules(推荐)

rules 按顺序匹配,命中第一条即决定是否将 Job 加入 Pipeline。常用写法:

1
2
3
4
5
6
编译测试任务:
stage: test
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
- when: never

常见 CI_PIPELINE_SOURCE 取值:pushmerge_request_eventscheduleweb(手动)、api

与旧语法的对应关系:

旧写法(only/except) 新写法(rules)
only: [branches] - if: $CI_PIPELINE_SOURCE == "push"
only: [develop] - if: $CI_COMMIT_BRANCH == "develop"
only: [merge_requests] - if: $CI_PIPELINE_SOURCE == "merge_request_event"
only: [schedules] - if: $CI_PIPELINE_SOURCE == "schedule"
when: manual + 分支限制 rules: - if: ... when: manual

stages

stages 用来定义可以被 job 调用的 stages。stages 的规范允许有灵活的多级 pipelines。
stages中的元素顺序决定了对应job的执行顺序:

  • 相同 stage 的 job 可以平行执行。
  • 下一个 stage 的 job 会在前一个 stage 的 job 成功后开始执行。
    接下仔细看看这个例子,它包含了3个 stage:
1
2
3
4
stages:
- build
- test
- deploy
  1. 首先,所有 build 的 jobs 都是并行执行的。
  2. 所有 build 的 jobs 执行成功后,test 的 jobs 才会开始并行执行。
  3. 所有 test 的 jobs 执行成功,deploy 的 jobs 才会开始并行执行。
  4. 所有的 deploy 的 jobs 执行成功,commit才会标记为success。
  5. 任何一个前置的 jobs 失败了,commit会标记为failed并且下一个 stages 的 jobs 都不会执行。
    这有两个特殊的例子值得一提:
  • 如果 .gitlab-ci.yml 中没有定义 stages,默认 stage 为 buildtestdeploy
  • 如果 Job 未指定 stage,默认分配到 test stage

参考链接

-------------本文结束感谢您的阅读-------------