Jenkins 持续集成/持续交付 完整系统学习大纲
一、CI/CD 与 Jenkins 概述
1.1 什么是 CI/CD
- 持续集成(CI, Continuous Integration)
- 定义:频繁地将代码变更合并到主干分支,并通过自动化构建和测试快速验证
- 核心思想:早集成、早发现、早修复
- 流程:开发提交代码 → 自动拉取 → 自动构建 → 自动测试 → 反馈结果
- 持续交付(CD, Continuous Delivery)
- 定义:在 CI 基础上,确保代码可以随时安全地部署到生产环境
- 特点:每次构建产物都是”可发布”状态,但需要手动触发实际部署
- 持续部署(CD, Continuous Deployment)
- 定义:在持续交付基础上更进一步,通过自动化测试的变更自动部署到生产环境
- 区别:持续交付需要手动批准,持续部署完全自动化
| 阶段 |
构建 |
测试 |
部署到测试环境 |
部署到生产 |
| 持续集成 |
自动化 |
自动化 |
可选 |
无 |
| 持续交付 |
自动化 |
自动化 |
自动化 |
手动 |
| 持续部署 |
自动化 |
自动化 |
自动化 |
自动化 |
1.2 Jenkins 简介
- 定义:Jenkins 是一个开源的、基于 Java 的自动化服务器,用于实现 CI/CD
- 历史:
- 前身是 Sun Microsystems 的 Hudson(2004年)
- 2011年 Oracle 与社区分裂,社区分支更名为 Jenkins
- 目前由 CloudBees 和社区共同维护
- 核心特性:
- 开源免费,MIT 许可证
- 跨平台:Windows、macOS、Linux
- 丰富的插件生态:1800+ 官方插件
- 支持分布式构建(Master-Agent 架构)
- Pipeline as Code(Jenkinsfile)
- 强大的可视化(Blue Ocean、Stage View)
- 支持多种 SCM(Git、SVN、Mercurial 等)
1.3 Jenkins 与其他 CI/CD 工具对比
| 特性 |
Jenkins |
GitLab CI |
GitHub Actions |
TeamCity |
| 开源 |
是 |
CE 版开源 |
公开仓库免费 |
专业版收费 |
| 安装方式 |
独立部署 |
集成 GitLab |
集成 GitHub |
独立部署 |
| 配置方式 |
Pipeline as Code |
YAML |
YAML |
Kotlin DSL/UI |
| 插件生态 |
极丰富(1800+) |
有限 |
Actions 市场 |
有限 |
| 学习曲线 |
中等 |
较低 |
较低 |
中等 |
| 分布式构建 |
原生支持 |
需要 Runner |
需要 Runner |
原生支持 |
| 适用场景 |
灵活定制、企业级 |
GitLab 用户 |
GitHub 用户 |
中小型团队 |
二、环境搭建与安装
2.1 系统要求
| 资源 |
最低要求 |
推荐配置 |
| CPU |
1 核 |
4 核+ |
| 内存 |
256 MB |
4 GB+ |
| 磁盘 |
1 GB(不含构建空间) |
50 GB+ |
| Java |
JDK 8 或 JDK 11 |
JDK 11 或 JDK 17 |
| 操作系统 |
Windows / macOS / Linux |
Linux(推荐) |
2.2 安装方式
2.2.1 Windows 安装
# 方式一:下载 MSI 安装包
# 访问 https://jenkins.io/download/ 下载 Windows 安装包
# 双击运行,按向导安装,会自动注册为 Windows 服务
# 方式二:使用 WAR 包运行
java -jar jenkins.war --httpPort=8080
2.2.2 Linux(Debian/Ubuntu)安装
# 1. 添加 Jenkins 仓库密钥和源
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
# 2. 安装 Java(Jenkins 需要 Java 运行环境)
sudo apt update
sudo apt install fontconfig openjdk-17-jre
# 3. 安装 Jenkins
sudo apt update
sudo apt install jenkins
# 4. 启动 Jenkins 并设置开机自启
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
2.2.3 Docker 安装
# 拉取官方镜像
docker pull jenkins/jenkins:lts-jdk17
# 运行容器
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkins/jenkins:lts-jdk17
# 获取初始管理员密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
2.3 初始化配置
- 解锁 Jenkins:访问
http://localhost:8080,输入初始管理员密码
- Linux:
/var/lib/jenkins/secrets/initialAdminPassword
- Docker:
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
- 安装推荐插件:选择”安装推荐的插件”(推荐新手)或”选择插件来安装”
- 创建管理员账户:设置用户名、密码、邮箱
- 配置 Jenkins URL:设置 Jenkins 的访问地址(用于邮件、通知等)
Jenkins 目录结构详解
| 目录/文件 |
说明 |
JENKINS_HOME/ |
Jenkins 主目录(Linux 默认 /var/lib/jenkins/) |
JENKINS_HOME/jobs/ |
每个 Job 的配置、构建记录、工作空间 |
JENKINS_HOME/plugins/ |
已安装的插件 |
JENKINS_HOME/workspace/ |
构建工作区(每个 Job 一个目录) |
JENKINS_HOME/users/ |
用户配置和权限信息 |
JENKINS_HOME/secrets/ |
密钥文件(如初始密码) |
JENKINS_HOME/config.xml |
Jenkins 全局配置文件 |
JENKINS_HOME/logs/ |
Jenkins 日志文件 |
三、核心概念与术语
3.1 核心术语
| 术语 |
说明 |
| Job / Project |
一个构建任务,定义了构建的步骤和配置 |
| Build |
一次具体的构建执行,对应一个构建编号(#1, #2, …) |
| Workspace |
构建的工作目录,存放检出的源码和生成的文件 |
| Node |
执行构建的节点(服务器),可以是 Master 或 Agent |
| Master |
Jenkins 主节点,负责调度任务、管理配置 |
| Agent / Slave |
Jenkins 从节点,接收 Master 任务,执行实际的构建工作 |
| Executor |
执行器,一个节点上可并行执行的构建线程数 |
| View |
视图,用于组织和筛选 Job 的显示方式 |
| SCM |
源码管理(Source Code Management),如 Git、SVN |
| Trigger |
触发器,定义何时启动构建 |
| Artifact |
构建产物,如 JAR 包、WAR 包、测试报告等 |
3.2 Jenkins 系统架构
┌─────────────────────────────────────────────────────┐
│ Jenkins Master │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Web UI │ │ 调度器 │ │ 配置/插件管理 │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
│ │ │
│ 分发构建任务到 Agent │
└────────────────────────┼────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Agent 1 │ │ Agent 2 │ │ Agent 3 │
│ (Linux) │ │ (Windows)│ │ (macOS) │
│ 构建 Java │ │ 构建 .NET │ │ 构建 iOS │
└──────────┘ └──────────┘ └──────────┘
四、Freestyle 项目(自由风格项目)
4.1 创建 Freestyle 项目
- 创建步骤:Dashboard → 新建 Item → 输入名称 → 选择”Freestyle project” → 确定
- 适用场景:简单任务、快速上手学习、不需要 Pipeline 脚本的小型项目
4.2 核心配置项
- General(通用配置)
- 描述:对 Job 的文字说明
- 丢弃旧的构建:设置保留天数和最大构建数,清理磁盘空间
- 参数化构建:允许在触发构建时传入参数
- 并发构建:是否允许同一个 Job 同时执行多次
- 源码管理(SCM)
- Git:配置仓库 URL、分支、凭证
- Subversion(SVN):配置 SVN 仓库地址
- None:不从源码管理拉取代码
- 构建触发器
- 定时构建(Build periodically):Cron 表达式
- 轮询 SCM(Poll SCM):定期检查仓库变更
- 远程触发:通过 URL 触发构建
- 其他项目构建后触发
- 构建环境
- Delete workspace before build starts
- Use secret text(s) or file(s)
- Add timestamps to the Console Output
- Set environment variables
- 构建步骤(Build Steps)
- Execute shell(Linux)/ Execute Windows batch command
- Invoke Ant / Invoke Gradle / Invoke top-level Maven targets
- Docker 相关步骤
- 构建后操作(Post-build Actions)
- 归档成品(Archive the artifacts)
- 发布 JUnit 测试结果报告
- 邮件通知(E-mail Notification)
- 触发其他项目构建
4.3 Freestyle 项目示例
# 执行 Shell 步骤示例
# 项目名称:simple-java-build
# 源码管理:Git - https://github.com/example/java-demo.git
# 构建步骤 - Execute shell:
echo "=== 开始构建 ==="
echo "工作空间: ${WORKSPACE}"
echo "构建编号: ${BUILD_NUMBER}"
# 清理旧构建产物
mvn clean
# 编译打包
mvn package -DskipTests
# 运行单元测试
mvn test
echo "=== 构建完成 ==="
Cron 表达式详解(定时触发)
格式:分 时 日 月 周
示例:
H/15 * * * * # 每15分钟构建一次
H H * * * # 每小时构建一次(每天24次)
H H(9-18) * * * # 工作日9-18点,每小时构建一次
H H(9-18) * * 1-5 # 周一到周五,9-18点,每小时构建一次
H 2 * * * # 每天凌晨2点构建一次
H H 1,15 * * # 每月1号和15号各构建一次
注意:
- H 表示 Hash,Jenkins 使用哈希值来均匀分散负载
- 与标准 Cron 的区别:Jenkins 不支持秒级调度
- 建议使用 H 代替具体数值,避免多任务同时触发
五、Pipeline(流水线)
5.1 Pipeline 概述
- 定义:Pipeline 是一种用代码描述 CI/CD 流程的方式(Pipeline as Code)
- 优势:
- 可版本控制:Pipeline 脚本可以存入 Git 仓库
- 可复用:可通过共享库提取公共逻辑
- 可恢复:Jenkins 重启后 Pipeline 自动继续执行
- 可视化:Stage View 直观展示每个阶段的耗时和状态
- 支持复杂逻辑:条件判断、循环、并行、错误处理等
5.2 Declarative Pipeline(声明式) vs Scripted Pipeline(脚本式)
| 对比维度 |
Declarative Pipeline |
Scripted Pipeline |
| 语法风格 |
结构化、声明式,注重”做什么” |
命令式、程序化,注重”怎么做” |
| 学习难度 |
较低,语法简洁 |
较高,需要 Groovy 基础 |
| 代码位置 |
pipeline { } 块内 |
node { } 块内 |
| 错误检查 |
启动时语法校验 |
运行时才报错 |
| 内置功能 |
when, post, environment 等指令 |
需要手动编程实现 |
| 灵活性 |
受限于 DSL 语法 |
完全灵活,Groovy 全能力 |
| 推荐场景 |
大多数 CI/CD 场景 |
复杂自定义逻辑 |
| 起始标记 |
pipeline {} |
node {} 或 stage {} |
5.3 Declarative Pipeline 核心语法
5.3.1 基本结构
pipeline {
agent any // 1. agent - 指定在哪执行
environment { // 2. environment - 环境变量
APP_NAME = 'my-app'
APP_VERSION = '1.0.0'
}
parameters { // 3. parameters - 参数化构建
string(name: 'BRANCH', defaultValue: 'main', description: '分支名')
choice(name: 'ENV', choices: ['dev', 'test', 'prod'], description: '部署环境')
booleanParam(name: 'SKIP_TEST', defaultValue: false, description: '是否跳过测试')
}
triggers { // 4. triggers - 触发器
cron('H 2 * * *')
pollSCM('H/5 * * * *')
}
tools { // 5. tools - 工具配置
maven 'maven-3.8'
jdk 'jdk-11'
}
options { // 6. options - 选项配置
timestamps() // 控制台输出时间戳
timeout(time: 1, unit: 'HOURS') // 超时设置
disableConcurrentBuilds() // 禁止并发构建
buildDiscarder(logRotator(numToKeepStr: '10')) // 保留最近10次构建
}
stages { // 7. stages - 阶段集合
stage('Checkout') { // 8. stage - 单个阶段
steps { // 9. steps - 步骤集合
checkout scm
echo "当前分支: ${env.BRANCH_NAME}"
}
}
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
when { // 10. when - 条件执行
expression { params.SKIP_TEST == false }
}
steps {
sh 'mvn test'
}
}
stage('Deploy') {
parallel { // 11. parallel - 并行执行
stage('Deploy to Dev') {
steps {
echo '部署到开发环境...'
}
}
stage('Deploy to Test') {
steps {
echo '部署到测试环境...'
}
}
}
}
}
post { // 12. post - 构建后操作
always { // 总是执行
echo '清理工作空间...'
}
success { // 构建成功时
emailext (
subject: "构建成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "构建成功!详情请查看: ${env.BUILD_URL}",
to: 'team@example.com'
)
}
failure { // 构建失败时
emailext (
subject: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "构建失败!详情请查看: ${env.BUILD_URL}",
to: 'team@example.com'
)
}
unstable { // 构建不稳定时
echo '测试未通过,构建标记为不稳定'
}
changed { // 构建状态发生变化时
echo '构建状态发生了变化'
}
}
}
5.3.2 agent 详解
pipeline {
// agent 指定 Pipeline 的执行位置
// 1. any - 在任何可用的 agent 上执行
agent any
// 2. none - 不在顶层指定 agent,每个 stage 各自指定
agent none
// 3. label - 在有特定标签的 agent 上执行
agent { label 'linux && docker' }
// 4. docker - 在 Docker 容器中执行
agent {
docker {
image 'maven:3.8-openjdk-11'
args '-v /tmp:/tmp'
}
}
// 5. dockerfile - 通过 Dockerfile 构建镜像并运行
agent {
dockerfile {
filename 'Dockerfile.build'
dir 'docker'
additionalBuildArgs '--build-arg version=1.0'
}
}
// 6. kubernetes - 在 Kubernetes Pod 中执行
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8-openjdk-11
'''
}
}
}
5.3.3 when 条件详解
stage('条件示例') {
when {
// 分支条件
branch 'main'
// 或:匹配多个分支
// anyOf { branch 'main'; branch 'develop' }
// 环境变量条件
environment name: 'DEPLOY_TO', value: 'production'
// 表达式条件(支持 Groovy 表达式)
expression { return params.DEPLOY == true }
// 非条件
not { branch 'master' }
// 所有条件都满足
allOf {
branch 'main'
environment name: 'APPROVED', value: 'true'
}
// 任一条件满足
anyOf {
branch 'main'
branch 'hotfix'
}
// 变更触发条件
changeset '**/*.java'
// 判断是否有特定文件变更
changeset "src/**/*"
}
steps {
echo '条件满足,执行此阶段'
}
}
5.4 Scripted Pipeline 示例
node('linux') {
// 定义环境变量
def appName = 'my-app'
def buildResult = ''
try {
stage('Checkout') {
checkout scm
echo "当前工作目录: ${pwd()}"
}
stage('Build') {
// 使用 try-catch 处理单个阶段错误
try {
sh 'mvn clean compile'
} catch (Exception e) {
echo "编译失败: ${e.message}"
error("编译阶段失败")
}
}
stage('Test') {
// 并行执行多个测试
parallel(
unit: {
sh 'mvn test'
},
integration: {
sh 'mvn verify -P integration-test'
}
)
}
// 使用 Groovy 循环动态创建 stage
def environments = ['dev', 'test', 'staging']
for (envName in environments) {
stage("Deploy to ${envName}") {
echo "正在部署到 ${envName} 环境..."
// 这里写部署逻辑
sleep 5
}
}
buildResult = 'SUCCESS'
} catch (Exception e) {
buildResult = 'FAILURE'
echo "Pipeline 执行异常: ${e.message}"
throw e
} finally {
// 清理操作
stage('Cleanup') {
echo "构建结果: ${buildResult}"
cleanWs()
}
}
}
六、Jenkinsfile
6.1 Jenkinsfile 概述
- 定义:Jenkinsfile 是一个文本文件,包含 Pipeline 的定义,通常存放在项目源码仓库的根目录
- 文件名:默认
Jenkinsfile(可自定义)
- 位置:项目根目录或子目录
- 好处:
- 构建流程与代码一起版本管理
- Code Review 时可以审查 CI/CD 流程
- 审计追踪:谁对 Pipeline 做了哪些修改
6.2 在 Jenkins 中使用 Jenkinsfile
创建 Pipeline Job 引用 Jenkinsfile:
- 新建 Item → 输入名称 → 选择”Pipeline” → 确定
- 在”Pipeline”配置项中,Definition 选择”Pipeline script from SCM”
- SCM 选择 Git → 填写仓库 URL → 填写分支
- Script Path → 填写
Jenkinsfile(默认值)
6.3 Jenkinsfile 最佳实践
Jenkinsfile 编写最佳实践
- 使用 Declarative Pipeline(推荐):语法清晰、易于维护
- 使用共享库:提取公共逻辑,避免重复代码
- 禁用 Groovy Sandbox 时要谨慎:仅在信任的代码中使用
- 避免在 Pipeline 中直接使用
input 阻塞:会占用 Executor
- 合理使用
timeout:防止构建无限等待
- 使用环境变量:而非硬编码值
- 凭证使用
withCredentials:安全处理敏感信息
- 使用
when 指令:条件化执行 stage
- 合理设置
agent:避免所有 stage 在同一个 agent 执行
- 使用
post 块:处理通知和清理
- 避免在 Pipeline 中执行
sleep:应使用合适的等待机制
- 添加恰当的错误处理:
catchError、retry 等
七、插件管理
7.1 插件概念
- 插件是 Jenkins 的核心扩展机制,所有功能几乎都通过插件实现
- 1800+ 官方插件覆盖了版本管理、构建工具、云平台、通知、报告等各方面
7.2 插件管理操作
管理路径:Dashboard → Manage Jenkins → Plugins → Available plugins
# 安装方式:
# 1. 在线安装(推荐):在 Available 标签页搜索并勾选,点击 Install
# 2. 离线安装:上传 .hpi 文件(Advanced settings → Upload Plugin)
# 3. 命令行安装(需重启 Jenkins)
java -jar jenkins-cli.jar -s http://localhost:8080/ install-plugin <plugin-name>
7.3 常用必备插件
| 插件名称 |
用途 |
| Git |
Git 源码管理 |
| Pipeline |
Pipeline 核心功能 |
| Pipeline: Stage View |
Pipeline 阶段可视化 |
| Blue Ocean |
现代化 UI,Pipeline 可视化编辑器 |
| Credentials Binding |
凭证管理与绑定 |
| Email Extension |
增强邮件通知 |
| JUnit |
JUnit 测试报告展示 |
| HTML Publisher |
HTML 报告展示 |
| Build Timestamp |
构建时间戳 |
| Workspace Cleanup |
工作空间清理 |
| Docker Pipeline |
Docker 集成 |
| Kubernetes |
动态创建 K8s Agent |
| SonarQube Scanner |
代码质量扫描 |
| Allure |
Allure 测试报告 |
| Role-based Authorization Strategy |
基于角色的权限管理 |
| Config File Provider |
配置文件管理 |
| Locale |
汉化插件 |
| Git Parameter |
Git 参数化构建 |
| AnsiColor |
控制台彩色输出 |
八、凭证管理与安全
8.1 凭证类型
| 凭证类型 |
说明 |
使用场景 |
| Username with password |
用户名+密码 |
Git 仓库认证、API 认证 |
| SSH Username with private key |
SSH 用户名+私钥 |
Git SSH 密钥认证 |
| Secret text |
加密文本 |
API Token、Token 等 |
| Secret file |
加密文件 |
kubeconfig、证书文件等 |
| Certificate |
证书 |
PKCS#12 证书 |
8.2 在 Pipeline 中使用凭证
pipeline {
agent any
environment {
// 方式一:使用 environment 指令直接绑定
SONAR_TOKEN = credentials('sonar-token-id')
}
stages {
stage('示例:使用凭证') {
steps {
// 方式二:使用 withCredentials 代码块
withCredentials([
usernamePassword(
credentialsId: 'git-credentials',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASS'
),
string(
credentialsId: 'api-token',
variable: 'API_TOKEN'
),
sshUserPrivateKey(
credentialsId: 'ssh-key',
keyFileVariable: 'SSH_KEY_FILE',
usernameVariable: 'SSH_USER'
)
]) {
sh '''
echo "使用 Git 凭证..."
git clone https://${GIT_USER}:${GIT_PASS}@github.com/repo.git
echo "使用 API Token: ${API_TOKEN}"
echo "使用 SSH 密钥: ${SSH_KEY_FILE}"
'''
}
}
}
}
}
8.3 权限管理
权限管理策略
- 安全域(Security Realm)
- Jenkins 自有用户数据库
- LDAP 集成
- Active Directory 集成
- OAuth(GitHub、GitLab、Google 等)
- 授权策略(Authorization)
- Logged-in users can do anything:登录用户全权限
- Matrix-based security:基于矩阵的权限控制
- Role-based Strategy:基于角色的权限控制(需安装插件)
- Project-based Matrix Authorization:基于项目矩阵授权
- Role-based Strategy 推荐角色划分:
admin:完全管理权限
developer:创建 Job、查看构建、配置 Job
viewer:只读权限
operator:运行 Job、查看构建
九、构建触发器详解
9.1 定时构建(Build periodically)
# Cron 表达式:分 时 日 月 周
# 每个工作日(周一到周五)早上 8 点构建
H 8 * * 1-5
# 每天晚上 10 点构建
H 22 * * *
# 每隔 2 小时构建一次
H */2 * * *
9.2 轮询 SCM(Poll SCM)
# 每 5 分钟检查一次 Git 仓库是否有变更
H/5 * * * *
# 工作日每 15 分钟检查一次
H/15 * * * 1-5
9.3 Webhook 触发
GitHub Webhook 配置
- Jenkins 端配置
- 安装 “GitHub Integration” 插件
- Pipeline 中添加
triggers { githubPush() } 或在 Freestyle 中勾选 “GitHub hook trigger for GITScm polling”
- GitHub 端配置
- 仓库 → Settings → Webhooks → Add webhook
- Payload URL:
http://jenkins-server:8080/github-webhook/
- Content type:
application/json
- Events: Just the push event
- 触发流程:开发者 Push 代码 → GitHub 发送 POST 请求到 Jenkins → Jenkins 触发对应 Job
9.4 远程触发
# 通过 URL 触发(需要配置身份验证令牌)
# Freestyle: 构建触发器 → 触发远程构建 → 设置 Token
# 触发命令
curl -X POST http://jenkins-server:8080/job/my-job/build?token=my-token
# 带参数触发
curl -X POST "http://jenkins-server:8080/job/my-job/buildWithParameters?token=my-token&BRANCH=develop"
# Pipeline 远程触发(需安装 Build with Parameters 或使用 Generic Webhook Trigger 插件)
十、构建工具集成
10.1 Maven 集成
pipeline {
agent any
tools {
maven 'maven-3.8' // 需先在 Global Tool Configuration 中配置
}
stages {
stage('Maven Build') {
steps {
sh '''
mvn clean install \
-Dmaven.test.skip=false \
-Dmaven.javadoc.skip=true \
-B -V # 批处理模式 + 显示版本
'''
}
}
stage('Publish Test Report') {
steps {
// 发布 JUnit 测试报告
junit '**/target/surefire-reports/*.xml'
}
}
stage('Archive Artifacts') {
steps {
// 归档构建产物
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
}
10.2 Gradle 集成
stage('Gradle Build') {
steps {
// 使用 Gradle Wrapper(推荐)
sh './gradlew clean build'
// 或使用 Jenkins 管理的 Gradle 工具
// tool name: 'gradle-7.6', type: 'gradle'
// sh 'gradle clean build'
}
}
10.3 Docker 集成
pipeline {
agent any
stages {
stage('Docker Build') {
steps {
script {
// 构建镜像
def appImage = docker.build("my-app:${env.BUILD_NUMBER}", '-f Dockerfile .')
// 推送到镜像仓库
docker.withRegistry('https://registry.example.com', 'registry-credentials') {
appImage.push()
appImage.push('latest')
}
}
}
}
stage('Docker Deploy') {
steps {
script {
// 使用 docker-compose 部署
sh '''
docker-compose down
docker-compose up -d
'''
}
}
}
}
post {
always {
// 清理构建过程中创建的 Docker 镜像
sh 'docker image prune -f'
}
}
}
十一、分布式构建(Master-Agent)
11.1 分布式架构概念
- Master 节点职责:Web UI、调度构建任务、管理配置、存储构建记录
- Agent 节点职责:接收任务、执行构建、返回结果
11.2 添加 Agent 节点
方式一:通过 SSH 连接(推荐)
Dashboard → Manage Jenkins → Nodes → New Node
→ Node Name → 选择 "Permanent Agent"
配置项:
- Name: Agent 名称
- # of executors: 并行构建数量
- Remote root directory: Agent 上的工作目录,如
/home/jenkins/agent
- Labels: 标签,如
linux java docker
- Usage: 选择
Only build jobs with label expressions matching this node
- Launch method: 选择
Launch agents via SSH
- Host: Agent 的 IP 地址
- Credentials: SSH 认证凭证
- Host Key Verification Strategy:
Non verifying Verification Strategy
方式二:通过 Java Web Start 连接
# 在 Agent 机器上执行(从 Jenkins Agent 配置页面获取命令)
java -jar agent.jar -jnlpUrl http://jenkins-master:8080/computer/agent-name/jenkins-agent.jnlp -secret <secret>
11.3 在 Pipeline 中使用标签分配 Agent
pipeline {
// 整个 Pipeline 在带 linux 标签的 agent 上执行
agent { label 'linux' }
stages {
stage('Build on Linux') {
agent { label 'linux' }
steps {
sh 'mvn clean compile'
}
}
stage('Test on Windows') {
agent { label 'windows' }
steps {
bat 'mvn test'
}
}
stage('Deploy with Docker') {
agent {
docker {
image 'node:16-alpine'
label 'docker-enabled'
}
}
steps {
sh 'node --version'
}
}
}
}
十二、共享库(Shared Libraries)
12.1 共享库概念
- 定义:将 Pipeline 中可复用的代码封装为共享库,供多个项目引用
- 存储方式:独立的 Git 仓库,需包含特定目录结构
12.2 共享库目录结构
my-shared-library/ # Git 仓库根目录
├── vars/ # 全局变量(可被 Pipeline 直接调用)
│ ├── sayHello.groovy # 自定义步骤
│ ├── mavenBuild.groovy # Maven 构建封装
│ └── deployApp.groovy # 部署封装
├── src/ # Java/Groovy 源码
│ └── com/
│ └── company/
│ └── jenkins/
│ ├── BuildUtils.groovy
│ └── NotifyUtils.groovy
└── resources/ # 资源文件
└── templates/
└── email-template.html
12.3 编写共享库步骤
文件 vars/mavenBuild.groovy:
#!/usr/bin/env groovy
/**
* 执行 Maven 构建
* @param args Map 类型参数
* - goals: Maven 目标(如 'clean install')
* - options: 额外选项(如 '-DskipTests')
* - pomPath: pom.xml 路径(默认为 '.')
*/
def call(Map args = [:]) {
def goals = args.goals ?: 'clean install'
def options = args.options ?: ''
def pomPath = args.pomPath ?: '.'
pipeline {
agent any
stages {
stage('Maven Build') {
steps {
script {
sh """
cd ${pomPath}
mvn ${goals} ${options} -B
"""
}
}
}
}
}
}
12.4 配置和使用共享库
在 Jenkins 中配置:
Dashboard → Manage Jenkins → Configure System → Global Pipeline Libraries
→ 添加 Library
- Name: my-shared-library
- Default version: main
- Retrieval method: Modern SCM → Git → 仓库 URL
- 勾选 "Load implicitly"(所有 Pipeline 自动加载)
在 Jenkinsfile 中使用:
// 声明使用共享库
@Library('my-shared-library') _
pipeline {
agent any
stages {
stage('Build') {
steps {
// 直接调用共享库中的步骤
mavenBuild(
goals: 'clean package',
options: '-DskipTests'
)
// 调用另一个共享库方法
sayHello(name: 'Jenkins')
}
}
stage('Deploy') {
steps {
script {
// 调用共享库中的工具类
def notifier = new com.company.jenkins.NotifyUtils()
notifier.sendNotification(
status: 'success',
to: 'team@example.com'
)
}
}
}
}
}
十三、Blue Ocean
13.1 Blue Ocean 概述
- 定义:Jenkins 的全新现代化用户界面,专为 Pipeline 设计
- 访问方式:
http://jenkins-server:8080/blue/
- 安装:在插件管理中搜索 “Blue Ocean” 安装
13.2 Blue Ocean 核心功能
| 功能 |
说明 |
| 可视化 Pipeline 编辑器 |
拖拽式创建 Pipeline,无需手写代码 |
| Pipeline 可视化 |
树形展示每个 stage 的执行状态和时间 |
| 分支识别 |
自动发现 Git 仓库的多分支,为每个分支创建独立的 Pipeline |
| 个性化仪表盘 |
可自定义关注的 Pipeline 视图 |
| 测试报告集成 |
直接在 UI 中查看测试结果和失败详情 |
| 日志查看 |
分步骤查看构建日志,易于定位问题 |
| GitHub/GitLab 集成 |
直接从 UI 创建 GitHub/GitLab 分支的 Pipeline |
十四、邮件与通知
14.1 邮件通知配置
// Jenkins 系统管理配置(Manage Jenkins → Configure System):
// - Jenkins URL: http://jenkins.example.com:8080/
// - 系统管理员邮件地址: jenkins@example.com
// - Extended E-mail Notification(高级配置)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
}
post {
success {
// 方式一:标准邮件通知
mail (
to: 'dev-team@example.com',
subject: "构建成功: ${env.JOB_NAME} - #${env.BUILD_NUMBER}",
body: """
构建项目: ${env.JOB_NAME}
构建编号: #${env.BUILD_NUMBER}
构建结果: 成功
构建 URL: ${env.BUILD_URL}
构建时间: ${currentBuild.durationString}
"""
)
// 方式二:增强邮件通知(需安装 Email Extension 插件)
emailext (
subject: "✅ 构建成功: ${env.JOB_NAME} - #${env.BUILD_NUMBER}",
body: '''${SCRIPT, template="groovy-html.template"}''',
to: 'dev-team@example.com',
attachLog: true, // 附加构建日志
compressLog: true // 压缩日志
)
}
failure {
emailext (
subject: "❌ 构建失败: ${env.JOB_NAME} - #${env.BUILD_NUMBER}",
body: '''${SCRIPT, template="groovy-html.template"}''',
to: 'dev-team@example.com',
recipientProviders: [
[ $class: 'DevelopersRecipientProvider' ], // 发送给变更提交者
[ $class: 'CulpritsRecipientProvider' ] // 发送给责任人
]
)
}
}
}
14.2 企业微信/钉钉/飞书通知
钉钉机器人通知示例
// 需安装 HTTP Request 插件,或使用 DingTalk 插件
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
}
post {
success {
script {
def dingtalkUrl = 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN'
def message = [
msgtype: 'markdown',
markdown: [
title: "构建通知",
text: """## ✅ Jenkins 构建成功
> **项目**: ${env.JOB_NAME}
> **构建编号**: #${env.BUILD_NUMBER}
> **分支**: ${env.BRANCH_NAME}
> **耗时**: ${currentBuild.durationString}
> [查看详情](${env.BUILD_URL})
"""
]
]
httpRequest (
url: dingtalkUrl,
httpMode: 'POST',
contentType: 'APPLICATION_JSON',
requestBody: groovy.json.JsonOutput.toJson(message)
)
}
}
failure {
script {
// 类似的失败通知逻辑
echo "发送失败通知到钉钉..."
}
}
}
}
十五、常用操作与技巧
15.1 常用内置环境变量
| 变量名 |
说明 |
示例值 |
BUILD_NUMBER |
构建编号 |
42 |
BUILD_ID |
构建 ID |
2024-01-01_12-00-00 |
BUILD_URL |
构建 URL |
http://jenkins/job/my-job/42/ |
JOB_NAME |
项目名称 |
my-job |
JOB_URL |
项目 URL |
http://jenkins/job/my-job/ |
WORKSPACE |
工作空间路径 |
/var/jenkins/workspace/my-job |
NODE_NAME |
节点名称 |
master |
NODE_LABELS |
节点标签 |
linux docker |
BRANCH_NAME |
分支名(Multibranch Pipeline) |
main |
GIT_COMMIT |
Git 提交哈希 |
a1b2c3d... |
GIT_BRANCH |
Git 分支 |
origin/main |
BUILD_TAG |
构建标签 |
jenkins-my-job-42 |
EXECUTOR_NUMBER |
执行器编号 |
0 |
JENKINS_URL |
Jenkins 根 URL |
http://jenkins:8080/ |
JENKINS_HOME |
Jenkins 主目录 |
/var/lib/jenkins |
15.2 参数化构建
pipeline {
agent any
parameters {
// 字符串参数
string(name: 'VERSION', defaultValue: '1.0.0', description: '发布版本号')
// 选择参数
choice(name: 'ENVIRONMENT', choices: ['dev', 'test', 'staging', 'prod'], description: '部署环境')
// 布尔参数
booleanParam(name: 'RUN_TESTS', defaultValue: true, description: '是否运行测试')
// 密码参数
password(name: 'DEPLOY_KEY', defaultValue: '', description: '部署密钥')
// 文件参数
// file(name: 'CONFIG_FILE', description: '上传配置文件')
// Git 参数(需安装 Git Parameter 插件)
gitParameter(name: 'BRANCH', type: 'PT_BRANCH', defaultValue: 'main', description: '选择分支')
}
stages {
stage('使用参数') {
steps {
echo "版本号: ${params.VERSION}"
echo "部署环境: ${params.ENVIRONMENT}"
echo "是否运行测试: ${params.RUN_TESTS}"
}
}
stage('条件执行') {
when {
expression { params.RUN_TESTS == true }
}
steps {
echo '运行测试...'
}
}
}
}
15.3 重试机制
pipeline {
agent any
stages {
stage('Deploy') {
steps {
// 方式一:使用 retry 步骤
retry(3) {
sh '''
echo "尝试部署..."
# 模拟部署操作
sleep 2
'''
}
}
}
stage('Unstable Build') {
steps {
script {
try {
sh 'mvn test'
} catch (Exception e) {
// 标记构建为不稳定,而非失败
currentBuild.result = 'UNSTABLE'
echo "测试有失败,但构建继续"
}
}
}
}
stage('Skip Stage On Error') {
steps {
// 方式二:使用 catchError 捕获错误并继续
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh './optional-script.sh'
}
}
}
}
}
pipeline {
agent any
stages {
stage('Build and Test') {
steps {
echo '构建和测试完成'
}
}
stage('Approval') {
steps {
// 等待人工审批
input (
message: '是否部署到生产环境?',
ok: '确认部署',
submitter: 'admin,leader', // 允许审批的用户
submitterParameter: 'APPROVER', // 记录审批人
parameters: [
string(name: 'REASON', defaultValue: '', description: '部署原因')
]
)
}
}
stage('Deploy to Production') {
steps {
echo "审批人: ${APPROVER}, 部署原因: ${REASON}"
echo '开始生产部署...'
}
}
}
}
十六、常见问题与排查
16.1 常见问题
问题 1:Jenkins 内存不足(OOM)
- 现象:Jenkins 频繁崩溃或重启,日志中出现
OutOfMemoryError
- 原因:默认 JVM 堆内存太小,大量构建任务占用内存
- 解决:
# 编辑 Jenkins 启动配置(Linux: /etc/default/jenkins)
JAVA_ARGS="-Xms1024m -Xmx4096m -XX:MaxPermSize=512m"
# Docker 方式
docker run -e JAVA_OPTS="-Xms1024m -Xmx4096m" jenkins/jenkins:lts-jdk17
# 重启 Jenkins 使配置生效
问题 2:磁盘空间不足
- 现象:构建失败,提示磁盘空间不足
- 解决:
- 设置构建保留策略(Discard Old Builds):限制保留天数和数量
- 定期清理工作空间:安装 Workspace Cleanup 插件
- 使用
cleanWs() 在 Pipeline 结束时清理
- 清理 JENKINS_HOME 大文件:
du -sh /var/lib/jenkins/* | sort -rh | head -20
问题 3:Pipeline 脚本语法错误
- 解决方式:
- 使用 Jenkins 内置的 “Pipeline Syntax” 生成器(Pipeline Job → Pipeline Syntax)
- 安装 “Pipeline Utility Steps” 插件获取更多工具步骤
- 使用 Blue Ocean 的可视化编辑器减少语法错误
- 在本地使用
jenkinsfile-runner 测试 Jenkinsfile
问题 4:插件兼容性问题
- 现象:升级 Jenkins 后某些功能异常
- 解决:
- 升级前先备份 Jenkins Home 目录
- 在测试环境先验证升级
- 使用 Jenkins LTS(长期支持)版本,避免频繁升级
- 检查插件更新日志中的兼容性说明
问题 5:Git 拉取超时或失败
- 解决:
- 检查凭证是否有效和过期
- 检查网络连接和防火墙规则
- 增加 Git 超时时间:
git config --global http.lowSpeedLimit 0
- 使用浅克隆(Shallow Clone)减少拉取时间:
checkout([$class: 'GitSCM', extensions: [[$class: 'CloneOption', shallow: true, depth: 1]]])
16.2 备份与恢复
Jenkins 备份策略
# 推荐备份内容:整个 JENKINS_HOME 目录(通常是 /var/lib/jenkins/)
# 方式一:使用 ThinBackup 插件
# Dashboard → Manage Jenkins → ThinBackup → Settings → Backup Now
# 方式二:手动备份
#!/bin/bash
BACKUP_DIR="/backup/jenkins"
DATE=$(date +%Y%m%d_%H%M%S)
JENKINS_HOME="/var/lib/jenkins"
# 停止 Jenkins(可选,推荐夜间操作)
# sudo systemctl stop jenkins
# 创建备份
tar -czf "${BACKUP_DIR}/jenkins_backup_${DATE}.tar.gz" -C ${JENKINS_HOME} .
# 保留最近 30 天的备份
find ${BACKUP_DIR} -name "jenkins_backup_*.tar.gz" -mtime +30 -delete
# 启动 Jenkins
# sudo systemctl start jenkins
echo "备份完成: ${BACKUP_DIR}/jenkins_backup_${DATE}.tar.gz"
十七、性能优化
17.1 Jenkins 性能优化方案
| 优化方向 |
措施 |
| JVM 优化 |
使用 G1 垃圾回收器:-XX:+UseG1GC,设置合理的堆大小 |
| 插件管理 |
卸载不需要的插件,定期更新插件 |
| 构建历史 |
限制保留的构建数量,定期清理旧构建 |
| Master 节点 |
Master 节点不执行构建任务(设置 Executor 为 0) |
| 分布式构建 |
将构建任务分散到多个 Agent 节点 |
| 文件系统 |
使用 SSD,避免 NFS 作为 JENKINS_HOME |
| 索引优化 |
定期运行 java -jar jenkins-cli.jar clear-queue 清理队列 |
| 日志清理 |
配置日志轮转策略 |
| 构建超时 |
为每个 Pipeline 设置 timeout |
17.2 最佳实践清单
- ✅ 使用 Declarative Pipeline
- ✅ Jenkinsfile 纳入版本管理
- ✅ 使用共享库提取公共逻辑
- ✅ Master 节点不执行构建任务
- ✅ 设置合理的构建保留策略
- ✅ 使用 LTS(长期支持)版本
- ✅ 配置 SSL/HTTPS
- ✅ 定期备份 JENKINS_HOME
- ✅ 使用凭证管理敏感信息,不硬编码
- ✅ 为 Pipeline 设置 timeout
- ✅ 使用 when 条件控制 stage 执行
- ✅ Agent 使用 label 进行任务分配
- ✅ 配置构建失败通知
- ✅ 合理使用并行执行加速构建
十八、实际项目 Pipeline 示例
18.1 完整的前后端项目 CI/CD Pipeline
pipeline {
agent { label 'linux && docker' }
environment {
DOCKER_REGISTRY = 'registry.example.com'
APP_NAME = 'web-application'
SONAR_HOST = 'http://sonarqube.example.com:9000'
}
parameters {
string(name: 'RELEASE_VERSION', defaultValue: '', description: '发布版本号(留空则使用构建编号)')
choice(name: 'DEPLOY_ENV', choices: ['dev', 'test', 'staging', 'prod'], description: '部署环境')
booleanParam(name: 'SKIP_SONAR', defaultValue: false, description: '跳过代码质量检查')
}
options {
timeout(time: 2, unit: 'HOURS')
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '30', daysToKeepStr: '90'))
timestamps()
}
stages {
stage('Checkout') {
steps {
checkout scm
echo "分支: ${env.BRANCH_NAME}, 提交: ${env.GIT_COMMIT.take(8)}"
}
}
stage('Version') {
steps {
script {
if (params.RELEASE_VERSION) {
env.APP_VERSION = params.RELEASE_VERSION
} else {
env.APP_VERSION = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
}
echo "构建版本: ${env.APP_VERSION}"
}
}
}
stage('Code Quality') {
when { expression { !params.SKIP_SONAR } }
steps {
withSonarQubeEnv('SonarQube') {
sh """
mvn sonar:sonar \
-Dsonar.projectKey=${APP_NAME} \
-Dsonar.projectVersion=${APP_VERSION} \
-Dsonar.host.url=${SONAR_HOST}
"""
}
}
}
stage('Build') {
steps {
sh "mvn clean package -DskipTests -Drevision=${APP_VERSION}"
}
}
stage('Unit Test') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Docker Build & Push') {
steps {
script {
def imageName = "${DOCKER_REGISTRY}/${APP_NAME}:${APP_VERSION}"
def dockerImage = docker.build(imageName)
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry-cred') {
dockerImage.push()
if (params.DEPLOY_ENV == 'prod') {
dockerImage.push('latest')
}
}
echo "镜像已推送: ${imageName}"
}
}
}
stage('Deploy') {
when {
anyOf {
expression { params.DEPLOY_ENV != 'prod' }
expression {
input(
message: '确认部署到生产环境?',
ok: '确认'
)
return true
}
}
}
steps {
script {
echo "开始部署到 ${params.DEPLOY_ENV} 环境..."
// 根据环境使用不同的部署方式
switch(params.DEPLOY_ENV) {
case 'dev':
sh "kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${APP_VERSION} -n dev"
break
case 'test':
sh "kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${APP_VERSION} -n test"
break
case 'staging':
sh "helm upgrade ${APP_NAME} ./helm-chart --set image.tag=${APP_VERSION} -n staging"
break
case 'prod':
sh "helm upgrade ${APP_NAME} ./helm-chart --set image.tag=${APP_VERSION} -n production"
break
}
}
}
}
stage('Smoke Test') {
steps {
sh '''
sleep 15 # 等待服务启动
curl -f http://service-endpoint/health || exit 1
'''
}
}
}
post {
success {
script {
def duration = currentBuild.durationString.replace(' and counting', '')
emailext(
subject: "✅ [${params.DEPLOY_ENV}] ${APP_NAME} #${BUILD_NUMBER} 构建部署成功",
body: """
<h3>构建部署成功</h3>
<ul>
<li><b>项目:</b> ${APP_NAME}</li>
<li><b>版本:</b> ${APP_VERSION}</li>
<li><b>环境:</b> ${params.DEPLOY_ENV}</li>
<li><b>分支:</b> ${BRANCH_NAME}</li>
<li><b>耗时:</b> ${duration}</li>
</ul>
<p><a href="${BUILD_URL}">查看构建详情</a></p>
""",
to: 'dev-team@example.com',
mimeType: 'text/html'
)
}
}
failure {
echo '构建或部署失败,请检查日志。'
}
always {
cleanWs(
cleanWhenNotBuilt: false,
deleteDirs: true,
disableDeferredWipeout: true
)
}
}
}
总结
- Jenkins 作为业界最成熟的开源 CI/CD 工具,具有极强的灵活性和可扩展性
- Declarative Pipeline 是推荐的 Pipeline 编写方式,结构清晰、易于维护
- Jenkinsfile + 共享库 是实现 Pipeline as Code 的核心模式
- 插件生态 是 Jenkins 的核心竞争力,但需审慎管理插件数量
- 分布式构建 是大规模项目的必要架构
- 安全和备份 是生产环境必须重视的方面
- 持续学习和实践是掌握 Jenkins 的最佳途径,建议从简单的 Freestyle 项目开始,逐步过渡到复杂的 Pipeline 和共享库