🚀 Jenkins CI/CD 实战博客教程
定位 :从零搭建企业级自动化流水线 | 适合开发/运维/DevOps 工程师
特色 :每篇含「真实场景 + 完整脚本 + 坑点排查 + 企业最佳实践」
环境 :基于华为云ECS实战环境(
ecs-fddbCI/CD集群 +ecs-2c98K8s集群)所有代码可直接复制运行(已适配 Jenkins 2.4+ LTS)
📋 目录
- [第一部分:Jenkins 入门与核心架构(打好地基)](#第一部分:Jenkins 入门与核心架构(打好地基))
- [第二部分:Pipeline 脚本核心语法(Declarative & Scripted)](#第二部分:Pipeline 脚本核心语法(Declarative & Scripted))
- [第三部分:CI 流水线实战(代码 → 构建 → 测试)](#第三部分:CI 流水线实战(代码 → 构建 → 测试))
- [第四部分:CD 流水线实战(构建 → 部署 → 验证)](#第四部分:CD 流水线实战(构建 → 部署 → 验证))
- 第五部分:高可用与企业级进阶
- 第六部分:真实企业案例合集
- 附录:必备工具包
第一部分:Jenkins 入门与核心架构(打好地基)
1.1 为什么企业都选 Jenkins?
CI/CD 本质:从"人肉发布"到"机器自动流水线"
传统发布流程的痛苦:
开发人员 → 本地构建 → 手动打包 → 上传服务器 → 手动部署 → 发现问题 → 回滚 → 重复...
- ❌ 耗时:每次发布需要30分钟~2小时
- ❌ 易错:手动操作容易出错(漏配环境变量、传错包等)
- ❌ 不可追溯:出了问题不知道是谁、哪个环节出的问题
CI/CD 流水线自动化:
代码提交 → 自动构建 → 自动测试 → 自动打包 → 自动部署 → 自动验证 → 通知
- ✅ 快速:每次发布只需2~5分钟
- ✅ 可靠:标准化流程,减少人为错误
- ✅ 可追溯:每次构建都有完整记录,可快速定位问题
Jenkins vs GitLab CI vs GitHub Actions 对比(附选型决策树)
| 维度 | Jenkins | GitLab CI | GitHub Actions |
|---|---|---|---|
| 部署方式 | 自部署(服务器/容器) | 自部署/GitLab SaaS | SaaS(GitHub托管) |
| 插件生态 | ⭐⭐⭐⭐⭐(1000+插件) | ⭐⭐⭐(内置功能丰富) | ⭐⭐⭐⭐(Marketplace) |
| 灵活性 | ⭐⭐⭐⭐⭐(完全可定制) | ⭐⭐⭐⭐(YAML配置) | ⭐⭐⭐⭐(YAML配置) |
| 学习曲线 | ⭐⭐⭐⭐(较陡峭) | ⭐⭐⭐(中等) | ⭐⭐(较简单) |
| 企业级功能 | ⭐⭐⭐⭐⭐(权限/HA/分布式) | ⭐⭐⭐⭐(内置) | ⭐⭐⭐(需企业版) |
| 适用场景 | 大型企业、复杂流水线、混合云 | GitLab用户、一体化DevOps | GitHub用户、开源项目 |
选型决策树:
你的代码在GitHub上?
├─ 是 → 用 GitHub Actions
└─ 否 → 你的代码在GitLab上?
├─ 是 → 用 GitLab CI
└─ 否 → 你需要高度定制化?
├─ 是 → 用 Jenkins
└─ 否 → 用 GitLab CI 或 GitHub Actions
企业选择Jenkins的核心原因:
- 插件生态丰富:几乎能集成所有工具(Docker、K8s、SonarQube、钉钉等)
- 高度可定制:支持Groovy脚本,可实现任意复杂的流水线逻辑
- 企业级功能:完善的权限管理、高可用架构、分布式构建
- 成熟稳定:10+年历史,大量企业最佳实践可参考
实战:5 分钟部署 Jenkins(Docker + Helm + 二进制三种方式)
方式一:Docker 部署(推荐,最快)
bash
# 创建Jenkins数据目录
mkdir -p /data/jenkins_home
chmod 777 /data/jenkins_home
# 运行Jenkins LTS容器
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v /data/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
--restart=always \
jenkins/jenkins:lts
# 查看初始管理员密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
参数详解:
-p 8080:8080:Web访问端口-p 50000:50000:Agent连接端口-v /data/jenkins_home:/var/jenkins_home:持久化Jenkins数据-v /var/run/docker.sock:/var/run/docker.sock:让Jenkins能调用宿主机的Docker(用于构建镜像)-v /usr/bin/docker:/usr/bin/docker:让Jenkins容器能执行docker命令--restart=always:开机自启动
方式二:Helm 部署(K8s环境推荐)
bash
# 添加Jenkins Helm仓库
helm repo add jenkins https://charts.jenkins.io
helm repo update
# 创建命名空间
kubectl create namespace jenkins
# 安装Jenkins
helm install jenkins jenkins/jenkins \
-n jenkins \
--set controller.servicePort=8080 \
--set controller.targetPort=8080
方式三:二进制部署(传统方式)
bash
# 安装JDK17
apt-get update && apt-get install -y openjdk-17-jdk
# 下载Jenkins WAR包
wget https://get.jenkins.io/war-stable/latest/jenkins.war -O /opt/jenkins.war
# 后台运行Jenkins
nohup java -jar /opt/jenkins.war --httpPort=8080 > /var/log/jenkins.log 2>&1 &
企业最佳实践:
- ✅ 生产环境推荐用Docker或Helm部署(易于迁移和备份)
- ✅ 一定要挂载数据卷(防止容器删除后数据丢失)
- ✅ 配置自动备份(每天定时备份
/var/jenkins_home目录)
1.2 Jenkins 架构解剖
Master/Agent 架构图解(含通信机制:JNLP vs SSH)
┌─────────────────────────────────────────────────────────────┐
│ Jenkins Master │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Web UI │ │ Build │ │ Plugin │ │ Credentials │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ▼
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Agent 通信机制(JNLP vs SSH) │ │
│ ├─────────────────────────────────────────────────────┤ │
│ │ JNLP(默认):Agent主动连接Master(TCP 50000) │ │
│ │ SSH:Master主动连接Agent(SSH 22端口) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Jenkins Agent(s) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Agent-1 │ │ Agent-2 │ │ Agent-3 │ ... │
│ │ (Build) │ │ (Test) │ │ (Deploy) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
JNLP vs SSH 对比:
| 维度 | JNLP(默认) | SSH |
|---|---|---|
| 连接方向 | Agent主动连接Master | Master主动连接Agent |
| 端口 | TCP 50000(需开放) | SSH 22(通常已开放) |
| 适用场景 | Agent在防火墙内/容器里 | Agent在公网/DMZ区 |
| 配置复杂度 | 低(Agent自动连接) | 中(需配置SSH凭据) |
| 企业推荐 | ✅ 容器化环境(K8s Pod as Agent) | ✅ 传统虚拟机环境 |
插件生态全景:Pipeline、Credentials、Git、Docker、Kubernetes 等核心插件
企业级核心插件清单(必装):
| 插件名称 | 用途 | 优先级 |
|---|---|---|
| Pipeline | 支持Jenkinsfile流水线 | ⭐⭐⭐⭐⭐ |
| Credentials Binding | 凭据管理(SSH Key、密码等) | ⭐⭐⭐⭐⭐ |
| Git | Git仓库集成 | ⭐⭐⭐⭐⭐ |
| Docker Pipeline | Docker镜像构建与推送 | ⭐⭐⭐⭐⭐ |
| Kubernetes | K8s云配置(动态Pod Agent) | ⭐⭐⭐⭐⭐ |
| Active Choices | 参数化构建下拉联动 | ⭐⭐⭐⭐ |
| SonarQube Scanner | 代码质量扫描 | ⭐⭐⭐⭐ |
| Role-based Authorization | 权限管理(RBAC) | ⭐⭐⭐⭐ |
| Prometheus | 监控指标暴露 | ⭐⭐⭐ |
| Backup | 数据备份 | ⭐⭐⭐ |
插件安装命令(自动化):
bash
# 在Jenkins容器内执行
jenkins-plugin-cli --plugins \
pipeline \
credentials-binding \
git \
docker-workflow \
kubernetes \
active-choices \
sonar \
role-strategy \
prometheus \
backup
安全加固:CSRF、Script Security、权限矩阵(Role-Based Strategy)
1. CSRF防护:
Jenkins → 系统管理 → 全局安全配置 → CSRF保护 → 启用
- ✅ 防止跨站请求伪造攻击
- ✅ 企业级Jenkins必须开启
2. Script Security:
Jenkins → 系统管理 → 全局安全配置 → 脚本安全 → 启用
- ✅ 限制Groovy脚本执行权限
- ✅ 防止恶意脚本执行
3. 权限矩阵(Role-Based Strategy):
| 角色 | 权限 |
|---|---|
| admin | 全部权限 |
| dev | 构建、查看、取消构建 |
| ops | 构建、部署、配置系统 |
| viewer | 仅查看 |
配置步骤:
- 安装
Role-based Authorization Strategy插件 系统管理 → 管理用户 → 创建用户(dev1、ops1、viewer1)系统管理 → 系统配置 → 全局安全配置 → 授权策略 → Role-Based Strategy系统管理 → Manage and Assign Roles → Manage Roles:
- 创建
dev角色:勾选Job → Build、Cancel、Read - 创建
ops角色:勾选Job → Build、Deploy、Configure、Read - 创建
viewer角色:勾选Job → Read
系统管理 → Manage and Assign Roles → Assign Roles:
- 将
dev1分配给dev角色 - 将
ops1分配给ops角色 - 将
viewer1分配给viewer角色
1.3 基础配置实战
配置全局工具(JDK/Maven/Git/Docker)
自动化配置脚本(Groovy):
groovy
import jenkins.model.*
import hudson.model.*
import hudson.tools.*
// 配置JDK17
def jdkTool = Jenkins.instance.getExtensionList(hudson.tools.JDK.DescriptorImpl.class)[0]
def jdkInstaller = new hudson.tools.JDKInstaller("17", true)
def jdk = new hudson.tools.JDK("JDK17", "/usr/lib/jvm/java-17-openjdk")
jdkTool.setInstallations(jdk)
// 配置Maven3.8.8
def mavenTool = Jenkins.instance.getExtensionList(hudson.tasks.Maven.DescriptorImpl.class)[0]
def maven = new hudson.tasks.Maven.MavenInstallation("Maven3", "/opt/maven", [])
mavenTool.setInstallations(maven)
// 配置Git
def gitTool = Jenkins.instance.getExtensionList(hudson.plugins.git.GitTool.DescriptorImpl.class)[0]
def git = new hudson.plugins.git.GitTool("Git", "/usr/bin/git", [])
gitTool.setInstallations(git)
// 保存配置
Jenkins.instance.save()
执行方式:
bash
# 在Jenkins Master上执行
curl -X POST -u admin:Admin@123456 \
http://localhost:8080/script \
--data-urlencode "script=$(cat config-tools.groovy)"
凭据管理:SSH Key、Username/Password、Docker Registry Token
1. 添加SSH Key凭据(用于Git克隆):
bash
# 生成SSH密钥对
ssh-keygen -t rsa -b 4096 -f ~/.ssh/jenkins_git_key -N ""
# 将公钥添加到Git服务器(如GitLab/GitHub)
cat ~/.ssh/jenkins_git_key.pub
# 在Jenkins中添加SSH私钥
# 方式:Jenkins → 凭据 → 系统 → 全局凭据 → 添加凭据
# 类型:SSH Username with private key
# ID:git-ssh-key
# Username:git
# Private Key:粘贴 ~/.ssh/jenkins_git_key 的内容
2. 添加Username/Password凭据(用于Git账号密码认证):
Jenkins → 凭据 → 系统 → 全局凭据 → 添加凭据
类型:Username with password
ID:git-username-password
Username:your-git-username
Password:your-git-password
3. 添加Docker Registry Token(用于推送镜像):
Jenkins → 凭据 → 系统 → 全局凭据 → 添加凭据
类型:Username with password
ID:docker-registry
Username:your-docker-username
Password:your-docker-password
自动化添加凭据(Groovy脚本):
groovy
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.impl.*
// 添加SSH Key凭据
def sshKey = new BasicSSHUserPrivateKey(
CredentialsScope.GLOBAL,
"git-ssh-key",
"git",
new BasicSSHUserPrivateKey.FileOnMasterPrivateKeySource("/var/jenkins_home/.ssh/id_rsa"),
"",
"Git SSH Key"
)
// 添加Username/Password凭据
def usernamePassword = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
"git-username-password",
"Git Username Password",
"your-git-username",
"your-git-password"
)
// 添加Docker Registry凭据
def dockerRegistry = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
"docker-registry",
"Docker Registry",
"your-docker-username",
"your-docker-password"
)
// 保存凭据
def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
store.addCredentials(Domain.global(), sshKey)
store.addCredentials(Domain.global(), usernamePassword)
store.addCredentials(Domain.global(), dockerRegistry)
// 保存配置
Jenkins.instance.save()
项目类型选择:Freestyle vs Pipeline(为什么必须用 Pipeline?)
| 维度 | Freestyle Project | Pipeline Project |
|---|---|---|
| 配置方式 | Web UI界面配置 | Jenkinsfile(代码化) |
| 可维护性 | ❌ 配置分散在UI,难以版本控制 | ✅ Jenkinsfile可提交到Git,版本控制 |
| 复杂性支持 | ❌ 仅支持简单流水线 | ✅ 支持复杂逻辑(条件、循环、并行) |
| 可复用性 | ❌ 难以复用 | ✅ 可共享库(Shared Library) |
| 企业级适用 | ❌ 不适合 | ✅ 行业标准 |
为什么必须用Pipeline?
- 代码化配置:Jenkinsfile可以提交到Git,方便版本控制和代码审查
- 复杂流水线支持:支持条件判断、循环、并行执行等复杂逻辑
- 可复用:通过Shared Library实现流水线逻辑复用
- 企业标准:所有现代企业CI/CD都使用Pipeline
企业最佳实践:
- ✅ 禁止使用Freestyle Project(难以维护)
- ✅ 所有流水线必须用Declarative Pipeline(更易读)
- ✅ Jenkinsfile必须提交到项目仓库(根目录或
ci/目录)
第二部分:Pipeline 脚本核心语法(Declarative & Scripted)
2.1 Declarative Pipeline 快速上手
基础结构
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
}
}
agent / stages / steps / post 四大核心块详解
1. agent(代理):
- 指定流水线在哪个Agent上执行
- 可选值:
any:任意可用Agentnone:每个stage需指定自己的agentlabel 'agent-label':指定标签的Agentdocker 'image-name':在Docker容器中执行
groovy
pipeline {
agent none // 顶层不指定agent
stages {
stage('Build') {
agent { label 'build-agent' } // 这个阶段在build-agent上执行
steps {
sh 'mvn clean package'
}
}
stage('Test') {
agent { docker 'maven:3.8.8-openjdk-17' } // 这个阶段在Maven容器中执行
steps {
sh 'mvn test'
}
}
}
}
2. stages(阶段):
- 包含一个或多个stage(阶段)
- 每个stage代表流水线的一个步骤(如Build、Test、Deploy)
3. steps(步骤):
- 包含一个或多个步骤(如sh、echo、git等)
- 每个step代表一个具体操作
4. post(后置处理):
- 在流水线或stage结束后执行
- 可选条件:
always:总是执行success:成功时执行failure:失败时执行aborted:取消时执行
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
post {
always {
echo 'This runs always'
}
success {
echo 'This runs only on success'
}
failure {
echo 'This runs only on failure'
}
}
}
环境变量注入:environment { KEY = 'value' }
groovy
pipeline {
agent any
environment {
APP_NAME = 'spring-petclinic'
DOCKER_REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
IMAGE_TAG = "${BUILD_NUMBER}"
}
stages {
stage('Build') {
steps {
echo "Building ${APP_NAME} with tag ${IMAGE_TAG}"
sh 'mvn clean package'
}
}
}
}
环境变量优先级(从高到低):
withEnv块内定义的环境变量environment块内定义的环境变量- Jenkins全局环境变量(如
BUILD_NUMBER、JOB_NAME) - 系统环境变量
2.2 高级语法实战
条件分支:when { branch 'main' } / expression { params.env == 'PROD' }
groovy
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['DEV', 'TEST', 'PROD'], description: '部署环境')
}
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Deploy to DEV') {
when {
branch 'main'
environment name: 'ENV', value: 'DEV'
}
steps {
echo 'Deploying to DEV environment'
sh 'kubectl apply -f k8s/dev/'
}
}
stage('Deploy to PROD') {
when {
branch 'main'
environment name: 'ENV', value: 'PROD'
}
steps {
echo 'Deploying to PROD environment'
sh 'kubectl apply -f k8s/prod/'
}
}
}
}
并行执行:parallel { stage('A') { ... }; stage('B') { ... } }
groovy
pipeline {
agent any
stages {
stage('Parallel Testing') {
parallel {
stage('Unit Test') {
steps {
sh 'mvn test -Dtest=UnitTest'
}
}
stage('Integration Test') {
steps {
sh 'mvn test -Dtest=IntegrationTest'
}
}
stage('Code Quality') {
steps {
sh 'mvn sonar:sonar'
}
}
}
}
}
}
错误处理:catchError / try-catch / timeout / retry
1. catchError(捕获错误,继续执行):
groovy
pipeline {
agent any
stages {
stage('Test') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'mvn test'
}
}
}
}
}
2. try-catch(Groovy语法):
groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
script {
try {
sh 'kubectl apply -f k8s/'
} catch (Exception e) {
echo "Deployment failed: ${e}"
// 执行回滚
sh 'kubectl rollout undo deployment/app'
error "Deployment failed"
}
}
}
}
}
}
3. timeout(超时控制):
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
timeout(time: 10, unit: 'MINUTES') {
sh 'mvn clean package'
}
}
}
}
}
4. retry(重试):
groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
retry(3) {
sh 'kubectl apply -f k8s/'
}
}
}
}
}
参数化构建:parameters { string(...) } + 下拉联动(如您提供的环境-服务联动)
基础参数化构建:
groovy
pipeline {
agent any
parameters {
string(name: 'APP_VERSION', defaultValue: '1.0.0', description: '应用版本')
choice(name: 'ENV', choices: ['DEV', 'TEST', 'PROD'], description: '部署环境')
booleanParam(name: 'SKIP_TEST', defaultValue: false, description: '跳过测试')
}
stages {
stage('Build') {
steps {
echo "Building version ${params.APP_VERSION} for ${params.ENV}"
if (!params.SKIP_TEST) {
sh 'mvn test'
}
sh 'mvn clean package'
}
}
}
}
高级下拉联动(Active Choices插件):
groovy
properties([
parameters([
activeChoice(
name: 'ENVIRONMENT',
choiceType: 'SELECT',
script: activeChoiceGroovyScript(
script: '''
return ['DEV', 'TEST', 'PROD']
'''
)
),
reactiveChoice(
name: 'SERVICE',
choiceType: 'CHECKBOX',
referencedParameters: 'ENVIRONMENT',
script: reactiveChoiceGroovyScript(
script: '''
if (ENVIRONMENT == 'DEV') {
return ['app-dev-1', 'app-dev-2']
} else if (ENVIRONMENT == 'TEST') {
return ['app-test-1', 'app-test-2']
} else if (ENVIRONMENT == 'PROD') {
return ['app-prod-1', 'app-prod-2', 'app-prod-3']
}
'''
)
)
])
])
2.3 Scripted Pipeline 进阶
node / stage / script 动态控制流
groovy
node('build-agent') {
stage('Checkout') {
git url: 'https://github.com/spring-projects/spring-petclinic.git', branch: 'main'
}
stage('Build') {
sh 'mvn clean package'
}
stage('Test') {
sh 'mvn test'
}
stage('Package') {
sh 'docker build -t spring-petclinic:${BUILD_NUMBER} .'
}
}
实战:根据 Git Tag 自动触发发布流程
groovy
node('build-agent') {
// 获取Git Tag
def gitTag = sh(script: 'git describe --tags --abbrev=0', returnStdout: true).trim()
stage('Check Tag') {
if (gitTag.startsWith('v')) {
echo "Release tag detected: ${gitTag}"
} else {
echo "Not a release tag, skipping deployment"
return
}
}
stage('Build Release') {
sh "mvn clean package -Dversion=${gitTag}"
}
stage('Deploy to PROD') {
input message: '确认部署到生产环境?', ok: '确认'
sh "kubectl set image deployment/app app=spring-petclinic:${gitTag} -n prod"
}
}
与 Groovy 深度集成:自定义函数、类、异常处理
groovy
// 自定义函数
def buildImage(String appName, String version) {
sh "docker build -t ${appName}:${version} ."
sh "docker push ${appName}:${version}"
}
def deployToK8s(String namespace, String deployment, String image) {
sh "kubectl set image deployment/${deployment} ${deployment}=${image} -n ${namespace}"
sh "kubectl rollout status deployment/${deployment} -n ${namespace}"
}
node('build-agent') {
stage('Build & Deploy') {
script {
def image = "spring-petclinic:${BUILD_NUMBER}"
// 调用自定义函数
buildImage('spring-petclinic', BUILD_NUMBER)
// 部署到不同环境
if (env.BRANCH_NAME == 'main') {
deployToK8s('test', 'app', image)
// 等待审批
input message: '部署到生产环境?', ok: '确认'
deployToK8s('prod', 'app', image)
} else {
deployToK8s('dev', 'app', image)
}
}
}
}
第三部分:CI 流水线实战(代码 → 构建 → 测试)
3.1 多语言项目构建实战
Java(Maven/Gradle):跳过测试、指定 profile、上传制品
完整Jenkinsfile(Maven项目):
groovy
pipeline {
agent any
tools {
maven 'Maven3'
jdk 'JDK17'
}
environment {
APP_NAME = 'spring-petclinic'
NEXUS_URL = 'http://nexus.example.com:8081'
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/spring-projects/spring-petclinic.git', branch: 'main'
}
}
stage('Build') {
steps {
// 跳过测试,使用dev profile
sh 'mvn clean package -DskipTests -Pdev'
}
}
stage('Test') {
steps {
// 只运行单元测试
sh 'mvn test -Dtest=UnitTest*'
}
}
stage('Package') {
steps {
// 打包并上传到Nexus
sh 'mvn deploy -DskipTests'
}
}
}
post {
always {
// 归档构建产物
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
Maven关键参数详解:
-DskipTests:跳过测试编译和执行-Dmaven.test.skip=true:跳过测试编译和执行-Pdev:激活dev profile(在pom.xml中定义)mvn deploy:上传制品到远程仓库(如Nexus)
Node.js:缓存 node_modules、Linter 集成
完整Jenkinsfile(Node.js项目):
groovy
pipeline {
agent any
environment {
APP_NAME = 'vue-app'
NODE_VERSION = '18'
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/your-repo/vue-app.git', branch: 'main'
}
}
stage('Install Dependencies') {
steps {
// 缓存node_modules(加速构建)
cache(maxCacheSize: 512, caches: [
arbitraryFileCache(path: 'node_modules', includes: '**/*')
]) {
sh 'npm install'
}
}
}
stage('Lint') {
steps {
// 代码风格检查
sh 'npm run lint'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm run test:unit'
}
}
}
post {
always {
// 归档构建产物
archiveArtifacts artifacts: 'dist/**', fingerprint: true
}
}
}
企业最佳实践:
- ✅ 使用
cache步骤缓存node_modules(减少构建时间50%+) - ✅ 在
package.json中配置pre-commit钩子(配合Husky) - ✅ 使用
.npmrc配置私有NPM仓库
Python:venv 管理、pytest 报告生成
完整Jenkinsfile(Python项目):
groovy
pipeline {
agent any
environment {
APP_NAME = 'django-app'
PYTHON_VERSION = '3.11'
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/your-repo/django-app.git', branch: 'main'
}
}
stage('Setup Virtual Environment') {
steps {
sh '''
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
'''
}
}
stage('Lint') {
steps {
sh '''
source venv/bin/activate
flake8 app/
'''
}
}
stage('Test') {
steps {
sh '''
source venv/bin/activate
pytest --junitxml=test-results.xml
'''
}
}
stage('Build Docker Image') {
steps {
sh 'docker build -t django-app:${BUILD_NUMBER} .'
}
}
}
post {
always {
// 发布测试报告
junit 'test-results.xml'
}
}
}
企业技巧:构建缓存加速(cache step + NFS/S3)
使用Jenkins Cache Step:
groovy
pipeline {
agent any
stages {
stage('Build with Cache') {
steps {
cache(maxCacheSize: 512, caches: [
arbitraryFileCache(path: 'target', includes: '**/*'),
arbitraryFileCache(path: '.m2/repository', includes: '**/*')
]) {
sh 'mvn clean package'
}
}
}
}
}
使用NFS共享缓存(多Agent共享):
bash
# 在Jenkins Master上配置NFS服务器
apt-get install -y nfs-kernel-server
echo '/data/jenkins-cache *(rw,sync,no_root_squash)' >> /etc/exports
systemctl restart nfs-kernel-server
# 在所有Agent上挂载NFS
mkdir -p /data/jenkins-cache
mount -t nfs jenkins-master:/data/jenkins-cache /data/jenkins-cache
使用S3存储缓存(云环境推荐):
groovy
pipeline {
agent any
stages {
stage('Build with S3 Cache') {
steps {
withAWS(region: 'cn-hangzhou') {
s3Download(file: 'm2-repo.tar.gz', bucket: 'jenkins-cache', key: 'm2-repo.tar.gz')
sh 'tar -xzf m2-repo.tar.gz -C ~'
sh 'mvn clean package'
sh 'tar -czf m2-repo.tar.gz -C ~ .m2/repository'
s3Upload(file: 'm2-repo.tar.gz', bucket: 'jenkins-cache', key: 'm2-repo.tar.gz')
}
}
}
}
}
3.2 质量门禁实战
SonarQube 集成:质量阈值检查 + 失败拦截
1. 安装SonarQube Scanner插件
2. 配置SonarQube服务器:
Jenkins → 系统管理 → 系统配置 → SonarQube servers → 添加SonarQube
Name: SonarQube
Server URL: http://sonarqube.example.com:9000
Server authentication token: 添加凭据(Secret text类型)
3. 在Jenkinsfile中集成SonarQube:
groovy
pipeline {
agent any
tools {
sonarQubeScanner 'SonarQube Scanner'
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/your-repo/java-app.git', branch: 'main'
}
}
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Quality Gate') {
steps {
// 等待质量门禁结果,失败则中断流水线
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
}
4. 配置质量阈值(SonarQube Web UI):
SonarQube → Quality Gates → 创建质量门禁
条件:
- 覆盖率 < 80% → 失败
- 重复代码 > 5% → 失败
- 新增代码覆盖率 < 80% → 失败
- 严重漏洞 > 0 → 失败
企业最佳实践:
- ✅ 为不同类型项目配置不同的质量阈值(核心业务 vs 工具类)
- ✅ 使用
abortPipeline: true(质量不达标则中断部署) - ✅ 在PR阶段就进行SonarQube扫描(提早发现质量问题)
单元测试覆盖率报告(JaCoCo / Cobertura)
JaCoCo配置(Maven项目):
pom.xml配置:
xml
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
Jenkinsfile配置:
groovy
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Coverage Report') {
steps {
// 发布JaCoCo报告
publishCoverage adapters: [jacocoAdapter('target/site/jacoco/jacoco.xml')],
sourceFileResolver: sourceFiles('STORE_LAST_BUILD')
}
}
}
}
Cobertura配置(Python项目):
groovy
pipeline {
agent any
stages {
stage('Test') {
steps {
sh '''
source venv/bin/activate
pytest --cov=app --cov-report=xml
'''
}
}
stage('Coverage Report') {
steps {
// 发布Cobertura报告
cobertura coberturaReportFile: 'coverage.xml'
}
}
}
}
安全扫描:OWASP Dependency-Check / Snyk
OWASP Dependency-Check(开源,免费):
1. 安装OWASP Dependency-Check插件
2. Jenkinsfile配置:
groovy
pipeline {
agent any
stages {
stage('Dependency Check') {
steps {
dependencyCheck arguments: '--project "Spring PetClinic" --scan ./ --format XML',
odcInstallation: 'OWASP Dependency-Check'
}
}
stage('Publish Results') {
steps {
dependencyCheckPublisher pattern: 'dependency-check-report.xml',
failedNewCritical: '0',
failedNewHigh: '0'
}
}
}
}
Snyk(商业版,功能更强):
1. 安装Snyk Security插件
2. 配置Snyk API Token:
Jenkins → 系统管理 → 系统配置 → Snyk → 添加API Token
3. Jenkinsfile配置:
groovy
pipeline {
agent any
stages {
stage('Snyk Security Scan') {
steps {
snykSecurity failOnIssues: true,
organisation: 'your-org',
projectName: 'spring-petclinic',
snykInstallation: 'Snyk',
snykTokenId: 'snyk-api-token'
}
}
}
}
企业最佳实践:
- ✅ 在CI阶段就进行安全扫描(提早发现漏洞)
- ✅ 设置失败阈值(如:高危漏洞>0则失败)
- ✅ 定期更新漏洞数据库(OWASP Dependency-Check daily update)
关键配置:waitForQualityGate(abortPipeline: true)
groovy
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
// abortPipeline: true → 质量门禁失败则中断流水线
// abortPipeline: false → 质量门禁失败只警告,不中断流水线
waitForQualityGate abortPipeline: true
}
}
}
参数详解:
abortPipeline: true:质量门禁失败 → 流水线失败(推荐用于生产环境)abortPipeline: false:质量门禁失败 → 只记录警告,流水线继续(推荐用于开发环境)timeout:等待质量门禁结果的最长时间(防止流水线无限等待)
3.3 多环境参数化构建
下拉联动实现(Active Choice + Reactive Choice)
完整配置脚本(Groovy):
groovy
properties([
parameters([
// 第一个下拉框:选择环境
activeChoice(
name: 'ENVIRONMENT',
choiceType: 'SELECT',
description: '选择部署环境',
script: activeChoiceGroovyScript(
script: '''
// 返回环境列表
return ['DEV', 'TEST', 'PROD']
''',
fallbackScript: '''
return ['ERROR']
'''
)
),
// 第二个下拉框:根据环境选择服务(联动)
reactiveChoice(
name: 'SERVICE',
choiceType: 'CHECKBOX',
description: '选择要部署的服务(可多选)',
referencedParameters: 'ENVIRONMENT', // 引用第一个下拉框
script: reactiveChoiceGroovyScript(
script: '''
// 根据ENVIRONMENT的值返回不同的服务列表
if (ENVIRONMENT == 'DEV') {
return ['app-dev-1', 'app-dev-2', 'app-dev-3']
} else if (ENVIRONMENT == 'TEST') {
return ['app-test-1', 'app-test-2']
} else if (ENVIRONMENT == 'PROD') {
return ['app-prod-1', 'app-prod-2', 'app-prod-3']
} else {
return ['请先选择环境']
}
''',
fallbackScript: '''
return ['ERROR']
'''
)
),
// 第三个下拉框:根据环境和服务选择版本(二级联动)
reactiveChoice(
name: 'VERSION',
choiceType: 'SELECT',
description: '选择版本',
referencedParameters: ['ENVIRONMENT', 'SERVICE'], // 引用前两个下拉框
script: reactiveChoiceGroovyScript(
script: '''
// 这里可以调用API获取可用版本
// 示例:从Nexus获取可用版本
def versions = ['1.0.0', '1.0.1', '1.0.2']
return versions
''',
fallbackScript: '''
return ['ERROR']
'''
)
)
])
])
企业级实战:从外部系统获取选项
groovy
reactiveChoice(
name: 'SERVICE',
choiceType: 'SELECT',
referencedParameters: 'ENVIRONMENT',
script: reactiveChoiceGroovyScript(
script: '''
// 从CMDB系统获取服务列表
def cmdbUrl = "http://cmdb.example.com/api/services?env=${ENVIRONMENT}"
def response = new URL(cmdbUrl).text
def services = new groovy.json.JsonSlurper().parseText(response)
return services.collect { it.name }
''',
fallbackScript: '''
return ['无法连接CMDB']
'''
)
)
实战:DEV/TEST/PROD/Tenant 四环境差异化构建策略
groovy
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['DEV', 'TEST', 'PROD', 'Tenant'], description: '部署环境')
string(name: 'TENANT_ID', defaultValue: '', description: '租户ID(仅Tenant环境需要)')
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/your-repo/app.git', branch: 'main'
}
}
stage('Build') {
steps {
script {
// 根据环境使用不同的构建策略
if (params.ENVIRONMENT == 'DEV') {
// DEV环境:快速构建,跳过部分测试
sh 'mvn clean package -DskipTests -Pdev'
} else if (params.ENVIRONMENT == 'TEST') {
// TEST环境:完整构建,运行所有测试
sh 'mvn clean package -Ptest'
} else if (params.ENVIRONMENT == 'PROD') {
// PROD环境:完整构建,运行所有测试,生成文档
sh 'mvn clean package -Pprod'
sh 'mvn site'
} else if (params.ENVIRONMENT == 'Tenant') {
// Tenant环境:多租户构建,需要TENANT_ID
if (params.TENANT_ID == '') {
error 'Tenant环境需要提供TENANT_ID'
}
sh "mvn clean package -Ptenant -Dtenant.id=${params.TENANT_ID}"
}
}
}
}
stage('Deploy') {
steps {
script {
// 根据环境使用不同的部署策略
if (params.ENVIRONMENT == 'DEV') {
// DEV环境:直接部署
sh 'kubectl apply -f k8s/dev/'
} else if (params.ENVIRONMENT == 'TEST') {
// TEST环境:蓝绿部署
sh 'kubectl apply -f k8s/test/green/'
sh 'kubectl delete -f k8s/test/blue/'
} else if (params.ENVIRONMENT == 'PROD') {
// PROD环境:金丝雀发布(需要人工审批)
input message: '确认部署到生产环境?', ok: '确认'
sh 'kubectl apply -f k8s/prod/canary/'
}
}
}
}
}
}
动态 Jenkinsfile:根据 params.Environment 切换构建逻辑
方案一:在Jenkinsfile中使用条件判断(适合简单场景)
groovy
stage('Deploy') {
steps {
script {
if (params.ENVIRONMENT == 'DEV') {
sh 'deploy-dev.sh'
} else if (params.ENVIRONMENT == 'PROD') {
sh 'deploy-prod.sh'
}
}
}
}
方案二:使用共享库(Shared Library)(适合复杂场景)
├── src
│ └── org
│ └── example
│ └── Deploy.groovy // 部署逻辑
├── vars
│ └── deploy.groovy // 全局变量
└── resources
└── org
└── example
└── deploy.sh // 部署脚本
vars/deploy.groovy:
groovy
def call(String environment) {
if (environment == 'DEV') {
sh 'kubectl apply -f k8s/dev/'
} else if (environment == 'PROD') {
input message: '确认部署到生产环境?', ok: '确认'
sh 'kubectl apply -f k8s/prod/'
}
}
Jenkinsfile:
groovy
@Library('jenkins-shared-library') _
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['DEV', 'PROD'], description: '部署环境')
}
stages {
stage('Deploy') {
steps {
script {
// 调用共享库
deploy(params.ENVIRONMENT)
}
}
}
}
}
企业最佳实践:
- ✅ 环境差异配置使用配置文件(如
config/dev.properties、config/prod.properties) - ✅ 敏感配置(如数据库密码)使用Jenkins凭据管理
- ✅ 使用共享库复用部署逻辑(减少重复代码)
第四部分:CD 流水线实战(构建 → 部署 → 验证)
4.1 Docker 镜像构建与推送
多平台镜像:buildx build --platform=linux/amd64,linux/arm64
启用Docker Buildx(支持多平台构建):
bash
# 创建并使用多平台构建器
docker buildx create --name multi-platform-builder --use
docker buildx inspect --bootstrap
Jenkinsfile配置:
groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
APP_NAME = 'spring-petclinic'
IMAGE_TAG = "${BUILD_NUMBER}"
}
stages {
stage('Build Docker Image') {
steps {
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry') {
// 构建多平台镜像
sh """
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ${DOCKER_REGISTRY}/your-namespace/${APP_NAME}:${IMAGE_TAG} \
-t ${DOCKER_REGISTRY}/your-namespace/${APP_NAME}:latest \
--push .
"""
}
}
}
}
}
}
避坑指南:
- ❌ 错误:
error: failed to solve: platform linux/arm64 not found - ✅ 解决:确保Buildx构建器支持QEMU模拟(
docker buildx inspect --bootstrap)
镜像标签策略:{branch}-{commit_short}-{timestamp}
groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
APP_NAME = 'spring-petclinic'
}
stages {
stage('Generate Image Tag') {
steps {
script {
// 获取分支名
def branchName = env.BRANCH_NAME ?: 'main'
// 获取短commit hash(7位)
def commitShort = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
// 获取时间戳
def timestamp = new Date().format('yyyyMMddHHmmss', TimeZone.getTimeZone('Asia/Shanghai'))
// 生成镜像标签:{branch}-{commit_short}-{timestamp}
def imageTag = "${branchName}-${commitShort}-${timestamp}"
// 设置环境变量
env.IMAGE_TAG = imageTag
echo "镜像标签:${imageTag}"
}
}
}
stage('Build & Push') {
steps {
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry') {
sh "docker build -t ${DOCKER_REGISTRY}/your-namespace/${APP_NAME}:${env.IMAGE_TAG} ."
sh "docker push ${DOCKER_REGISTRY}/your-namespace/${APP_NAME}:${env.IMAGE_TAG}"
}
}
}
}
}
}
企业标签策略最佳实践:
- ✅ 开发环境:
{branch}-{commit_short}(如main-a1b2c3d) - ✅ 测试环境:
{version}-{build_number}(如1.0.0-123) - ✅ 生产环境:
{version}-{timestamp}(如1.0.0-20260607230000) - ✅ 标记
latest标签(方便手动部署)
私有仓库认证:Docker Credentials + withCredentials
方式一:使用Docker Pipeline插件(推荐)
groovy
pipeline {
agent any
stages {
stage('Build & Push') {
steps {
script {
// 使用Docker Pipeline插件的withRegistry方法
docker.withRegistry('https://registry.cn-hangzhou.aliyuncs.com', 'docker-registry') {
def customImage = docker.build("your-namespace/app:${BUILD_NUMBER}")
customImage.push()
}
}
}
}
}
}
方式二:使用withCredentials(更灵活)
groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
DOCKER_USERNAME = ''
DOCKER_PASSWORD = ''
}
stages {
stage('Login & Push') {
steps {
script {
// 获取Docker凭据
withCredentials([usernamePassword(credentialsId: 'docker-registry', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
// 登录Docker仓库
sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASS} ${DOCKER_REGISTRY}"
// 构建镜像
sh "docker build -t ${DOCKER_REGISTRY}/your-namespace/app:${BUILD_NUMBER} ."
// 推送镜像
sh "docker push ${DOCKER_REGISTRY}/your-namespace/app:${BUILD_NUMBER}"
// 登出Docker仓库
sh "docker logout ${DOCKER_REGISTRY}"
}
}
}
}
}
}
避坑指南:docker login 在 Agent 中失效的解决方案
问题现象:
+ docker login -u admin -p **** https://registry.cn-hangzhou.aliyuncs.com
Error response from daemon: Get "https://registry.cn-hangzhou.aliyuncs.com/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
原因分析:
- Agent无法访问Docker仓库(网络问题)
- Agent的Docker守护进程未运行
- 凭据在Agent上未正确传递
解决方案:
方案一:使用宿主机Docker(推荐)
groovy
pipeline {
agent {
docker {
image 'maven:3.8.8-openjdk-17'
args '-v /var/run/docker.sock:/var/run/docker.sock' // 挂载宿主机Docker socket
}
}
stages {
stage('Build & Push') {
steps {
script {
// 在容器内使用宿主机的Docker
sh 'docker build -t app:latest .'
}
}
}
}
}
方案二:在Agent上安装Docker
groovy
pipeline {
agent { label 'docker-agent' } // 这个Agent已安装Docker
stages {
stage('Install Docker') {
steps {
sh '''
# 安装Docker
apt-get update
apt-get install -y docker.io
systemctl start docker
systemctl enable docker
'''
}
}
stage('Build & Push') {
steps {
script {
docker.withRegistry('https://registry.cn-hangzhou.aliyuncs.com', 'docker-registry') {
sh 'docker build -t app:latest .'
}
}
}
}
}
}
方案三:使用Kaniko(无需Docker守护进程)
groovy
pipeline {
agent any
stages {
stage('Build with Kaniko') {
steps {
script {
// 使用Kaniko构建镜像(无需Docker守护进程)
sh """
/kaniko/executor \
--context `pwd` \
--dockerfile `pwd`/Dockerfile \
--destination ${DOCKER_REGISTRY}/your-namespace/app:${BUILD_NUMBER}
"""
}
}
}
}
}
4.2 Kubernetes 部署实战
方案一:kubectl set image(适用于 Deployment)
完整Jenkinsfile:
groovy
pipeline {
agent any
environment {
K8S_MASTER = 'k8s-master.example.com'
NAMESPACE = 'prod'
DEPLOYMENT = 'spring-petclinic'
IMAGE = 'registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-petclinic:${BUILD_NUMBER}'
}
stages {
stage('Deploy to K8s') {
steps {
script {
// 方式一:直接使用kubectl(需要配置kubeconfig)
sh "kubectl set image deployment/${DEPLOYMENT} ${DEPLOYMENT}=${IMAGE} -n ${NAMESPACE}"
// 等待部署完成
sh "kubectl rollout status deployment/${DEPLOYMENT} -n ${NAMESPACE}"
}
}
}
}
}
企业最佳实践:
- ✅ 使用
kubectl rollout status等待部署完成 - ✅ 设置
--timeout=5m(防止无限等待) - ✅ 部署前备份当前版本(
kubectl get deployment -o yaml > backup.yaml)
方案二:Helm Chart + helm upgrade(推荐)
项目结构:
helm-chart/
├── Chart.yaml
├── values.yaml
├── values-dev.yaml
├── values-test.yaml
├── values-prod.yaml
└── templates/
├── deployment.yaml
├── service.yaml
└── ingress.yaml
Jenkinsfile配置:
groovy
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['dev', 'test', 'prod'], description: '部署环境')
}
environment {
APP_NAME = 'spring-petclinic'
IMAGE_TAG = "${BUILD_NUMBER}"
}
stages {
stage('Package Helm Chart') {
steps {
sh """
# 更新Helm依赖
helm dependency update helm-chart/
# 打包Helm Chart
helm package helm-chart/ --version ${IMAGE_TAG}
"""
}
}
stage('Deploy with Helm') {
steps {
script {
def env = params.ENVIRONMENT
sh """
# 使用Helm升级(如果不存在则安装)
helm upgrade --install ${APP_NAME} helm-chart/ \
--namespace ${env} \
--values helm-chart/values-${env}.yaml \
--set image.tag=${IMAGE_TAG} \
--wait \
--timeout 5m
"""
}
}
}
}
}
values-prod.yaml示例:
yaml
replicaCount: 3
image:
repository: registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-petclinic
tag: "latest"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
resources:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "1"
memory: "1Gi"
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
方案三:Kubernetes Plugin(声明式部署)
1. 安装Kubernetes插件
2. 配置Kubernetes云:
Jenkins → 系统管理 → 系统配置 → Cloud → 添加Cloud → Kubernetes
Kubernetes URL: https://k8s-master:6443
Kubernetes Namespace: jenkins
Credentials: 添加kubeconfig凭据
3. Jenkinsfile配置:
groovy
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8.8-openjdk-17
command: ['cat']
tty: true
- name: docker
image: docker:24.0.5
command: ['cat']
tty: true
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
'''
}
}
stages {
stage('Build') {
steps {
container('maven') {
sh 'mvn clean package'
}
}
}
stage('Build Docker Image') {
steps {
container('docker') {
sh 'docker build -t app:latest .'
}
}
}
stage('Deploy to K8s') {
steps {
// 使用kubectl部署
sh 'kubectl apply -f k8s/'
}
}
}
}
滚动更新控制:--max-unavailable=25% --max-surge=25%
在Helm Chart中配置:
yaml
# values.yaml
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
在K8s Deployment中配置:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-petclinic
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25% # 最多25%的Pod不可用(即1个)
maxSurge: 25% # 最多额外创建25%的Pod(即1个)
template:
spec:
containers:
- name: app
image: spring-petclinic:latest
企业最佳实践:
- ✅ 生产环境建议:
maxUnavailable: 25%,maxSurge: 25%(保证服务可用性) - ✅ 开发环境建议:
maxUnavailable: 50%,maxSurge: 50%(加快部署速度) - ✅ 关键服务建议:
maxUnavailable: 0%,maxSurge: 1(滚动更新更平滑)
4.3 多环境部署策略
| 环境 | 部署方式 | 验证方式 |
|---|---|---|
| DEV | 直接更新 | 自动化 Smoke Test |
| TEST | Helm + Canary | Postman API 测试集 |
| PROD | 蓝绿部署 / 金丝雀 | 人工审批 + 监控看板 |
| Demo | 多架构镜像 + docker-compose | 页面截图验证 |
DEV环境:直接更新 + Smoke Test
groovy
stage('Deploy to DEV') {
steps {
script {
// 直接更新Deployment
sh 'kubectl set image deployment/app app=registry.cn-hangzhou.aliyuncs.com/your-namespace/app:${BUILD_NUMBER} -n dev'
// 等待部署完成
sh 'kubectl rollout status deployment/app -n dev --timeout=5m'
// 运行冒烟测试
sh 'curl -f http://app-dev.example.com/health || exit 1'
}
}
}
TEST环境:Helm + Canary + Postman测试
groovy
stage('Deploy to TEST (Canary)') {
steps {
script {
// 部署金丝雀版本(10%流量)
sh """
helm upgrade --install app-canary helm-chart/ \
--namespace test \
--values helm-chart/values-test.yaml \
--set image.tag=${BUILD_NUMBER} \
--set replicaCount=1 \
--set canary.enabled=true \
--set canary.weight=10
"""
// 等待金丝雀部署完成
sh 'kubectl rollout status deployment/app-canary -n test --timeout=5m'
// 运行Postman测试集
sh 'newman run postman/api-tests.postman_collection.json -e postman/test.postman_environment.json'
// 如果测试通过,扩大金丝雀流量到100%
sh """
helm upgrade app-canary helm-chart/ \
--namespace test \
--set canary.weight=100
"""
}
}
}
PROD环境:蓝绿部署 / 金丝雀 + 人工审批
蓝绿部署:
groovy
stage('Deploy to PROD (Blue-Green)') {
steps {
script {
// 人工审批
input message: '确认部署到生产环境?', ok: '确认'
// 部署绿色环境
sh """
helm upgrade --install app-green helm-chart/ \
--namespace prod \
--values helm-chart/values-prod.yaml \
--set image.tag=${BUILD_NUMBER}
"""
// 等待绿色环境部署完成
sh 'kubectl rollout status deployment/app-green -n prod --timeout=10m'
// 验证绿色环境
sh 'curl -f http://app-green-prod.example.com/health || exit 1'
// 切换流量到绿色环境
sh 'kubectl patch service app -n prod -p {"spec":{"selector":{"version":"green"}}}'
// 等待流量切换完成
sleep time: 30, unit: 'SECONDS'
// 验证生产环境
sh 'curl -f http://app-prod.example.com/health || exit 1'
// 删除蓝色环境
sh 'kubectl delete deployment app-blue -n prod'
}
}
}
金丝雀发布:
groovy
stage('Deploy to PROD (Canary)') {
steps {
script {
// 人工审批
input message: '确认部署金丝雀版本到生产环境?', ok: '确认'
// 部署金丝雀版本(10%流量)
sh """
kubectl apply -f k8s/prod/canary/
"""
// 等待金丝雀部署完成
sh 'kubectl rollout status deployment/app-canary -n prod --timeout=10m'
// 验证金丝雀版本
sh 'curl -f http://app-canary-prod.example.com/health || exit 1'
// 监控指标(人工观察)
input message: '请观察监控指标,确认无误后继续', ok: '继续'
// 扩大金丝雀流量到100%
sh """
kubectl patch deployment app -n prod \
-p {"spec":{"template":{"metadata":{"labels":{"version":"canary"}}}}}
"""
// 等待滚动更新完成
sh 'kubectl rollout status deployment/app -n prod --timeout=10m'
}
}
}
4.4 部署后验证与回滚
健康检查:curl -f http://svc:8080/health
groovy
stage('Health Check') {
steps {
script {
def healthCheckUrl = 'http://app-prod.example.com/health'
def maxRetries = 10
def retryInterval = 10 // 秒
for (int i = 0; i < maxRetries; i++) {
try {
sh "curl -f ${healthCheckUrl}"
echo "健康检查通过!"
break
} catch (Exception e) {
if (i == maxRetries - 1) {
error "健康检查失败,已重试${maxRetries}次"
}
echo "健康检查失败,第${i+1}次重试..."
sleep time: retryInterval, unit: 'SECONDS'
}
}
}
}
}
K8s健康检查配置(更可靠):
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
spec:
containers:
- name: app
image: app:latest
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
自动化验收测试(Cypress / Selenium)
Cypress配置(现代Web应用推荐):
groovy
stage('E2E Test with Cypress') {
steps {
script {
// 运行Cypress测试
sh '''
npm install cypress --save-dev
npx cypress run --config baseUrl=http://app-test.example.com
'''
// 发布Cypress测试报告
publishHTML([
reportDir: 'cypress/reports',
reportFiles: 'index.html',
reportName: 'Cypress Test Report',
reportTitles: ''
])
}
}
}
Selenium配置(传统Web应用):
groovy
stage('E2E Test with Selenium') {
steps {
script {
// 运行Selenium测试
sh 'mvn test -Dtest=SeleniumTest'
// 发布Selenium测试报告
publishHTML([
reportDir: 'target/surefire-reports',
reportFiles: 'index.html',
reportName: 'Selenium Test Report',
reportTitles: ''
])
}
}
}
一键回滚:记录历史镜像版本 + kubectl rollout undo
完整回滚Jenkinsfile:
groovy
pipeline {
agent any
parameters {
booleanParam(name: 'ROLLBACK', defaultValue: false, description: '是否回滚?')
}
environment {
NAMESPACE = 'prod'
DEPLOYMENT = 'spring-petclinic'
}
stages {
stage('Check Rollback Flag') {
steps {
script {
if (params.ROLLBACK) {
// 执行回滚
echo "开始回滚..."
// 查看历史版本
sh "kubectl rollout history deployment/${DEPLOYMENT} -n ${NAMESPACE}"
// 回滚到上一个版本
sh "kubectl rollout undo deployment/${DEPLOYMENT} -n ${NAMESPACE}"
// 等待回滚完成
sh "kubectl rollout status deployment/${DEPLOYMENT} -n ${NAMESPACE}"
// 验证回滚结果
sh "curl -f http://app-prod.example.com/health"
currentBuild.result = 'SUCCESS'
return
}
}
}
}
stage('Deploy') {
steps {
script {
// 记录当前版本(用于回滚)
sh "kubectl get deployment ${DEPLOYMENT} -n ${NAMESPACE} -o yaml > backup-${BUILD_NUMBER}.yaml"
// 部署新版本
sh "kubectl set image deployment/${DEPLOYMENT} ${DEPLOYMENT}=registry.cn-hangzhou.aliyuncs.com/your-namespace/app:${BUILD_NUMBER} -n ${NAMESPACE}"
// 等待部署完成
sh "kubectl rollout status deployment/${DEPLOYMENT} -n ${NAMESPACE}"
}
}
}
}
}
使用Helm回滚(更简单):
bash
# 查看Helm发布历史
helm history app -n prod
# 回滚到指定版本
helm rollback app 1 -n prod
# 回滚到上一个版本
helm rollback app 0 -n prod
企业最佳实践:
- ✅ 每次部署前自动备份当前版本(
kubectl get deployment -o yaml > backup.yaml) - ✅ 在Jenkins中提供"一键回滚"按钮(参数化构建)
- ✅ 回滚后自动验证服务健康状态
- ✅ 记录回滚原因(方便事后分析)
第五部分:高可用与企业级进阶
5.1 Jenkins 高可用架构
主从模式:Master 负载均衡 + Agent 弹性伸缩(K8s Pod as Agent)
架构图:
┌─────────────────────────────────────────────────────────────┐
│ 负载均衡(HAProxy/Nginx) │
│ (VIP:192.168.0.100) │
└─────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Jenkins Master 1 │ │ Jenkins Master 2 │
│ (Active) │ │ (Standby) │
└──────────────────┘ └──────────────────┘
│ │
└───────────┬─────────────┘
▼
┌──────────────────────────────┐
│ 共享存储(NFS/Ceph) │
│ /var/jenkins_home │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ K8s 动态 Agent │
│ (Pod 自动创建/销毁) │
└──────────────────────────────┘
配置步骤:
1. 配置共享存储(NFS):
bash
# 在Master节点上安装NFS服务器
apt-get install -y nfs-kernel-server
# 配置共享目录
echo '/data/jenkins_home *(rw,sync,no_root_squash)' >> /etc/exports
# 重启NFS服务
systemctl restart nfs-kernel-server
# 在所有Jenkins Master节点上挂载NFS
mkdir -p /data/jenkins_home
mount -t nfs nfs-server:/data/jenkins_home /data/jenkins_home
2. 配置K8s云(动态Pod Agent):
Jenkins → 系统管理 → 系统配置 → Cloud → 添加Cloud → Kubernetes
- Kubernetes URL :
https://k8s-master:6443 - Kubernetes Namespace :
jenkins - Credentials: 添加K8s凭据(Secret file类型,上传kubeconfig)
- Jenkins URL :
http://jenkins-master:8080 - Pod Template :
- Name :
jnlp-agent - Docker image :
jenkins/inbound-agent:latest - Working directory :
/home/jenkins/agent
- Name :
3. 配置Pod模板(支持Docker构建):
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins: agent
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:latest
resources:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "1"
memory: "1Gi"
- name: docker
image: docker:24.0.5
command: ['cat']
tty: true
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
共享存储:Jenkins Home 挂载 NFS / S3
方式一:挂载NFS(推荐用于本地机房):
bash
# 在所有Jenkins Master节点上执行
mkdir -p /data/jenkins_home
mount -t nfs nfs-server:/data/jenkins_home /data/jenkins_home
# 配置开机自动挂载
echo 'nfs-server:/data/jenkins_home /data/jenkins_home nfs defaults 0 0' >> /etc/fstab
# 启动Jenkins时指定JENKINS_HOME
docker run -d \
--name jenkins \
-p 8080:8080 \
-v /data/jenkins_home:/var/jenkins_home \
--restart=always \
jenkins/jenkins:lts
方式二:使用S3存储(推荐用于云环境):
bash
# 安装S3插件(S3 Artifact Storage Plugin)
# 配置S3存储
# Jenkins → 系统管理 → 系统配置 → S3 Profile
# Profile Name: s3-jenkins
# Bucket Name: jenkins-artifacts
# Credentials: 添加AWS Access Key凭据
企业最佳实践:
- ✅ 生产环境必须使用共享存储(防止单点故障)
- ✅ 定期备份Jenkins Home(每天定时备份到S3/NAS)
- ✅ 使用SSD存储(提高Jenkins性能)
备份恢复:backup-plugin + 定时快照
安装ThinBackup插件(推荐):
Jenkins → 系统管理 → 插件管理 → 搜索ThinBackup → 安装
配置ThinBackup:
Jenkins → 系统管理 → ThinBackup Settings
- Backup directory :
/data/jenkins_backup - Backup schedule :
0 2 * * *(每天凌晨2点备份) - Max number of backup sets :
7(保留7天备份) - Excluded files :
workspace/**, builds/**(排除工作空间和构建记录)
手动备份/恢复:
bash
# 手动备份
docker exec jenkins java -jar /var/jenkins_home/war/WEB-INF/jenkins-cli.jar \
-s http://localhost:8080 \
-auth admin:Admin@123456 \
thinBackupPerformBackup
# 恢复备份
docker exec jenkins java -jar /var/jenkins_home/war/WEB-INF/jenkins-cli.jar \
-s http://localhost:8080 \
-auth admin:Admin@123456 \
thinBackupRestore
企业级备份策略:
┌──────────────────────────────────────────────┐
│ 备份策略 │
├──────────────────────────────────────────────┤
│ 1. 每天凌晨2点全量备份(ThinBackup) │
│ 2. 备份文件上传到S3(跨地域容灾) │
│ 3. 保留30天备份(符合等保要求) │
│ 4. 每月进行一次恢复演练(验证备份有效性) │
└──────────────────────────────────────────────┘
5.2 安全加固实战
最小权限原则:Agent 使用非 root 用户
Docker Agent配置(非root用户):
dockerfile
# Dockerfile-agent
FROM jenkins/inbound-agent:latest
# 切换到root用户安装依赖
USER root
# 安装构建工具
RUN apt-get update && apt-get install -y \
maven \
nodejs \
npm \
python3 \
&& rm -rf /var/lib/apt/lists/*
# 创建非root用户
RUN useradd -m -u 1000 builder && \
chown -R builder:builder /home/jenkins
# 切换回非root用户
USER builder
WORKDIR /home/jenkins/agent
K8s Pod Agent配置(非root用户):
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins: agent
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: jnlp
image: your-registry/jenkins-agent:latest
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
企业最佳实践:
- ✅ Agent必须使用非root用户运行(防止容器逃逸)
- ✅ 禁用特权容器(
privileged: false) - ✅ 使用只读根文件系统(
readOnlyRootFilesystem: true)
敏感信息管理:credentials-binding + withCredentials
方式一:使用credentials-binding插件(推荐):
groovy
pipeline {
agent any
environment {
// 绑定SSH Key凭据
SSH_KEY = credentials('git-ssh-key')
// 绑定Username/Password凭据
DB_PASSWORD = credentials('db-password')
// 绑定Secret text凭据
API_TOKEN = credentials('api-token')
}
stages {
stage('Use Credentials') {
steps {
// SSH_KEY包含SSH_KEY_USR和SSH_KEY_PSW(实际上SSH_KEY是私钥文件路径)
sh 'ssh -i $SSH_KEY user@server'
// DB_PASSWORD包含DB_PASSWORD_USR和DB_PASSWORD_PSW
sh 'echo "Password: $DB_PASSWORD_PSW"'
// API_TOKEN是Secret text
sh 'curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com'
}
}
}
}
方式二:使用withCredentials步骤:
groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'git-ssh-key', keyFileVariable: 'SSH_KEY')]) {
sh 'ssh -i $SSH_KEY user@server'
}
withCredentials([usernamePassword(credentialsId: 'db-password', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASS')]) {
sh 'mysql -u $DB_USER -p$DB_PASS -e "SHOW DATABASES;"'
}
}
}
}
}
企业最佳实践:
- ✅ 所有敏感信息(密码、Token、密钥)必须存储在Jenkins凭据中
- ✅ 禁止使用明文密码(如
sh 'mysql -u root -p123456') - ✅ 定期轮换凭据(每90天)
审计日志:audit-trail-plugin
安装audit-trail-plugin:
Jenkins → 系统管理 → 插件管理 → 搜索audit-trail → 安装
配置审计日志:
Jenkins → 系统管理 → 系统配置 → Audit Trail
- Log File :
/var/jenkins_home/logs/audit.log - Log Events: 勾选所有事件(用户登录、任务创建、构建触发等)
审计日志示例:
2026-06-07 23:30:15 +0800 INFO admin Login succeeded /jenkins/login
2026-06-07 23:31:20 +0800 INFO admin Build triggered /jenkins/job/spring-petclinic/build
2026-06-07 23:32:15 +0800 INFO admin Configuration changed /jenkins/configure
企业最佳实践:
- ✅ 启用审计日志(符合等保要求)
- ✅ 审计日志定期归档到S3/ELK
- ✅ 设置日志告警(如:异常时间登录、敏感操作)
防止脚本注入:禁用 script step(仅允许 Declarative)
方式一:使用Pipeline: Groovy Plugin 的安全选项:
Jenkins → 系统管理 → 系统配置 → Pipeline: Groovy Script → 启用脚本安全
方式二:使用Declarative Pipeline Only插件:
Jenkins → 系统管理 → 插件管理 → 搜索Declarative Pipeline Only → 安装
配置后效果:
- ❌ 禁止使用
script步骤(Groovy脚本) - ✅ 只允许使用Declarative语法
- ✅ 防止恶意Groovy脚本执行
企业最佳实践:
- ✅ 生产环境禁用Scripted Pipeline(防止脚本注入)
- ✅ 使用Shared Library复用逻辑(而不是在Jenkinsfile中写Groovy)
- ✅ 启用Pipeline Linter(检查Jenkinsfile语法)
5.3 性能优化与监控
构建耗时分析:Performance Plugin
安装Performance Plugin:
Jenkins → 系统管理 → 插件管理 → 搜索Performance → 安装
在Jenkinsfile中配置:
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
post {
always {
// 收集构建性能数据
performanceReport parsers: [junitParser(operation: 'Add', glob: 'target/surefire-reports/*.xml')]
// 生成性能趋势图
publishPerformanceReport sourceDataFiles: 'target/surefire-reports/*.xml', mode: 'ByBuild'
}
}
}
分析构建耗时:
Jenkins → 任务页面 → 性能报告 → 查看构建耗时趋势
资源监控:Prometheus + Grafana 接入 Jenkins Metrics
1. 安装Prometheus Plugin:
Jenkins → 系统管理 → 插件管理 → 搜索Prometheus → 安装
2. 配置Prometheus Plugin:
Jenkins → 系统管理 → 系统配置 → Prometheus
- URL :
/prometheus - Collect disk usage: 勾选
- Collect offline executors: 勾选
3. 配置Prometheus抓取Jenkins指标:
yaml
# prometheus.yml
scrape_configs:
- job_name: 'jenkins'
metrics_path: '/prometheus'
static_configs:
- targets: ['jenkins-master:8080']
4. 导入Grafana仪表盘:
- 下载Jenkins Grafana仪表盘JSON:https://grafana.com/grafana/dashboards/9964
- 导入到Grafana
关键监控指标:
| 指标 | 说明 | 告警阈值 |
|---|---|---|
jenkins_builds_total |
构建总数 | - |
jenkins_builds_success_total |
成功构建数 | - |
jenkins_builds_failure_total |
失败构建数 | > 10% |
jenkins_build_duration_seconds |
构建耗时 | > 10分钟 |
jenkins_executors_total |
执行器总数 | - |
jenkins_executors_busy |
忙碌执行器数 | > 80% |
流水线优化:并行阶段、缓存复用、轻量 Agent
优化一:并行执行阶段:
groovy
pipeline {
agent any
stages {
stage('Parallel Testing') {
parallel {
stage('Unit Test') {
steps {
sh 'mvn test -Dtest=UnitTest'
}
}
stage('Integration Test') {
steps {
sh 'mvn test -Dtest=IntegrationTest'
}
}
stage('Code Quality') {
steps {
sh 'mvn sonar:sonar'
}
}
}
}
}
}
优化二:缓存复用:
groovy
pipeline {
agent any
stages {
stage('Build with Cache') {
steps {
cache(maxCacheSize: 512, caches: [
arbitraryFileCache(path: '.m2/repository', includes: '**/*'),
arbitraryFileCache(path: 'node_modules', includes: '**/*')
]) {
sh 'mvn clean package'
}
}
}
}
}
优化三:使用轻量Agent:
groovy
pipeline {
agent {
docker {
image 'maven:3.8.8-openjdk-17-alpine' // 使用Alpine版本(更小)
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
}
企业最佳实践:
- ✅ 并行执行独立任务(测试、代码扫描等)
- ✅ 使用缓存(Maven本地仓库、Node modules等)
- ✅ 使用轻量级Agent镜像(Alpine版本)
- ✅ 定期清理旧构建记录(保留30天)
第六部分:真实企业案例合集
案例一:金融系统灰度发布流水线
环境:DEV → UAT → PRE → PROD
流水线设计:
┌─────────────────────────────────────────────────────────────┐
│ 金融系统部署流水线 │
├─────────────────────────────────────────────────────────────┤
│ 1. 代码提交 → 触发CI流水线 │
│ 2. CI流水线:构建 → 测试 → 打包 → 推送镜像 │
│ 3. CD流水线: │
│ ├─ DEV环境:自动部署(kubectl) │
│ ├─ UAT环境:人工审批 + 部署(Helm) │
│ ├─ PRE环境:人工审批 + 金丝雀部署(10%流量) │
│ └─ PROD环境:人工审批 + 蓝绿部署 + 监控 │
└─────────────────────────────────────────────────────────────┘
Jenkinsfile(关键部分):
groovy
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['DEV', 'UAT', 'PRE', 'PROD'], description: '部署环境')
}
stages {
stage('Build & Test') {
steps {
sh 'mvn clean package'
sh 'mvn test'
sh 'docker build -t app:${BUILD_NUMBER} .'
sh 'docker push registry.example.com/app:${BUILD_NUMBER}'
}
}
stage('Deploy to DEV') {
when {
environment name: 'ENVIRONMENT', value: 'DEV'
}
steps {
sh 'kubectl set image deployment/app app=registry.example.com/app:${BUILD_NUMBER} -n dev'
sh 'kubectl rollout status deployment/app -n dev --timeout=5m'
}
}
stage('Deploy to UAT') {
when {
environment name: 'ENVIRONMENT', value: 'UAT'
}
steps {
input message: '确认部署到UAT环境?', ok: '确认'
sh 'helm upgrade --install app helm-chart/ --namespace uat --set image.tag=${BUILD_NUMBER}'
}
}
stage('Deploy to PRE (Canary)') {
when {
environment name: 'ENVIRONMENT', value: 'PRE'
}
steps {
input message: '确认部署金丝雀版本到PRE环境?', ok: '确认'
// 部署金丝雀版本(10%流量)
sh 'kubectl apply -f k8s/pre/canary/'
sh 'kubectl rollout status deployment/app-canary -n pre --timeout=10m'
// 验证金丝雀版本
sh 'curl -f http://app-canary-pre.example.com/health'
// 观察监控指标
input message: '请观察监控指标,确认无误后继续', ok: '继续'
// 扩大流量到100%
sh 'kubectl patch deployment app -n pre -p {"spec":{"template":{"metadata":{"labels":{"version":"canary"}}}}}'
}
}
stage('Deploy to PROD (Blue-Green)') {
when {
environment name: 'ENVIRONMENT', value: 'PROD'
}
steps {
input message: '确认部署到生产环境?', ok: '确认'
// 部署绿色环境
sh 'helm upgrade --install app-green helm-chart/ --namespace prod --set image.tag=${BUILD_NUMBER}'
sh 'kubectl rollout status deployment/app-green -n prod --timeout=10m'
// 验证绿色环境
sh 'curl -f http://app-green-prod.example.com/health'
// 切换流量到绿色环境
sh 'kubectl patch service app -n prod -p {"spec":{"selector":{"version":"green"}}}'
// 观察30秒
sleep time: 30, unit: 'SECONDS'
// 验证生产环境
sh 'curl -f http://app-prod.example.com/health'
// 删除蓝色环境
sh 'helm uninstall app-blue -n prod'
}
}
}
}
特色:人工审批网关 + 流量切分(Istio) + 熔断机制
1. 人工审批网关:
- 使用Jenkins的
input步骤实现人工审批 - 审批人:开发Leader + 运维Leader(双审批)
- 审批记录:自动发送到企业微信/钉钉
2. 流量切分(Istio):
yaml
# Istio VirtualService配置(金丝雀发布)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: app
spec:
hosts:
- app-prod.example.com
http:
- route:
- destination:
host: app.prod.svc.cluster.local
subset: stable
weight: 90
- destination:
host: app.prod.svc.cluster.local
subset: canary
weight: 10
3. 熔断机制(Istio):
yaml
# Istio DestinationRule配置(熔断)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: app
spec:
host: app.prod.svc.cluster.local
trafficPolicy:
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30m
案例二:微服务多模块协同构建
问题:A 服务依赖 B 服务 SNAPSHOT 版本
场景描述:
- 服务A依赖服务B的SNAPSHOT版本(
1.0.0-SNAPSHOT) - 服务B更新后,服务A需要重新构建(但Nexus缓存导致服务A无法获取最新SNAPSHOT)
解决方案:
1. 使用Maven Repository Proxy:
xml
<!-- pom.xml -->
<repositories>
<repository>
<id>nexus-snapshots</id>
<url>http://nexus.example.com/repository/maven-snapshots/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy> <!-- 每次构建都检查最新SNAPSHOT -->
</snapshots>
</repository>
</repositories>
2. 配置Nexus仓库更新策略:
Nexus → Repository → Repositories → maven-snapshots → Configuration
- Snapshot Policy :
Unique - Refresh Period :
1 minute
3. 在Jenkinsfile中强制更新依赖:
groovy
pipeline {
agent any
stages {
stage('Build Service A') {
steps {
// 强制更新SNAPSHOT依赖
sh 'mvn clean package -U'
}
}
}
}
解决:Maven Repository Proxy + mvn deploy 到 Nexus
完整Jenkinsfile(多模块协同构建):
groovy
pipeline {
agent any
tools {
maven 'Maven3'
jdk 'JDK17'
}
stages {
stage('Build Service B') {
steps {
dir('service-b') {
sh 'mvn clean deploy -DskipTests'
}
}
}
stage('Build Service A') {
steps {
dir('service-a') {
// 等待Service B部署完成
sleep time: 10, unit: 'SECONDS'
// 强制更新SNAPSHOT依赖
sh 'mvn clean package -U'
}
}
}
}
}
使用Jenkins Pipeline的build步骤触发下游任务:
groovy
pipeline {
agent any
stages {
stage('Build Service B') {
steps {
sh 'mvn clean deploy -DskipTests'
}
}
}
post {
success {
// 触发Service A的构建
build job: 'service-a-build', wait: false
}
}
}
案例三:边缘计算设备 OTA 更新
场景:ARM 设备集群(IoT)
场景描述:
- 1000+ ARM架构的边缘设备(如智能网关、工业控制器)
- 需要定期更新设备上的应用(OTA更新)
- 设备分布在全国各地,网络不稳定
方案:Jenkins 构建 multi-arch 镜像 → MQTT 推送更新指令 → 设备自动拉取
1. Jenkins构建多架构镜像:
groovy
pipeline {
agent any
stages {
stage('Build Multi-Arch Image') {
steps {
sh '''
# 启用Buildx
docker buildx create --name multi-arch-builder --use
docker buildx inspect --bootstrap
# 构建多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
-t registry.example.com/iot-app:${BUILD_NUMBER} \
--push .
'''
}
}
}
}
2. 推送更新指令到MQTT Broker:
groovy
pipeline {
agent any
stages {
stage('Push OTA Update Command') {
steps {
script {
// 使用MQTT Plugin推送更新指令
def mqttCommand = """
{
"version": "${BUILD_NUMBER}",
"image": "registry.example.com/iot-app:${BUILD_NUMBER}",
"checksum": "${sha256sum('Dockerfile')}"
}
"""
// 发布到MQTT主题
mqttPublish(topic: 'iot/ota/update', message: mqttCommand)
}
}
}
}
}
3. 边缘设备自动拉取更新:
python
# 边缘设备上的OTA更新客户端(Python)
import paho.mqtt.client as mqtt
import subprocess
import json
def on_message(client, userdata, msg):
payload = json.loads(msg.payload)
version = payload['version']
image = payload['image']
# 拉取新镜像
subprocess.run(['docker', 'pull', image])
# 停止旧容器
subprocess.run(['docker', 'stop', 'iot-app'])
# 启动新容器
subprocess.run(['docker', 'run', '-d', '--name', 'iot-app', image])
# 上报更新结果
client.publish('iot/ota/status', json.dumps({'version': version, 'status': 'success'}))
client = mqtt.Client()
client.on_message = on_message
client.connect('mqtt-broker.example.com', 1883, 60)
client.subscribe('iot/ota/update')
client.loop_forever()
企业最佳实践:
- ✅ 使用多架构镜像(支持不同CPU架构的设备)
- ✅ OTA更新前验证镜像Checksum(防止篡改)
- ✅ 支持灰度更新(先更新10%设备,验证通过后再全量更新)
- ✅ OTA更新失败时自动回滚(设备上有旧版本镜像备份)
附录:必备工具包
📦 模板库:
1. Jenkinsfile.template(Java/Node/Python 通用版)
groovy
pipeline {
agent any
tools {
maven 'Maven3'
jdk 'JDK17'
}
environment {
APP_NAME = 'your-app'
DOCKER_REGISTRY = 'registry.example.com'
IMAGE_TAG = "${BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
git url: 'https://github.com/your-repo/your-app.git', branch: 'main'
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Build Docker Image') {
steps {
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry') {
def customImage = docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}")
customImage.push()
}
}
}
}
stage('Deploy to DEV') {
steps {
sh 'kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG} -n dev'
sh 'kubectl rollout status deployment/${APP_NAME} -n dev --timeout=5m'
}
}
}
post {
always {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
junit 'target/surefire-reports/*.xml'
}
success {
echo '构建成功!'
}
failure {
echo '构建失败!'
// 发送通知到企业微信/钉钉
emailext subject: '构建失败:${JOB_NAME} #${BUILD_NUMBER}',
body: '请检查构建日志:${BUILD_URL}',
to: 'dev-team@example.com'
}
}
}
2. docker-compose.yml(本地调试环境)
yaml
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- JAVA_OPTS=-Xmx2g -Xms2g
restart: always
gitlab:
image: gitlab/gitlab-ee:latest
container_name: gitlab
ports:
- "80:80"
- "443:443"
- "22:22"
volumes:
- gitlab_config:/etc/gitlab
- gitlab_logs:/var/log/gitlab
- gitlab_data:/var/opt/gitlab
restart: always
sonarqube:
image: sonarqube:latest
container_name: sonarqube
ports:
- "9000:9000"
volumes:
- sonarqube_data:/opt/sonarqube/data
environment:
- SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
restart: always
volumes:
jenkins_home:
gitlab_config:
gitlab_logs:
gitlab_data:
sonarqube_data:
3. sonar-project.properties(SonarQube 配置)
properties
# 项目Key(唯一)
sonar.projectKey=your-app
# 项目名称
sonar.projectName=Your App
# 项目版本
sonar.projectVersion=1.0.0
# 源代码编码
sonar.sourceEncoding=UTF-8
# 源代码目录
sonar.sources=src/main/java
# 测试代码目录
sonar.tests=src/test/java
# 排除的文件
sonar.exclusions=**/generated/**,**/*.generated.java
# 语言
sonar.language=java
# Java版本
sonar.java.source=17
# 覆盖率报告路径
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
# 测试报告路径
sonar.junit.reportsPath=target/surefire-reports
📊 检查清单:
1. CI/CD 流水线健康度评分表(10 项指标)
| 指标 | 权重 | 评分标准 | 得分 |
|---|---|---|---|
| 构建成功率 | 20% | > 95%: 10分; 90-95%: 8分; < 90%: 0分 | |
| 构建耗时 | 15% | < 5分钟: 10分; 5-10分钟: 8分; > 10分钟: 0分 | |
| 测试覆盖率 | 15% | > 80%: 10分; 60-80%: 8分; < 60%: 0分 | |
| 代码质量 | 10% | SonarQube无严重问题: 10分; 有严重问题: 0分 | |
| 安全扫描 | 10% | 无高危漏洞: 10分; 有高危漏洞: 0分 | |
| 部署频率 | 10% | 每天多次: 10分; 每周一次: 8分; 每月一次: 0分 | |
| 回滚时间 | 10% | < 5分钟: 10分; 5-15分钟: 8分; > 15分钟: 0分 | |
| 监控覆盖率 | 5% | 100%服务有监控: 10分; 80-100%: 8分; < 80%: 0分 | |
| 文档完整性 | 3% | 有完整文档: 10分; 有部分文档: 8分; 无文档: 0分 | |
| 团队协作 | 2% | 多人协作顺畅: 10分; 有协作问题: 0分 |
总分计算 :总分 = Σ(各项得分 × 权重)
健康度评级:
- A级(90-100分):优秀,无需改进
- B级(70-89分):良好,需小幅改进
- C级(50-69分):合格,需大幅改进
- D级(<50分):不合格,需立即整改
2. 安全合规 checklist(GDPR/等保)
GDPR合规检查清单:
- 个人数据加密存储(数据库字段加密)
- 个人数据传输加密(HTTPS/TLS)
- 数据访问日志记录(谁访问了哪些数据)
- 数据导出功能(用户可导出自己的数据)
- 数据删除功能(用户可删除自己的数据)
- Cookie使用告知(弹窗告知用户)
- 隐私政策页面(明确说明数据用途)
等保2.0三级合规检查清单:
- 身份鉴别(双因素认证)
- 访问控制(基于角色的权限管理)
- 安全审计(所有操作有日志记录)
- 入侵防范(防火墙、WAF)
- 数据完整性(数据备份、校验)
- 数据保密性(敏感数据加密)
- 数据备份恢复(每天备份、定期恢复演练)
- 个人信息保护(脱敏处理)
🎯 学习路径图:
┌─────────────────────────────────────────────────────────────┐
│ Jenkins CI/CD 学习路径 │
├─────────────────────────────────────────────────────────────┤
│ 阶段1:入门(1-2周) │
│ ├─ Jenkins安装与配置 │
│ ├─ Freestyle Project使用 │
│ └─ Pipeline基础语法 │
│ │
│ 阶段2:进阶(2-4周) │
│ ├─ Declarative Pipeline语法 │
│ ├─ 多分支流水线 │
│ ├─ SonarQube集成 │
│ └─ Docker集成 │
│ │
│ 阶段3:高级(1-2个月) │
│ ├─ Kubernetes集成(动态Pod Agent) │
│ ├─ Helm部署 │
│ ├─ 蓝绿部署/金丝雀发布 │
│ └─ Shared Library │
│ │
│ 阶段4:专家(3-6个月) │
│ ├─ Jenkins性能优化 │
│ ├─ 高可用架构 │
│ ├─ 安全加固 │
│ ├─ 企业级最佳实践 │
│ └─ GitOps(Argo CD) │
└─────────────────────────────────────────────────────────────┘
推荐学习资源:
- 官方文档:https://www.jenkins.io/doc/
- Pipeline语法参考:https://www.jenkins.io/doc/book/pipeline/syntax/
- 企业级案例:https://www.jenkins.io/blog/
- 推荐书籍:《Jenkins 2权威指南》、《持续交付》
💡 每篇结尾设置:
「今日挑战」:
- 改造你的 Jenkinsfile,支持按 commit message 触发不同构建策略(如:commit message包含
[skip ci]则跳过构建) - 实现Jenkinsfile的自动生成工具(根据项目类型自动生成Jenkinsfile)
- 配置Jenkins的异地容灾(主备Jenkins,自动切换)
「企业真题」:
- 某大厂面试题:如何在 Jenkins 中实现构建失败自动通知企业微信?
- 答案 :使用
post步骤的failure条件,调用企业微信Webhook发送通知。
- 某大厂面试题:如何优化Jenkins的构建性能?
- 答案:并行执行、缓存复用、轻量Agent、定期清理旧构建。
- 某大厂面试题:如何实现Jenkins的高可用?
- 答案:主从模式+共享存储+负载均衡。
「彩蛋视频」:
- 关键操作录屏(如下拉联动配置、K8s 部署调试)
- 企业级流水线实战演示
- Jenkins性能优化实战
总结
本文从零开始,详细介绍了Jenkins CI/CD的全流程实战,包括:
- 基础篇:Jenkins安装、配置、插件管理
- 语法篇:Declarative Pipeline语法、高级特性
- CI篇:多语言项目构建、质量门禁、参数化构建
- CD篇:Docker镜像构建、K8s部署、多环境策略
- 进阶篇:高可用架构、安全加固、性能优化
- 实战篇:金融系统、微服务、IoT等真实案例
所有内容均基于企业级最佳实践,可直接应用于生产环境。
下一步学习建议:
- 学习GitOps(Argo CD、Flux CD)
- 学习Serverless CI/CD(GitHub Actions、GitLab CI)
- 学习云原生CI/CD(Tekton、Jenkins X)
文档版本 :v1.0
最后更新 :2026-06-07
作者 :基于华为云ECS实战环境编写
适用版本:Jenkins 2.4+ LTS
版权声明:本文档仅供学习交流使用,未经授权不得用于商业用途。