工作中接手了个项目是使用jenkins构建的,所以借着机会完整看一下Jenkins官方文档并作记录。
说起来,其实早在7~8年前工作中就在用jenkins了,但那时是别人搭建并配置好,甚至都没有自动触发逻辑——仍然需要手动build,实在说不上是多么“utilised”了这个软件。
基本概念
- Jenkins由Java编写
- 类似Gradle, Jenkins自身实现了通用部分的抽象,包括基本的调度和执行等,然后通过plugin来扩展了具体功能,只是Jenkins的plugin能做得更多更广
- 通常我们用一个独立的文件来定义构建流程。在Jenkins中这个文件叫作Jenkinsfile。它有两种格式——声明式(declarative)和脚本式(scripted)。实际上所谓声明式就是通过groovy实现的DSL,底层是已经结构化得脚本命令。相比脚本他结构更清晰,但同时失去了灵活性。对一般项目而言声明式已经足够强大。另外,其实我们可以在任意需要的位置编写groovy脚本,从而在整体declarative的同时部分scripted
- Jenkinsfile可以放在项目根目录下,或者也可以在独立的仓库中维护
- 我们见到的Jenkins界面运行的服务器通常叫做Jenkins controller(以前叫master)。但执行构建一般不是在同一个服务器上,这些构建用的机器通常叫做agent(以前叫node)
Jenkins Controller
- Jenkins Controller(原称 Master)是 Jenkins 的核心服务,负责管理和调度构建任务、维护 Job 与 Pipeline 配置、处理来自 SCM 的 Webhook 事件,并通过 Web UI 和 API 对外提供构建管理与状态信息
- Controller 本身通常不执行实际的构建任务,而是将构建分发到一个或多个 Jenkins Agent 上执行
项目类型
初始化 Jenkins 以后,我们就可以在 Jenkins 网页上点击 Add Item 来创建项目。这里的 Item 会有多种类型可供选择,不同类型基本也对应了 Jenkins 不同历史阶段的使用方式:
Folder
用于组织项目结构,本身不执行构建
Freestyle Project
我觉得这个不如叫做oldschool project。早年我接触的应该也是这种类型。它是最早期、也最“GUI 驱动”的 Jenkins 项目类型。相关构建参数都通过jenkins界面去配置和定义。
在早期阶段,Freestyle Project 通过 GUI 对构建过程中的单个执行步骤做了较好的抽象,例如拉取 Git 代码、执行 Shell 命令等。
Multi-configuration Project
也叫Matrix Project。配置和使用方式上类似Freestyle,同时支持在多个参数组合(矩阵)配置下执行同一套构建逻辑。有点类似Android Gradle Plugin的build variant。
Pipeline Project
相比Freestyle,这是对现代CI有更深入理解后的阶段性产物。这里开始构建流程不再是通过网页,而是在Jenksfile中进行定义。
但这一阶段的Jenkins处理多分支复杂项目时还是会力不从心,由此引出了我们常用的multibranch pipeline。
Multibranch Pipeline
它允许每个分支定义自己的Jenkinsfile。在配置好git仓库地址后,Jenkins就会扫描所有分支,对每个包含 Jenkinsfile 的分支创建一个子 Pipeline。并且支持PR/MR自动构建。
项目创建后,每个项目名称就是一个job name。
Organization Folder
和github/gitlab等绑定,自动为org下的所有项目生成multibranch pipeline。
Plugin
在 Jenkinsfile 中,开发者主要关注项目的构建流程本身,而构建所依赖的插件能力、全局配置或敏感信息(例如访问令牌、凭据等),通常由 Jenkins 管理员提前配置好。
这些配置既可以通过管理员账号登录 Jenkins,在管理页面中完成;也可以通过更现代的方式——“配置即代码(Configuration as Code)”进行管理,即使用独立的配置文件。
此外,像 Docker 或 k8s 这类现代 CI 场景,也需要通过安装相应的插件才能在 Jenkins 中得到支持。
JenkinsFile
Jenkinsfile结构大概是这样:
pipeline {
agent any
stages {
stage('Prepare') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh '''
chmod +x ./gradlew
./gradlew assembleRelease
'''
}
}
}
}
他本质上是一个基于Groovy的DSL实现。
参数
Jenkins Pipeline 在构建时可以接收参数,可以通过 parameters 块在 Jenkinsfile 中进行定义。
pipeline {
agent any
parameters {
string(
name: 'BRANCH_NAME',
defaultValue: 'main',
description: 'target branch'
)
booleanParam(
name: 'RUN_TESTS',
defaultValue: true,
description: 'whether to perform UT'
)
}
...
}
当 Pipeline 定义了参数后,构建会以 参数化构建(Parameterized Build)的形式进行:
- 通过 Web UI、API 或 Webhook 触发构建时,可以指定参数
- 若未显式传入参数,则使用
defaultValue
在 Pipeline 脚本中,可以通过 params.<PARAM_NAME> 的方式访问参数值。此外,Jenkins 会将这些参数同时注入为构建时的环境变量,在执行的步骤(如 sh、bat)中可以通过环境变量的方式访问。
结果处理
post命令类似我们常用的回调函数。可以在在 Pipeline 或 Stage 块内定义,用于处理全局或局部阶段的构建结果。比如归档产物、发布测试报告、资源清理以及通知等操作。
post 支持按构建结果进行条件划分:
always:无论结果如何都会执行success:构建成功时执行failure:构建失败时执行unstable:构建结果为 UNSTABLE 时执行aborted:构建被中断时执行changed:本次构建结果与上一次不同
pipeline {
agent any
stages {
...
stage('Build') {
steps {
sh '''
chmod +x ./gradlew
./gradlew assembleRelease
'''
}
post {
always {
echo 'build finished'
}
failure {
echo 'build failed'
}
}
}
}
}
并行执行(parallel)
pipeline在设计上是串行执行,但类似测试,lint等构建不互相影响的可以并行执行缩短时间。
并行分支一般有各自的 workspace/节点环境;要共享文件用 stash/unstash(或归档再取)。
组合构建
像前面的multi configuration,要同一套构建步骤跑多套组合时可以用matrix。
stage('Matrix Test') {
matrix {
axes {
axis {
name 'JDK'
values '17', '21'
}
axis {
name 'OS'
values 'linux', 'windows'
}
}
stages {
stage('Test') {
steps {
echo "JDK=${JDK}, OS=${OS}"
sh 'make test'
}
}
}
}
}
条件
按条件决定某个 stage 是否执行(分支、PR、参数、变更路径等),尤其适合 Multibranch。例如在针对release和其他分支时,可以执行不同的构建命令。
stage('Deploy') {
when { branch 'main' }
steps { sh './deploy.sh' }
}
构建产物归档(archiveArtifacts)
将构建产物持久化保存,绑定到一次构建记录中,供后续下载或审计
post {
always {
archiveArtifacts artifacts: 'dist/**', allowEmptyArchive: true
}
}
归档文件会出现在 Jenkins UI 的 Artifacts中
文件生命周期与构建记录一致
通常放在 Pipeline 级或 Stage 级
post中不用于在后续 stage 中继续使用
文件暂存与传递(stash / unstash)
在 Pipeline 内部,在不同 stage、不同 agent、或并行分支之间传递文件
stage('Build') {
steps {
sh 'make build'
stash name: 'build-output', includes: 'dist/**'
}
}
stage('Test') {
steps {
unstash 'build-output'
sh 'make test'
}
}
- 只在 同一次 Pipeline 执行内有效
- 不会出现在 Jenkins UI 的 Artifacts 中
- Pipeline 结束后即被清理
- 本质是 Jenkins 内部的临时文件存储
Workspace
Workspace 是 Jenkins 在某个 Agent 节点上,为某个 Job 的某一次构建分配的一块工作目录。
Workspace 与 Agent 绑定:如果多个 stage 在同一个 agent 上顺序执行,它们通常会共享同一个 workspace。
在 parallel 和 matrix 场景下,由于存在并发执行,Jenkins 会为每个并发执行单元提供隔离的 workspace(或等效的隔离视图),以避免并发写入造成冲突。
需要注意的是,如果显式指定共享路径(例如使用 customWorkspace、ws(),或在并行分支中写入同一个外部目录),仍然可能发生文件冲突。
Agent
Agent(也叫 Node) 是 Jenkins 用来实际执行构建步骤的执行环境,可以是:
- 一台物理机
- 一台虚拟机
- 一个 Docker 容器
- 一个 Kubernetes Pod
在 Jenkinsfile 里:
agent any
agent { label 'linux' }
表达的都是:
这段 Pipeline / Stage 在什么执行环境上跑
Executor
Executor 是 Agent 上的一个 “并发执行槽位”。
- 一个 executor = 同一时间 只能执行一个任务
- executor 的数量 = 这个 agent 最多能同时跑多少个任务
一个 agent 拥有多少个 executors 是由 Jenkins 管理员在节点配置中决定的,通常会根据该节点的机器配置(CPU、内存、IO 等)以及预期的任务负载来设置。
Webhooks / API
配置好 Jenkins 项目后,进入具体的 Job 页面,在浏览器地址后追加 /api,可以查看该 Job 所支持的 REST API 描述信息。
例如,通过 REST API 可以主动触发构建:
无参数构建
POST /job/<job-name>/build
参数化构建
/job/<job-name>/buildWithParameters?BRANCH=main&RUN_TESTS=true
需要注意的是,REST API 并不属于 Webhook, 它用于外部系统主动调用Jenkins, 而 Webhook 用于 SCM(如 GitLab、GitHub)在事件发生时 主动通知 Jenkins。
在实际开发中,最常直接使用的是上述 /build 和/buildWithParameters 这类构建 API。而 Webhook 通常需要在 GitLab / GitHub 的仓库或组织设置页面中配置,用于将 push、Merge Request 等事件分发给 Jenkins,从而触发分支扫描或构建。
由于 Webhook 配置发生在 SCM 与 Jenkins 的集成层,通常需要在 Jenkins 项目或 Organization Folder 中提前完成 SCM Source 及发现策略等相关配置,在项目数量较多的情况下,这些集成配置往往由平台或管理员统一维护;相较于 GitLab 自身的 CI(配置即代码、随仓库演进),Jenkins 在初始接入和集中管理上会带来更高的配置成本,也使得部分与构建触发相关的逻辑需要在平台层进行约定和维护。