Jenkins Pipeline 实战指南:从基础到 K8s 生产环境
Jenkins Pipeline 核心指南 本文全面解析Jenkins Pipeline的核心组件与实用技巧: 核心架构: Agent:支持any/none/label三种模式指定执行节点 Post:定义构建后操作,支持always/changed/failure等状态判断 Stages:构建流程阶段划分,至少包含一个stage 关键指令: Environment:管理环境变量,支持credent
阅读信息
- 预计阅读时间:15-20分钟
- 主要内容:
- Jenkins Pipeline 核心概念与基本架构
- 常用指令与全局变量详解
- 生产环境 K8s 流水线完整示例
- 现代 CI/CD 环境集成方案
- 最佳实践与性能优化建议
关注公众号 键盘下的小宇宙 并回复关键字 “视频资料”,即可获取我们整理的 Kubernetes、Docker 容器、Python 编程、Linux 运维等教学视频合集(总计 548GB)。本资源仅面向学习交流使用,请遵守版权和使用规范,严禁商用、转售或违规传播。
Jenkins Pipeline 完整指南
1. 概述
本文提供了 Jenkins Pipeline 的全面指南,涵盖核心概念、常用指令、最佳实践以及现代 CI/CD 环境的集成方案。
2. 核心概念
2.1 Agent(代理)
Agent 指令指定 Jenkins Pipeline 在哪里执行,支持以下参数:
- any:在任何可用节点上执行 pipeline
- none:未指定 agent 时的默认值
- label:在指定标签的节点上运行 pipeline
agent {
node {
label "master" // 指定运行节点的名称或者标签
customWorkspace "${workspace}" // 执行运行的工作目录(可选)
}
}
2.2 Post
Post 代码块定义了流水线运行完成后的操作,其执行取决于流水线的完成状态:
- always:无论流水线或阶段完成状态如何都运行
- changed:只有当流水线或阶段完成状态与之前不同时才运行
- failure:只有当流水线状态为 failure 时才运行
- success:只有当流水线状态为 success 时才运行
- aborted:只有当流水线状态为 aborted(手动取消)时才运行
post {
always {
script {
println("总是执行脚本片段")
}
}
success {
script {
currentBuild.description += "\n 构建成功"
}
}
failure {
script {
currentBuild.description += "\n 构建失败"
}
}
aborted {
script {
currentBuild.description += "\n 构建取消"
}
}
}
2.3 Stages
Stages 包含一系列一个或多个 stage 指令,用于定义连续交付流程中的各个阶段,如构建、测试和部署。每个 pipeline 必须至少包含一个 stage。
stages {
// 下载代码
stage("GetCode") {
steps {
timeout(time: 5, unit: "MINUTES") {
script {
println('获取代码')
}
}
}
}
}
3. 指令与全局变量
3.1 Environment
Environment 指令指定键值对序列,这些键值对将被定义为所有步骤的环境变量,或特定于阶段的步骤,具体取决于 environment 指令在流水线内的位置。
该指令支持一个特殊的 credentials() 方法,用于在 Jenkins 环境中通过标识符访问预定义的凭证:
- 对于类型为 “Secret Text” 的凭证,
credentials()将确保指定的环境变量包含秘密文本内容 - 对于类型为 “Standard username and password” 的凭证,指定的环境变量格式为
username:password,并自动定义两个额外的环境变量:MYVARNAME_USR和MYVARNAME_PSW
pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
AN_ACCESS_KEY = credentials('my-prefined-secret-text')
}
steps {
sh 'printenv'
}
}
}
}
3.2 Options
Options 指令允许从流水线内部配置特定于流水线的选项:
- buildDiscarder:为最近的流水线运行的特定数量保存组件和控制台输出
- disableConcurrentBuilds:不允许同时执行流水线,可用于防止同时访问共享资源等
- overrideIndexTriggers:允许覆盖分支索引触发器的默认处理
- skipDefaultCheckout:在 agent 指令中,跳过从源代码控制中检出代码的默认情况
- skipStagesAfterUnstable:一旦构建状态变得 UNSTABLE,跳过该阶段
- checkoutToSubdirectory:在工作空间的子目录中自动执行源代码控制检出
- timeout:设置流水线运行的超时时间,在此之后 Jenkins 将中止流水线
- retry:在失败时,重新尝试整个流水线的指定次数
- timestamps:为所有由流水线生成的控制台输出添加时间戳
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('Example') {
steps {
echo 'hello world'
}
}
}
}
3.3 Parameters
Parameters 指令为流水线运行时添加相关的参数:
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '部署环境')
}
3.4 Triggers
Triggers 指令定义了流水线的触发方式:
-
cron:计划任务定期执行构建
triggers { cron('H */4 * * 1-5') } -
pollSCM:与 cron 定义类似,但是由 Jenkins 定期检测源码变化
triggers { pollSCM('H */4 * * 1-5') } -
upstream:接受逗号分隔的任务字符串和阈值,当字符串中的任何作业以最小阈值结束时,流水线被重新触发
triggers { upstream(upstreamProjects: 'job1, job2', threshold: hudson.model.Result.SUCCESS) }
3.5 Tool
Tool 指令获取通过自动安装或手动放置的工具的环境变量,支持 Maven、JDK 等。工具的名称必须在系统设置 -> 全局工具配置中定义:
pipeline {
agent any
tools {
maven 'mvn391'
}
stages {
stage('Example') {
steps {
sh 'mvn --version'
}
}
}
}
3.6 Input
Input 指令允许在执行各个阶段时,由人工确认是否继续进行:
- message:呈现给用户的提示信息
- id:可选,默认为 stage 名称
- ok:默认表单上的 “OK” 文本
- submitter:可选的,以逗号分隔的用户列表或允许提交的外部组名,默认允许任何用户
- submitterParameter:环境变量的可选名称,如果存在则用 submitter 名称设置
- parameters:提示提交者提供的一个可选的参数列表
input id: 'Test',
message: '是否要继续',
ok: '是,继续吧!',
parameters: [choice(choices: ['A', 'B'], name: 'test1')],
submitter: 'wangwl'
3.7 When
When 指令允许流水线根据给定的条件决定是否应该执行阶段。When 指令至少包含一个条件,如果包含多个条件,所有子条件必须返回 True,阶段才能执行。
内置条件
-
branch:当正在构建的分支与给定模式匹配时,执行这个阶段(仅适用于多分支流水线)
when { branch 'master' } -
environment:当指定的环境变量是给定的值时,执行这个阶段
when { environment name: 'DEPLOY_TO', value: 'production' } -
expression:当指定的 Groovy 表达式评估为 true 时,执行这个阶段
when { expression { return params.DEBUG_BUILD } } -
not:当嵌套条件为 false 时,执行这个阶段
when { not { branch 'master' } } -
allOf:当所有的嵌套条件都为 true 时,执行这个阶段
when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } } -
anyOf:当至少有一个嵌套条件为 true 时,执行这个阶段
when { anyOf { branch 'master'; branch 'staging' } }
3.8 Parallel
Parallel 指令允许在一个阶段内并行执行多个嵌套阶段。注意:
- 一个阶段必须只有一个 steps 或 parallel 块
- 嵌套阶段本身不能包含进一步的 parallel 阶段
- Parallel 的阶段不能包含 agent 或 tools 指令,因为它们没有相关的 steps
- 通过添加
failFast true到包含 parallel 的 stage 中,当其中一个进程失败时,可以强制所有的 parallel 阶段都被终止
stage('Parallel Stage') {
when {
branch 'master'
}
failFast true // 第一个进程失败时,后面的也会失败
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
}
}
3.9 Script 步骤
Script 步骤允许在声明式流水线中执行脚本化流水线代码。对于大多数用例,声明式流水线中的 “脚本” 步骤是不必要的,但它可以提供一个有用的 “逃生出口”。非平凡规模和/或复杂性的 script 块应该被转移到共享库。
pipeline {
agent any
stages {
stage("Example") {
steps {
echo 'Hello World'
script {
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
}
}
}
}
4. 完整示例
4.2 生产环境 K8s 流水线示例
生产环境中与 Kubernetes 集成的 CI/CD 流水线通常包含以下核心步骤,以下是完整的示例代码。
根据自己环境情况修改即可,构建的pod使用到镜像可能需要根据自己环境自定义。
#!groovy
pipeline {
// 使用 Kubernetes 作为执行环境,创建包含多个容器的 Pod
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
# 构建容器,用于执行 Maven 构建
- name: build
image: maven:3.8.4-jdk-11
command: ['cat'] # 保持容器运行
tty: true # 启用终端
# Docker 容器,用于构建和推送镜像
- name: docker
image: docker:20.10.16
command: ['cat']
tty: true
volumeMounts:
- name: docker-sock # 挂载 Docker 套接字,实现与主机 Docker 通信
mountPath: /var/run/docker.sock
# kubectl 容器,用于执行 Kubernetes 命令
- name: kubectl
image: bitnami/kubectl:1.23.5
command: ['cat']
tty: true
# 卷定义
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock # 主机上的 Docker 套接字路径
"""
}
}
// 流水线选项配置
options {
timestamps() // 为日志添加时间戳
disableConcurrentBuilds() // 禁止并行构建,避免冲突
timeout(time: 2, unit: 'HOURS') // 流水线超时时间
buildDiscarder(logRotator(numToKeepStr: '10')) // 保留最近10次构建日志
}
// 环境变量定义
environment {
// 镜像仓库地址
REGISTRY = 'my-registry.example.com'
// 应用名称
APP_NAME = 'my-application'
// Kubernetes 命名空间
K8S_NAMESPACE = 'production'
// 凭证 ID,用于访问镜像仓库
DOCKER_CREDENTIALS_ID = 'docker-registry-credentials'
// 凭证 ID,用于访问 Kubernetes 集群
K8S_CREDENTIALS_ID = 'kubernetes-credentials'
}
// 流水线阶段定义
stages {
// 1. 代码获取阶段
stage("1. Get Code") {
steps {
echo "正在获取代码..."
// 从与流水线关联的代码仓库检出代码
checkout scm
// 或指定具体仓库:
// git url: 'https://github.com/example/app.git', branch: 'main'
}
}
// 2. 依赖安装与构建阶段
stage("2. Build") {
steps {
echo "正在构建应用..."
// 在 build 容器中执行 Maven 构建
container('build') {
// 清理并打包应用,跳过测试(测试在专门的测试阶段执行)
sh 'mvn clean package -DskipTests'
}
}
}
// 3. 自动化测试阶段
stage("3. Test") {
steps {
echo "正在执行测试..."
// 在 build 容器中执行 Maven 测试
container('build') {
sh 'mvn test'
// 收集测试报告,便于在 Jenkins 中查看
junit 'target/surefire-reports/**/*.xml'
}
}
}
// 4. 代码扫描阶段
stage("4. Code Scan") {
steps {
echo "正在执行代码扫描..."
// 在 build 容器中执行 SonarQube 扫描
container('build') {
sh '''
sonar-scanner \
-Dsonar.projectKey=${APP_NAME} \
-Dsonar.sources=. \
-Dsonar.java.binaries=target/classes \
-Dsonar.junit.reportsPath=target/surefire-reports \
-Dsonar.qualitygate.wait=true // 等待质量 gate 结果
'''
}
}
}
// 5. 镜像构建阶段
stage("5. Image Build") {
steps {
echo "正在构建 Docker 镜像..."
// 在 docker 容器中执行镜像构建
container('docker') {
script {
// 生成镜像标签,使用构建号和 Git 提交哈希
def gitCommit = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
def imageTag = "${BUILD_NUMBER}-${gitCommit}"
// 构建镜像
sh "docker build -t ${REGISTRY}/${APP_NAME}:${imageTag} ."
// 保存镜像标签到环境变量,供后续阶段使用
env.IMAGE_TAG = imageTag
}
}
}
}
// 6. 镜像扫描与推送阶段
stage("6. Image Push") {
steps {
echo "正在扫描并推送 Docker 镜像..."
// 在 docker 容器中执行操作
container('docker') {
script {
// 使用之前生成的镜像标签
def imageTag = env.IMAGE_TAG
// 使用 Trivy 扫描镜像漏洞
sh "trivy image ${REGISTRY}/${APP_NAME}:${imageTag}"
// 使用凭证登录镜像仓库
withCredentials([usernamePassword(credentialsId: env.DOCKER_CREDENTIALS_ID, usernameVariable: 'USER', passwordVariable: 'PASS')]) {
sh "echo $PASS | docker login ${REGISTRY} -u $USER --password-stdin"
// 推送镜像到仓库
sh "docker push ${REGISTRY}/${APP_NAME}:${imageTag}"
}
}
}
}
}
// 7. Kubernetes 部署阶段
stage("7. K8s Deploy") {
steps {
echo "正在部署到 Kubernetes 集群..."
// 在 kubectl 容器中执行部署操作
container('kubectl') {
script {
// 使用之前生成的镜像标签
def imageTag = env.IMAGE_TAG
// 更新 Kubernetes Deployment 中的镜像版本
sh "kubectl set image deployment/${APP_NAME} ${APP_NAME}=${REGISTRY}/${APP_NAME}:${imageTag} -n ${K8S_NAMESPACE}"
// 验证部署状态,等待部署完成
sh "kubectl rollout status deployment/${APP_NAME} -n ${K8S_NAMESPACE} --timeout=120s"
}
}
}
}
// 8. 部署验证阶段
stage("8. Verification") {
steps {
echo "正在验证部署结果..."
// 在 kubectl 容器中执行验证操作
container('kubectl') {
// 查看 Pod 状态
sh "kubectl get pods -n ${K8S_NAMESPACE} -l app=${APP_NAME}"
// 查看服务状态
sh "kubectl get svc -n ${K8S_NAMESPACE} ${APP_NAME}"
// 执行健康检查(假设应用提供 /health 端点)
sh "kubectl port-forward svc/${APP_NAME} 8080:80 -n ${K8S_NAMESPACE} & sleep 5"
sh "curl -f http://localhost:8080/health || (pkill -f 'kubectl port-forward' && exit 1)"
sh "pkill -f 'kubectl port-forward'"
}
}
}
}
// 流水线完成后的操作
post {
// 成功时的操作
success {
echo "流水线执行成功!"
// 发送 Slack 通知
slackSend
channel: '#deployments',
color: 'good',
message: "应用 ${APP_NAME} 部署成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}\n镜像标签: ${env.IMAGE_TAG}"
}
// 失败时的操作
failure {
echo "流水线执行失败!"
// 发送 Slack 通知
slackSend
channel: '#deployments',
color: 'danger',
message: "应用 ${APP_NAME} 部署失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
// 在 kubectl 容器中执行回滚操作
container('kubectl') {
echo "正在执行回滚操作..."
sh "kubectl rollout undo deployment/${APP_NAME} -n ${K8S_NAMESPACE}"
}
}
// 无论成功失败都执行的操作
always {
echo "流水线执行完成!"
// 清理工作空间
cleanWs()
}
}
}
4.2.1 生产环境流水线步骤说明
生产环境中的 Kubernetes 流水线通常包含以下关键步骤:
-
代码获取 (Get Code)
- 从版本控制系统拉取最新代码
- 支持指定分支、标签或提交哈希
-
依赖安装与构建 (Build)
- 安装项目依赖
- 构建应用,生成可部署的制品
-
自动化测试 (Test)
- 执行单元测试、集成测试等
- 收集测试报告,便于问题分析
-
代码扫描 (Code Scan)
- 检测代码中的安全漏洞
- 分析代码质量,确保符合最佳实践
-
镜像构建 (Image Build)
- 将构建产物打包为 Docker 镜像
- 为镜像添加版本标签(如构建号、Git 提交哈希)
-
镜像扫描与推送 (Image Push)
- 扫描 Docker 镜像中的安全漏洞
- 将镜像推送到镜像仓库(如 Docker Hub、Harbor)
-
Kubernetes 部署 (K8s Deploy)
- 更新 Kubernetes 中的应用版本
- 支持滚动更新、金丝雀发布等策略
-
部署验证 (Verification)
- 验证部署是否成功
- 检查应用健康状态和可用性
-
通知与回滚 (Post Actions)
- 发送部署结果通知(如 Slack、邮件)
- 在失败时自动回滚到上一版本
4.2.2 K8s 相关最佳实践
- 镜像仓库集成:使用私有的镜像仓库,并配置 Kubernetes 的
imagePullSecrets以拉取私有镜像 - 资源配置:明确指定 CPU/内存资源限制,避免资源竞争
- 健康检查:为 Pod 配置
livenessProbe、readinessProbe和startupProbe - 滚动更新策略:设置合理的
rollingUpdate参数,确保部署过程中服务不中断 - 命名空间隔离:将不同环境的应用部署到独立命名空间
- Secrets 管理:使用 K8s Secrets 或外部密钥管理服务存储敏感信息
- 监控集成:集成 Prometheus、Grafana 等监控工具,实时监控应用状态
- 日志管理:配置集中式日志收集,便于问题排查
5. 现代 CI/CD 环境集成
5.1 容器化集成
5.1.1 使用 Docker 执行环境
pipeline {
agent {
docker {
image 'node:14-alpine'
args '-p 3000:3000'
}
}
stages {
stage('构建') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('测试') {
steps {
sh 'npm test'
}
}
}
}
5.1.2 Kubernetes 集成
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: build
image: maven:3.8.4-jdk-11
command: ['cat']
tty: true
- name: test
image: node:14-alpine
command: ['cat']
tty: true
"""
}
}
stages {
stage('构建') {
steps {
container('build') {
sh 'mvn clean package'
}
}
}
stage('测试') {
steps {
container('test') {
sh 'npm install && npm test'
}
}
}
}
}
5.2 云服务集成
5.2.1 AWS 集成
pipeline {
agent any
environment {
AWS_REGION = 'us-east-1'
AWS_ACCOUNT_ID = credentials('aws-account-id')
AWS_ACCESS_KEY_ID = credentials('aws-access-key')
AWS_SECRET_ACCESS_KEY = credentials('aws-secret-key')
}
stages {
stage('部署到 S3') {
steps {
sh 'aws s3 sync ./build s3://my-bucket'
}
}
stage('部署到 ECS') {
steps {
sh 'aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment'
}
}
}
}
5.3 监控与通知
5.3.1 集成 Slack 通知
pipeline {
agent any
stages {
// 构建阶段...
}
post {
success {
slackSend
channel: '#jenkins-builds',
color: 'good',
message: "构建成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
}
failure {
slackSend
channel: '#jenkins-builds',
color: 'danger',
message: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
}
}
}
5.3.2 集成 Prometheus 监控
pipeline {
agent any
stages {
// 构建阶段...
}
post {
always {
script {
// 推送构建指标到 Prometheus
sh '''
curl -X POST "http://prometheus-pushgateway:9091/metrics/job/jenkins/builds"
-d "jenkins_build_duration_seconds $BUILD_DURATION"
-d "jenkins_build_result{result=\"$BUILD_RESULT\"} 1"
'''
}
}
}
}
6. 最佳实践
6.1 代码组织
- 使用共享库:将重复的逻辑提取到 Jenkins 共享库中,提高代码复用性
- 模块化:将复杂的流水线分解为多个小的、可管理的阶段
- 版本控制:将 Jenkinsfile 存储在源代码仓库中,与应用代码一起版本控制
6.2 安全性
- 使用凭证绑定:避免在代码中硬编码敏感信息
- 最小权限原则:为 Jenkins 代理和流水线设置最小必要权限
- 定期更新:及时更新 Jenkins 和插件,修复安全漏洞
6.3 性能优化
- 并行执行:使用 parallel 指令并行执行独立任务
- 缓存依赖:缓存构建依赖,减少构建时间
- 合理设置超时:为各个阶段设置合理的超时时间,避免无限等待
6.4 可维护性
- 添加注释:为复杂的流水线逻辑添加注释,提高可维护性
- 使用参数化构建:通过参数化构建,使流水线更加灵活
- 添加日志:在关键步骤添加日志,便于问题排查
7. 总结
Jenkins Pipeline 是实现 CI/CD 自动化的强大工具,通过代码定义构建、测试和部署流程,提高了流程的可重复性和可维护性。本文涵盖了 Jenkins Pipeline 的核心概念、常用指令、完整示例以及现代 CI/CD 环境的集成方案,希望能帮助您构建更加高效、可靠的 CI/CD 流水线。
关注微信公众号 Linux容器运维 并回复关键字 “视频资料”,即可获取我们整理的 Kubernetes、Docker 容器、Python 编程、Linux 运维等教学视频合集(总计 548GB)。本资源仅面向学习交流使用,请遵守版权和使用规范,严禁商用、转售或违规传播。
更多推荐
所有评论(0)