详情

首页手游攻略 【CI/CD·Jenkins篇】Pipeline 基础:Declarative 与 Scripted 语法详细说明

【CI/CD·Jenkins篇】Pipeline 基础:Declarative 与 Scripted 语法详细说明

佚名 2026-08-25 20:35:54

{"type":"doc","content":[{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","content":[{"type":"text","text":"Jenkins Pipeline 是 Jenkins 的核心能力——用代码定义完整的交付流水线。Pipeline 有两种写法:Declarative(声明式)和 Scripted(脚本式)。本篇详解两种语法的区别、选择策略和编写技巧,让你能独立编写生产级流水线。"}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"一、两种语法的选择"}]},{"type":"paragraph","content":[{"type":"text","text":"| 维度 | Declarative | Scripted |"}]},{"type":"paragraph","content":[{"type":"text","text":"|------|-------------|----------|"}]},{"type":"paragraph","content":[{"type":"text","text":"| 语法 | 结构化 YAML 风格 | Groovy 脚本 |"}]},{"type":"paragraph","content":[{"type":"text","text":"| 上手难度 | 低 | 中高 |"}]},{"type":"paragraph","content":[{"type":"text","text":"| 灵活性 | 中(但足够覆盖90%场景) | 高 |"}]},{"type":"paragraph","content":[{"type":"text","text":"| 可读性 | 强 | 中 |"}]},{"type":"paragraph","content":[{"type":"text","text":"| 代码审查 | 容易 | 较难 |"}]},{"type":"paragraph","content":[{"type":"text","text":"| 推荐场景 | 90% 的流水线 | 复杂条件逻辑 |"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"strong"}],"text":"结论:优先用 Declarative,只有遇到它无法表达的复杂逻辑时才回退到 Scripted。"}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"二、Declarative Pipeline 语法详解"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"基本结构"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"pipeline {nagent any// 在任意可用节点执行nnenvironment {n// 环境变量定义nAPP_NAME = 'myapp'nVERSION = "${env.BUILD_NUMBER}"nDOCKER_REGISTRY = 'registry.mycompany.com'n}nnoptions {n// 流水线选项ntimeout(time: 30, unit: 'MINUTES')nbuildDiscarder(logRotator(numToKeepStr: '20'))ndisableConcurrentBuilds()// 禁止并发构建n}nnparameters {n// 参数定义nchoice(name: 'ENV', choices: ['dev', 'test', 'staging', 'prod'], description: '部署环境')nstring(name: 'IMAGE_TAG', defaultValue: 'latest', description: '镜像标签')nbooleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试')n}nntriggers {n// 触发器ncron('H 2 * * *')// 每天凌晨2点执行n}nnstages {nstage('Build') {nsteps {nsh 'mvn clean package -DskipTests'n}n}nnstage('Test') {nwhen {nexpression { !params.SKIP_TESTS }n}nsteps {nsh 'mvn test'n}npost {nalways {njunit 'target/surefire-reports/TEST-*.xml'n}n}n}n}nnpost {nsuccess {necho 'Pipeline succeeded!'n}nfailure {necho 'Pipeline failed!'nemailext to: '[email protected]', subject: 'Build Failed: ${JOB_NAME} #${BUILD_NUMBER}'n}nalways {ncleanWs()// 清理工作空间n}n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"agent 指令详解"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"pipeline {n// 方式1:任意节点nagent anynn// 方式2:指定标签的节点nagent { label 'docker-build' }nn// 方式3:指定 Docker 镜像(不需要预装工具)nagent {ndocker {nimage 'maven:3.9-eclipse-temurin-17'nargs '-v $HOME/.m2:/root/.m2 -v $HOME/.gradle:/root/.gradle'nlabel 'docker-build'n}n}nn// 方式4:Kubernetes Pod(需要 K8s 插件)nagent {nkubernetes {nlabel 'mypod'nyaml '''napiVersion: v1nkind: Podnspec:ncontainers:n- name: mavennimage: maven:3.9-eclipse-temurin-17ncommand: ['cat']nvolumeMounts:n- mountPath: /root/.m2nname: maven-cachenvolumes:n- name: maven-cachenpersistentVolumeClaim:nclaimName: maven-cache-pvcn'''n}n}n}"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"strong"}],"text":"培训要点"},{"type":"text","text":":用 Docker agent 是最佳实践——不需要在 Agent 上预装 Maven/Gradle 等工具,直接在 Pipeline 中指定镜像版本,保证构建环境的确定性。"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"environment 指令"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"pipeline {nenvironment {n// 静态值nAPP_NAME = 'myapp'nn// 引用构建号nBUILD_TAG = "build-${BUILD_NUMBER}"nn// 引用凭据(敏感信息)nDB_PASSWORD = credentials('db-password')// 会生成 DB_PASSWORD 和 DB_PASSWORD_USR 变量nn// 条件赋值nDEPLOY_ENV = "${env.BRANCH_NAME == 'main' ? 'prod' : 'dev'}"n}nnstages {nstage('Config') {n// 局部环境变量,只在此 stage 生效nenvironment {nLOCAL_VAR = 'stage-specific'n}nsteps {necho "APP_NAME=${APP_NAME}"necho "DEPLOY_ENV=${DEPLOY_ENV}"n// 使用凭据时用 $ 而非 ${} 在 sh 中nsh 'echo $DB_PASSWORD | wc -c'n}n}n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"when 指令:条件执行"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"stages {nstage('Deploy Prod') {nwhen {nbranch 'main' // 只在 main 分支执行n// expression { env.BRANCH_NAME == 'main' }// 等价写法n}nsteps {nsh './deploy.sh prod'n}n}nnstage('Deploy Dev') {nwhen {nbranch 'dev'n}nsteps {nsh './deploy.sh dev'n}n}nnstage('Nightly Build') {nwhen {ntriggeredBy 'TimerTrigger'// 只在定时触发时执行n}nsteps {nsh './run-full-test-suite.sh'n}n}nnstage('Skip on PR') {nwhen {nnot { changeRequest() }// 非 PR 时执行n}nsteps {nsh './heavy-test.sh'n}n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"parallel:并行执行"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"stage('Test') {nparallel {nstage('Unit Test') {nsteps {nsh 'mvn test'n}n}nstage('Integration Test') {nsteps {nsh 'mvn verify -Pintegration'n}n}nstage('Code Scan') {nsteps {nsh 'sonar-scanner'n}n}n}n}"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"strong"}],"text":"踩坑提示"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"parallel"},{"type":"text","text":" 中的每个 stage 默认在同一个 agent 上执行。如果需要在不同 agent 上并行,需要在每个 stage 内部指定 "},{"type":"text","marks":[{"type":"code"}],"text":"agent"},{"type":"text","text":"。"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"script 块:在 Declarative 中嵌入 Groovy"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"stage('Dynamic Deploy') {nsteps {nscript {n// 在 Declarative 中使用 Groovy 逻辑ndef services = ['user-service', 'order-service', 'payment-service']nfor (service in services) {necho "Deploying ${service}..."nsh "kubectl set image deployment/${service} app=myapp:${BUILD_NUMBER} -n prod"n}n}n}n}"}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"三、Scripted Pipeline 语法详解"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"基本结构"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"// Scripted Pipeline 没有外层 pipeline {} 块n// 直接写 Groovy 脚本nnnode('docker-build') {n// 定义环境变量ndef appName = 'myapp'ndef version = env.BUILD_NUMBERnntry {nstage('Checkout') {ncheckout scmn}nnstage('Build') {nsh 'mvn clean package -DskipTests'n// 归档构建产物narchiveArtifacts artifacts: 'target/*.jar', fingerprint: truen}nnstage('Test') {nsh 'mvn test'nstep([$class: 'JUnitResultArchiver', testResults: '**/surefire-reports/TEST-*.xml'])n}nnstage('Deploy') {nif (env.BRANCH_NAME == 'main') {nsh "./deploy.sh prod ${version}"n} else {nsh "./deploy.sh dev ${version}"n}n}nn} catch (Exception e) {n// 错误处理nemailext to: '[email protected]',nsubject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",nbody: "Check: ${env.BUILD_URL}"nthrow e// 重新抛出,让 Jenkins 标记为失败n} finally {n// 清理ncleanWs()n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"Scripted 中的条件与循环"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"node('docker-build') {nstage('Multi-Service Deploy') {ndef services = [n[name: 'user-service', replicas: 3],n[name: 'order-service', replicas: 2],n[name: 'payment-service', replicas: 2]n]nnfor (svc in services) {necho "Deploying ${svc.name} with ${svc.replicas} replicas"nsh "kubectl set image deployment/${svc.name} app=myapp:${env.BUILD_NUMBER} -n prod"nsh "kubectl scale deployment/${svc.name} --replicas=${svc.replicas} -n prod"nsh "kubectl rollout status deployment/${svc.name} -n prod --timeout=120s"n}n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"并行构建(Scripted 方式)"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"def branches = [:]nbranches['unit-test'] = {nnode('java-build') {nstage('Unit Test') {nsh 'mvn test'n}n}n}nbranches['integration-test'] = {nnode('java-build') {nstage('Integration Test') {nsh 'mvn verify -Pintegration'n}n}n}nbranches['code-scan'] = {nnode('java-build') {nstage('Code Scan') {nsh 'sonar-scanner'n}n}n}nnparallel branches// 并行执行所有分支"}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"四、实战对比:同一个需求的两种写法"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"需求"}]},{"type":"paragraph","content":[{"type":"text","text":"根据分支决定部署环境:main→生产,develop→测试,其他→不部署。"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"Declarative 写法"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"pipeline {nagent anynstages {nstage('Build') { steps { sh 'mvn clean package' } }nnstage('Deploy') {nstages {nstage('Deploy Prod') {nwhen { branch 'main' }nsteps { sh './deploy.sh prod' }n}nstage('Deploy Test') {nwhen { branch 'develop' }nsteps { sh './deploy.sh test' }n}n}n}n}n}"}]},{"type":"heading","attrs":{"level":3},"content":[{"type":"text","text":"Scripted 写法"}]},{"type":"code_block","attrs":{"language":"groovy"},"content":[{"type":"text","text":"node {nstage('Build') {nsh 'mvn clean package'n}nstage('Deploy') {nif (env.BRANCH_NAME == 'main') {nsh './deploy.sh prod'n} else if (env.BRANCH_NAME == 'develop') {nsh './deploy.sh test'n} else {necho "Branch ${env.BRANCH_NAME} does not trigger deployment"n}n}n}"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"strong"}],"text":"培训要点"},{"type":"text","text":":Declarative 的 "},{"type":"text","marks":[{"type":"code"}],"text":"when"},{"type":"text","text":" 让流水线结构更清晰——即使不部署的 stage 也会显示在流水线视图上(标记为 skipped)。Scripted 的 "},{"type":"text","marks":[{"type":"code"}],"text":"if/else"},{"type":"text","text":" 更灵活但不够直观。"}]}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"五、常用内置变量速查"}]},{"type":"paragraph","content":[{"type":"text","text":"| 变量 | 说明 | 示例值 |"}]},{"type":"paragraph","content":[{"type":"text","text":"|------|------|--------|"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.JOB_NAME"},{"type":"text","text":" | Job 名称 | "},{"type":"text","marks":[{"type":"code"}],"text":"myapp-pipeline"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.BUILD_NUMBER"},{"type":"text","text":" | 构建编号 | "},{"type":"text","marks":[{"type":"code"}],"text":"42"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.BUILD_ID"},{"type":"text","text":" | 构建 ID | "},{"type":"text","marks":[{"type":"code"}],"text":"2024-01-15_10-30-00"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.BUILD_URL"},{"type":"text","text":" | 构建 URL | "},{"type":"text","marks":[{"type":"code"}],"text":"http://jenkins/job/myapp/42/"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.WORKSPACE"},{"type":"text","text":" | 工作空间路径 | "},{"type":"text","marks":[{"type":"code"}],"text":"/home/jenkins/workspace/myapp"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.NODE_NAME"},{"type":"text","text":" | 执行节点名 | "},{"type":"text","marks":[{"type":"code"}],"text":"agent-docker"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.JENKINS_URL"},{"type":"text","text":" | Jenkins URL | "},{"type":"text","marks":[{"type":"code"}],"text":"http://jenkins:8080"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.BRANCH_NAME"},{"type":"text","text":" | 分支名 | "},{"type":"text","marks":[{"type":"code"}],"text":"main"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.GIT_COMMIT"},{"type":"text","text":" | Git commit hash | "},{"type":"text","marks":[{"type":"code"}],"text":"a1b2c3d4"},{"type":"text","text":" |"}]},{"type":"paragraph","content":[{"type":"text","text":"| "},{"type":"text","marks":[{"type":"code"}],"text":"env.GIT_URL"},{"type":"text","text":" | Git 仓库 URL | "},{"type":"text","marks":[{"type":"code"}],"text":"https://github.com/org/repo"},{"type":"text","text":" |"}]},{"type":"horizontal_rule"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"六、本篇要点回顾"}]},{"type":"ordered_list","attrs":{"order":1},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"优先用 Declarative,复杂逻辑用 "},{"type":"text","marks":[{"type":"code"}],"text":"script {}"},{"type":"text","text":" 块嵌入 Groovy"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"code"}],"text":"agent"},{"type":"text","text":" 指令推荐用 Docker 镜像方式,保证构建环境确定性"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"code"}],"text":"when"},{"type":"text","text":" 指令控制条件执行,替代 "},{"type":"text","marks":[{"type":"code"}],"text":"if/else"},{"type":"text","text":" 更结构化"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"code"}],"text":"parallel"},{"type":"text","text":" 实现并行执行,大幅缩短流水线时间"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"code"}],"text":"credentials()"},{"type":"text","text":" 函数安全引用密钥,不要在代码中硬编码"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"code"}],"text":"post"},{"type":"text","text":" 块处理流水线结果通知"}]}]}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"strong"}],"text":"下一篇预告"},{"type":"text","text":":《Jenkinsfile 最佳实践:多分支流水线与共享库》——从语法层面进入工程层面,学习如何管理多个项目的 Jenkinsfile 和复用流水线代码。"}]}]}","createTime":1786331419,"ext":{"closeTextLink":0,"comment_ban":0,"description":"","focusRead":0},"favNum":0,"html":"","isOriginal":0,"likeNum":0,

相关资讯
点击查看更多
游戏推荐
推荐专题
热门阅读
推荐下载