第四章:Pipeline 基础
理解 Jenkins Pipeline 的核心概念、类型和使用场景。
最后更新: 2024-01-15
页面目录
Jenkins Pipeline 基础
Pipeline(流水线)是 Jenkins 2.0 引入的核心功能,通过代码定义构建流程,实现「Pipeline as Code」理念。
为什么需要 Pipeline?
传统 Freestyle 的局限性
- 配置分散在 Web 界面,难以追踪
- 不便于版本控制和代码审查
- 难以复用和模块化
- 复杂的条件逻辑难以实现
Pipeline 的优势
┌─────────────────────────────────────────────────────────────────┐
│ Pipeline 优势 │
├─────────────────────────────────────────────────────────────────┤
│ ✅ 版本控制 Pipeline 配置存储在代码仓库中 │
│ ✅ 代码审查 通过 PR/MR 审查构建流程 │
│ ✅ 持久化 构建过程状态自动保存 │
│ ✅ 可复用 提取公共逻辑为共享库 │
│ ✅ 可见性 完整的阶段视图和日志 │
│ ✅ 增量执行 支持从失败点恢复构建 │
└─────────────────────────────────────────────────────────────────┘
Pipeline 类型
1. Declarative Pipeline(声明式)
声明式 Pipeline 是推荐的编写方式,语法更简洁、结构更清晰:
// 声明式 Pipeline 示例
pipeline {
agent any
parameters {
string(name: 'VERSION', defaultValue: '1.0.0')
}
environment {
APP_NAME = 'my-app'
}
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
post {
always {
cleanWs()
}
}
}
2. Scripted Pipeline(脚本式)
脚本式 Pipeline 使用 Groovy 语法,更灵活但结构较复杂:
// 脚本式 Pipeline 示例
node('docker') {
stage('Checkout') {
checkout scm
}
stage('Build') {
sh 'mvn clean package'
}
stage('Test') {
try {
sh 'mvn test'
} catch (Exception e) {
currentBuild.result = 'UNSTABLE'
}
}
stage('Deploy') {
if (env.BRANCH_NAME == 'main') {
sh './deploy.sh'
}
}
}
两种语法对比
| 特性 | Declarative | Scripted |
|---|---|---|
| 语法风格 | YAML-like | Groovy |
| 学习曲线 | 平缓 | 较陡 |
| 灵活性 | 固定结构 | 完全自由 |
| 错误恢复 | 支持 | 不支持 |
| 推荐度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
Pipeline 核心概念
1. Agent
定义 Pipeline 或 stage 在哪里执行:
// 在任意可用节点执行
agent any
// 在指定标签的节点执行
agent { label 'docker' }
// Docker 容器中执行
agent {
docker {
image 'maven:3.8-openjdk-11'
reuseNode true // 复用主节点工作区
}
}
// Kubernetes Pod 模板
agent {
kubernetes {
label 'pod-template'
yaml '''
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins: agent
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:latest
- name: maven
image: maven:3.8-openjdk-11
command: sleep
args: infinity
'''
}
}
// 不分配节点(用于声明阶段)
agent none
2. Stages 和 Steps
pipeline {
agent any
stages {
stage('阶段名称') {
steps {
// 具体步骤
echo 'Hello World'
sh 'mvn --version'
bat 'dir' // Windows
}
}
}
}
3. Post
定义 Pipeline 执行完成后的操作:
post {
always {
// 无论构建结果如何都执行
echo '清理资源'
}
success {
// 构建成功时执行
echo '🎉 构建成功!'
}
failure {
// 构建失败时执行
echo '❌ 构建失败!'
slackSend message: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
}
unstable {
// 构建不稳定时执行
echo '⚠️ 构建不稳定'
}
aborted {
// 构建被中止时执行
echo '⏹️ 构建已中止'
}
cleanup {
// 无论如何最后执行(总是最后)
echo '最终清理'
}
}
4. Environment
定义环境变量:
pipeline {
agent any
environment {
APP_NAME = 'my-service'
VERSION = '1.2.3'
JAVA_OPTS = '-Xmx512m'
CC = 'clang'
}
stages {
stage('Build') {
environment {
BUILD_MODE = 'release'
}
steps {
echo "构建应用: ${env.APP_NAME}"
sh 'printenv | grep -E "APP_|BUILD_"'
}
}
}
}
5. Parameters
定义构建参数:
pipeline {
agent any
parameters {
string(
name: 'VERSION',
defaultValue: '1.0.0',
description: '版本号'
)
choice(
name: 'ENVIRONMENT',
choices: ['dev', 'staging', 'prod'],
description: '部署环境'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '跳过测试'
)
password(
name: 'API_TOKEN',
defaultValue: '',
description: 'API Token'
)
file(
name: 'CONFIG_FILE',
description: '配置文件'
)
text(
name: 'BUILD_NOTES',
defaultValue: '',
description: '构建备注'
)
}
stages {
stage('Parameters') {
steps {
echo "版本: ${params.VERSION}"
echo "环境: ${params.ENVIRONMENT}"
}
}
}
}
6. When 条件
控制阶段的执行条件:
stages {
stage('Deploy') {
when {
branch 'main'
}
steps {
echo '部署到生产环境'
}
}
stage('Deploy Staging') {
when {
anyOf {
branch 'main'
branch 'release/*'
}
}
steps {
echo '部署到预发布环境'
}
}
stage('Integration Tests') {
when {
expression { params.RUN_TESTS == true }
not { branch 'feature/*' }
}
steps {
echo '运行集成测试'
}
}
}
7. Parallel 并行执行
stages {
stage('Test in Parallel') {
parallel {
stage('Unit Tests') {
steps {
echo '运行单元测试'
sh 'mvn test -Dtest=*Test'
}
}
stage('Integration Tests') {
steps {
echo '运行集成测试'
sh 'mvn verify -Dintegration'
}
}
stage('Code Analysis') {
steps {
echo '代码分析'
sh 'mvn sonar:sonar'
}
}
}
}
}
8. Matrix 矩阵执行
stages {
stage('Build Matrix') {
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'windows', 'macos'
}
axis {
name 'ARCH'
values 'x64', 'arm64'
}
}
stages {
stage('Build') {
steps {
echo "构建平台: ${PLATFORM}, 架构: ${ARCH}"
sh "./build.sh --platform=${PLATFORM} --arch=${ARCH}"
}
}
}
excludedAgents 'docker' // 排除特定节点
}
}
}
完整的 Pipeline 示例
// Jenkinsfile - 完整的声明式 Pipeline
@Library('shared-library') _
pipeline {
agent {
kubernetes {
defaultContainer 'jnlp'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8-eclipse-temurin-11
command: sleep
args: infinity
- name: docker
image: docker:20.10-dind
securityContext:
privileged: true
volumeMounts:
- name: docker-graph-storage
mountPath: /var/lib/docker
volumes:
- name: docker-graph-storage
emptyDir: {}
'''
}
}
options {
timestamps()
timeout(time: 1, unit: 'HOURS')
buildDiscarder(logRotator(numToKeepStr: '30'))
disableConcurrentBuilds()
}
parameters {
choice(name: 'BRANCH', choices: ['main', 'develop', 'release/*'], description: '分支')
booleanParam(name: 'DEPLOY', defaultValue: false, description: '部署')
}
environment {
REGISTRY = 'registry.example.com'
IMAGE_NAME = 'myapp'
CREDENTIALS = credentials('docker-registry')
}
stages {
stage('Checkout') {
steps {
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
}
checkout scm
}
}
stage('Build') {
steps {
container('maven') {
sh '''
mvn clean package -DskipTests
echo "Build completed: ${GIT_COMMIT_SHORT}"
'''
}
}
post {
success {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('Test') {
steps {
container('maven') {
sh 'mvn test'
}
}
post {
always {
junit 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/jacoco.exec'
}
}
}
stage('Security Scan') {
steps {
container('maven') {
sh 'mvn dependency:tree -DoutputFile=dependencies.txt'
}
echo 'OWASP dependency check...'
}
}
stage('Docker Build') {
when {
anyOf { branch 'main'; branch 'release/*' }
}
steps {
container('docker') {
sh '''
echo $CREDENTIALS_PSW | docker login -u $CREDENTIALS_USR --password-stdin ${REGISTRY}
docker build -t ${REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT} .
docker push ${REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}
docker tag ${REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT} ${REGISTRY}/${IMAGE_NAME}:latest
docker push ${REGISTRY}/${IMAGE_NAME}:latest
'''
}
}
}
stage('Deploy') {
when {
allOf {
branch 'main'
expression { params.DEPLOY == true }
}
}
steps {
sh '''
kubectl set image deployment/myapp \
app=${REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}
'''
}
}
}
post {
success {
echo 'Pipeline 执行成功!'
}
failure {
echo 'Pipeline 执行失败!'
}
always {
cleanWs()
}
}
}
下一步
现在您已经掌握了 Pipeline 的核心概念。接下来让我们深入学习 Pipeline 的详细语法。
📖 参考文档: