Jenkins Pipeline 声明式语法
groovy pipeline { agent any stages { stage('Build') { steps { echo 'Building..' } } } }
以上代码定义了一个最简单的 Pipeline:在任何可用代理(agent)上执行一个名为 “Build” 的阶段,其中只包含一个打印文本的步骤。
## 顶级指令详解
声明式 Pipeline 允许在 `pipeline` 块中使用一系列指令来控制整体行为。
### agent
`agent` 指定整个 Pipeline 或特定阶段在哪个节点上执行。它必须位于 `pipeline` 块内的顶层,或者在 `stage` 内部。常用参数包括:
- `any`:在任何可用的代理上执行。
- `none`:不在全局指定代理,后续各 `stage` 必须各自定义自己的 `agent`。
- `label`:在指定标签的节点上执行,如 `agent { label 'linux' }`。
- `docker`:在 Docker 容器中执行,例如:
```groovy
agent {
docker {
image 'node:16-alpine'
args '-v /tmp:/tmp'
}
}
stages 与 stage
stages 块包含一个或多个 stage,每个 stage 代表流程中的一个阶段,比如“构建”、“测试”、“部署”。stage 的名称(如 stage('Build'))会在 Jenkins 界面上清晰显示,方便追踪进度。
stages {
stage('Stage 1') {
steps { ... }
}
stage('Stage 2') {
steps { ... }
}
}
steps
steps 是每个 stage 内部必须包含的块,它定义该阶段要执行的实际操作。可以使用 Jenkins 内置步骤,如 echo、sh、git 等。
steps {
echo '开始编译'
sh 'mvn clean compile'
}
post
post 块定义了在整个 Pipeline 或某个 stage 执行完毕后需要运行的操作,通常用于清理、通知等。它支持多种条件分支:
always:无论结果如何都会执行。success:只有当前构建成功时执行。failure:只有构建失败时执行。unstable:构建结果不稳定时执行。changed:当前构建状态与上一次不同时执行。
post {
always {
junit '**/target/surefire-reports/*.xml'
}
failure {
mail to: 'team@example.com', subject: 'Pipeline Failed'
}
}
environment
environment 指令用于定义环境变量,这些变量可以在所有步骤中通过 env.VAR_NAME 或 ${VAR_NAME} 访问。它可以放在 pipeline 顶层(全局有效)或某个 stage 内部(仅该阶段有效)。
pipeline {
environment {
APP_NAME = 'my-app'
DEPLOY_DIR = '/var/www'
}
stages {
stage('Deploy') {
environment {
TARGET_ENV = 'production'
}
steps {
sh 'echo "Deploying $APP_NAME to $TARGET_ENV in $DEPLOY_DIR"'
}
}
}
}
options
options 用于设置 Pipeline 级别的选项,如超时时间、保持构建天数、禁止并发构建等。
options {
timeout(time: 1, unit: 'HOURS')
buildDiscarder(logRotator(numToKeepStr: '10'))
disableConcurrentBuilds()
}
parameters
parameters 指令可定义参数化构建中的参数,用户在触发构建时可以输入自定义值。支持类型包括 string、booleanParam、choice 等。
parameters {
string(name: 'VERSION', defaultValue: '1.0', description: '版本号')
booleanParam(name: 'RUN_TESTS', defaultValue: true, description: '是否运行测试')
choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: '部署环境')
}
triggers
triggers 定义了 Pipeline 的自动触发方式,例如定时构建、轮询 SCM 或由上游项目触发。
triggers {
cron('H 4 * * 1-5') // 周一到周五凌晨4点左右构建
pollSCM('* * * * *') // 每分钟检查版本库变化
}
tools
tools 用于自动安装并配置构建工具,要求 Jenkins 已安装对应工具的配置。它可在 pipeline 顶层或 stage 内使用。
tools {
maven 'Maven-3.8.6' // 引用的工具名称需在 Jenkins 全局工具配置中定义
jdk 'JDK11'
}
when
when 指令允许阶段在特定条件满足时才执行,这是实现智能流程控制的重要手段。它必须放在 stage 块内部,steps 之前。常用条件包括 branch、environment、expression 等。
stage('Deploy to Production') {
when {
branch 'main'
environment name: 'DEPLOY_TO_PROD', value: 'true'
}
steps {
sh 'ansible-playbook deploy.yml'
}
}
进阶功能与内置步骤
并行执行
声明式 Pipeline 支持在同一个阶段内并行运行多个子阶段,只需在 stage 下使用 parallel 块。
stage('Run Tests') {
parallel {
stage('Unit Tests') {
steps { sh 'npm run test:unit' }
}
stage('Integration Tests') {
steps { sh 'npm run test:integration' }
}
}
}
凭据与敏感信息处理
通过 credentials() 助手方法可以安全地引用 Jenkins 中存储的凭据,避免在脚本中硬编码密码。
environment {
DB_PWD = credentials('database-password')
}
steps {
sh 'echo "Connecting with password $DB_PWD"'
}
代码拉取
最常用的步骤是 git,它会根据 SCM 配置拉取源代码。通常放在第一个阶段:
stage('Checkout') {
steps {
git url: 'https://github.com/user/repo.git', branch: 'main'
}
}
共享库
当多个 Pipeline 存在重复逻辑时,可以将 Groovy 函数封装为“共享库”,并在声明式 Pipeline 中通过 @Library 注解引入,或直接在 libraries 指令中配置。
@Library('my-shared-library@v1.0') _
pipeline {
// ...
steps {
myCustomStep(arg1: 'value')
}
}
编写最佳实践
- 保持
Jenkinsfile精简:将复杂逻辑封装到 Shell 脚本或工具中,避免 Groovy 代码过度膨胀。 - 遵循阶段语义:一个阶段只做一件事,如“编译”、“测试”、“构建镜像”、“部署”,便于快速定位问题。
- 使用
when条件而非硬编码分支判断:让流程根据分支、标签、参数自动调整行为。 - 善用
post处理资源清理和通知:确保无论成功失败都能归档报告或发送通知。 - 对耗时的步骤设置超时:通过
stage的options或在步骤中使用timeout包装,避免构建挂起。
完整示例:一个典型的 CI/CD Pipeline
下面展示一个使用声明式语法构建 Java 应用的完整 Pipeline,涵盖代码拉取、编译、测试、镜像构建和部署通知。
pipeline {
agent any
environment {
REGISTRY = 'docker.io'
IMAGE = "$REGISTRY/myorg/myapp"
}
tools {
maven 'Maven-3.8.6'
jdk 'JDK11'
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/myorg/myapp.git'
}
}
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Containerize') {
when {
branch 'main'
}
steps {
sh "docker build -t $IMAGE:${env.BUILD_ID} ."
sh "docker push $IMAGE:${env.BUILD_ID}"
}
}
stage('Deploy to Staging') {
when {
branch 'main'
}
steps {
sh "kubectl set image deployment/myapp myapp=$IMAGE:${env.BUILD_ID}"
}
}
}
post {
success {
emailext body: '构建成功!', subject: 'CI Pipeline Passed', to: 'devs@example.com'
}
failure {
emailext body: '构建失败,请检查日志。', subject: 'CI Pipeline Failed', to: 'devops@example.com'
}
}
}