【CICD】Jenkins Pipeline 快速学习入门

文章持续更新ing

一、快速开始

复制代码
pipeline {
    agent any

    environment {
        APP_NAME = 'demo-app'
    }

    stages {
        stage('Build') {
            steps {
                echo "Building ${APP_NAME}"
                sh 'echo build'
            }
        }
    }

    post {
        success {
            echo 'Success'
        }
        failure {
            echo 'Failed'
        }
    }
}

1. pipeline:整个流水线的最外层定义。

2. agent:指定在哪台 Jenkins 节点执行。指定 Pipeline 或 Stage 在哪个执行环境(节点/容器)上运行。

复制代码
agent any                 // 任意可用节点
agent none                // 不分配全局节点,每个 stage 单独指定
agent { label 'linux' }   // 指定带 linux 标签的节点

# 补充:动态agent
# https://plugins.jenkins.io/kubernetes/#plugin-content-configuration-reference
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: golang
    image: your-registry/ci/go:1.22
    command: ["cat"]
    tty: true
  - name: kaniko
    image: gcr.io/kaniko-project/executor:debug
    command: ["/busybox/cat"]
    tty: true
'''
        }
    }
项目 agent any agent kubernetes
执行位置 任意已有 Jenkins 节点 动态创建 Kubernetes Pod
环境依赖 节点须预装 Go、Docker、curl 等 在 Pod 镜像/YAML 中定义环境
环境隔离 节点可能残留上次构建文件 每次构建全新、隔离
配置复杂度 低,适合入门 较高,需要 Pod YAML、镜像构建方案
Docker 构建 节点有 Docker 即可 通常使用 Kaniko、BuildKit 或 DinD,不能默认直接 docker build

3. stages / stage:将流程拆成清晰步骤,如 Checkout、Build、Test、Deploy。

复制代码
stages {
    stage('Build') {
        steps {
            sh 'npm run build'
        }
    }
}

4. steps:某个阶段中实际执行的动作。

复制代码
steps {
    echo 'Start build'
    sh 'pwd'
    sh 'ls -la'
}

5. sh 与 bat:执行命令行。

复制代码
sh 'npm ci'          // Linux / macOS Agent
bat 'npm ci'         // Windows Agent

多行 Shell:

复制代码
sh '''
    npm ci
    npm run build
'''

6. environment:定义环境变量,避免把配置散落在命令中。

复制代码
environment {
    REGISTRY = 'harbor.example.com'
    IMAGE_NAME = 'team/demo-app'
}

在 Groovy 字符串中使用:

复制代码
echo "Image: ${REGISTRY}/${IMAGE_NAME}"

在 Shell 命令中使用:

复制代码
sh 'docker build -t $REGISTRY/$IMAGE_NAME:$BUILD_NUMBER .'

7. when:控制阶段是否执行,常用于区分分支。

复制代码
stage('Deploy') {
    when {
        branch 'main'
    }
    steps {
        sh './deploy.sh'
    }
}

8. post:定义成功、失败或始终执行的收尾动作。

复制代码
post {
    always {
        archiveArtifacts artifacts: 'build/**', allowEmptyArchive: true
    }
    success {
        echo 'Pipeline succeeded'
    }
    failure {
        echo 'Check Console Output for errors'
    }
}

二、Agent

2.1 顶层 agent和Stage agent的区别

顶层 agent Stage agent
timeout 计时起点 agent 分配之后开始 agent 分配之前开始
agent 分配时间 不计入 timeout 计入 timeout
风险 无 agent 延迟可能导致 timeout 失败

2.2 stage参数

参数 用途 示例
any 任意可用节点 agent any
none 不分配全局 agent,每个 Stage 自己指定 agent none
label 指定标签的节点 agent { label 'linux && docker' }
node 同 label,但支持更多选项(如 customWorkspace) agent { node { label 'xxx' } }
docker 在 Docker 容器中运行 agent { docker 'maven:3.9' }
dockerfile 用源码中的 Dockerfile 构建容器 agent { dockerfile true }
kubernetes 在 K8s Pod 中运行 agent { kubernetes { yaml '...' } }

三、环境变量

Jenkins Pipeline 中,环境变量通过全局对象 env 访问,例如:

复制代码
echo "Build number: ${env.BUILD_NUMBER}"

常用内置变量包括:

  • BUILD_NUMBER:当前构建编号
  • BUILD_ID:构建 ID
  • JOB_NAME:任务名称
  • BUILD_URL:本次构建页面链接
  • WORKSPACE:当前构建工作目录
  • JENKINS_URL:Jenkins 地址

完整变量列表可在 Jenkins 的 ${JENKINS_URL}/pipeline-syntax/globals#env 查看。

3.1 普通环境变量

Declarative Pipeline 使用 environment:

复制代码
pipeline {
    agent any

    environment {
        APP_NAME = 'chat-agent'
        REGISTRY = 'harbor.example.com'
    }

    stages {
        stage('Build') {
            steps {
                sh 'echo "Building $APP_NAME"'
            }
        }
    }
}

作用域有两种:

  • pipeline 下的 environment:全局生效,所有 Stage 都可使用。

  • stage 下的 environment:仅对该 Stage 的步骤生效。

    stage('Build') {
    environment {
    BUILD_MODE = 'production'
    }
    steps {
    sh 'echo $BUILD_MODE'
    }
    }

Scripted Pipeline 不用 environment,而使用 withEnv:

复制代码
withEnv(['APP_NAME=chat-agent']) {
    sh 'echo $APP_NAME'
}

补充:Declarative Pipeline和Scripted Pipeline的区别

对比 Declarative Pipeline Scripted Pipeline
风格 声明"流水线有哪些阶段" 用 Groovy 编程描述"如何执行"
基本入口 pipeline {} node {}
结构约束 强,必须遵循固定结构 弱,可自由组合代码
易读性 高,适合团队维护 较低,逻辑复杂时不易读
错误提示 较早、较清晰 常在运行时才暴露
条件/循环/函数 支持有限,复杂时需 script {} 原生支持 if、循环、函数、异常处理等
推荐场景 常规构建、测试、镜像发布、部署 动态生成 Stage、复杂分支或循环逻辑

3.2 动态设置变量

可以从 Shell 命令获取返回值:

复制代码
environment {
    VERSION = """${sh(
        returnStdout: true,
        script: 'git rev-parse --short HEAD'
    ).trim()}"""
}

注意:

  • 动态执行 sh 时,顶层必须有可用的 agent,不能是 agent none。
  • returnStdout: true 的输出通常带换行,建议加 .trim()。(因为 sh(returnStdout: true, ...) 返回的是命令的完整标准输出 ,通常包含末尾换行符 \n。).trim() 会移除字符串开头和末尾的空格、制表符和换行,保留中间内容。
  • returnStatus: true 可获取命令退出码。

3.3 使用环境变量注入 Jenkins 凭据

出于安全考虑,密码、Token 等不应该直接写进 Jenkinsfile,应先在 Jenkins 的 Credentials 中创建凭据,再通过凭据 ID 引用。

3.3.1 Secret Text

  1. Token

    environment {
    HARBOR_TOKEN = credentials('harbor-token')
    }

在 Shell 中使用:

复制代码
sh 'curl -H "Authorization: Bearer $HARBOR_TOKEN" https://harbor.example.com'
  1. 用户名和密码

    environment {
    HARBOR_CREDS = credentials('harbor-username-password')
    }

在environment中声明一次凭据绑定后,Jenkins 会自动注入三个变量:

复制代码
HARBOR_CREDS       # username:password
HARBOR_CREDS_USR   # username
HARBOR_CREDS_PSW   # password

_USR 和 _PSW 不需要、也不应分别写入 environment。使用如下,以登录 Harbor为例:

复制代码
sh 'echo "$HARBOR_CREDS_PSW" | docker login harbor.example.com -u "$HARBOR_CREDS_USR" --password-stdin'

3.3.2 Secret File

如 Kubernetes 的配置文件可使用Secret File进行保存:

复制代码
environment {
    KUBECONFIG_FILE = credentials('kubeconfig-credential')
}

变量值是 Jenkins 临时创建的安全文件路径:

复制代码
sh 'kubectl --kubeconfig "$KUBECONFIG_FILE" get pods'

3.4 安全要点

  • 凭据放在 Jenkins Credentials,不提交到 Git。
  • 尽量把凭据只定义在需要它的 stage,缩小作用域。
  • Jenkins 会在日志中掩码部分敏感值,但这只是降低误泄露风险,不代表绝对安全。
  • Shell 步骤中优先使用单引号包裹 Groovy 字符串,如 sh 'echo $TOKEN',让 Shell 展开变量;避免在 Groovy 双引号字符串中直接插入敏感变量。

补充:Groovy/Jenkinsfile 的引号,以及Shell 命令里的引号

层级 写法 是否展开变量 示例结果 / 用途
Groovy(Jenkinsfile 外层) 'echo $TOKEN' Groovy 不展开 原样传给 Shell;Shell 再展开 $TOKEN。适合凭据。
Groovy(Jenkinsfile 外层) "echo ${env.BUILD_NUMBER}" Groovy 展开 先变成 echo 123,再交给 Shell。适合非敏感变量。
Groovy 多行 '''echo "$TOKEN"''' Groovy 不展开 多行命令,交给 Shell 展开 $TOKEN。适合凭据和复杂命令。
Groovy 多行 """echo ${env.BUILD_NUMBER}""" Groovy 展开 多行命令中使用非敏感 Jenkins 变量。
Shell(命令内部) "$TOKEN" Shell 展开 输出 Token 的值;保留值内的空格,是常用安全写法。
Shell(命令内部) '$TOKEN' Shell 不展开 原样输出 $TOKEN。
Shell(命令内部) $TOKEN Shell 展开 可以使用,但如果值包含空格,可能被拆分成多个参数。

推荐组合:

场景 推荐写法 原因
使用密码、Token、密钥 sh 'curl -H "Authorization: Bearer $TOKEN" ...' 凭据由 Shell 展开,不经 Groovy 插值。
多行登录 Harbor `sh '''echo "$HARBOR_CREDS_PSW" docker login ...'''`
引用构建号、分支名等非敏感 Jenkins 值 sh "docker build -t app:${env.BUILD_NUMBER} ." Groovy 插值直观可读。
Shell 内传递路径/变量 sh 'cd "$WORKSPACE" && ./build.sh' 双引号避免路径中有空格时出错。

四、测试结果保存

要点 说明
问题 控制台输出太多,难以定位失败测试
解决 Jenkins 自动记录和汇总测试结果文件
前提 测试运行时能输出测试结果文件(如 JUnit XML)
内置支持 junit步骤(Declarative Pipeline 自带)
扩展支持 其他插件可处理非 JUnit 格式的测试报告

4.1 junit 步骤用法

复制代码
post {
    always {
        junit 'build/reports/**/*.xml'  // 收集 JUnit 格式的测试报告
    }
}
属性 说明
always 无论构建成功/失败,都执行
路径通配符 **/*.xml 递归匹配所有 XML 测试报告

补充:构建状态的区别

状态 颜色 含义
SUCCESS 绿色 全部通过
UNSTABLE 黄色 有测试失败,但 Pipeline 本身执行成功
FAILED 红色 Pipeline 执行失败(编译错误、脚本异常等)

关键区别:测试失败 = UNSTABLE(黄),构建脚本失败 = FAILED(红)

4.2 构建产物归档:archiveArtifacts

复制代码
post {
    always {
        archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
        junit 'build/reports/**/*.xml'
    }
}
参数 说明
artifacts 要归档的文件路径(支持通配符)
fingerprint 生成文件指纹,用于追踪产物来源
省略参数名 如果只传路径,可简写 archiveArtifacts 'build/libs/**/*.jar'

简写语法:

复制代码
// 完整写法
archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true

// 简写(仅路径,省略参数名)
archiveArtifacts 'build/libs/**/*.jar'

注意:多参数时必须显式指定参数名。

完整示例

复制代码
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh './gradlew build'
            }
        }
        stage('Test') {
            steps {
                sh './gradlew check'  // 运行测试
            }
        }
    }
    post {
        always {
            // 归档构建产物(jar 包)
            archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
            // 收集测试报告
            junit 'build/reports/**/*.xml'
        }
    }
}

五、清理和通知

5.1 清理

post 部分的作用

特性 说明
保证执行 Pipeline 结束时必定运行,无论成败
用途 清理资源、发送通知、记录状态
位置 Pipeline 顶层或 Stage 级别

post 的条件块

条件 触发时机 推荐
always 总是执行(无论成败) 放清理
success 仅 Pipeline 成功时 放轻量通知
unstable Pipeline 不稳定时(测试失败)
failure Pipeline 失败时 放告警
changed 当前构建状态与上一次不同时(成功→失败 或 失败→成功) 用于状态翻转告警

完整示例

复制代码
post {
    always {
        echo 'One way or another, I have finished'
        deleteDir()  // 清理工作区
    }
    success {
        echo 'I succeeded!'
    }
    unstable {
        echo 'I am unstable :/'
    }
    failure {
        echo 'I failed :('
    }
    changed {
        echo 'Things were different before...'
    }
}

常用内置步骤

步骤 用途
deleteDir() 删除当前工作区目录(清理)
cleanWs() 更彻底的清理(需 Workspace Cleanup 插件)
echo 打印日志

5.2 通知

5.2.1 邮件通知

复制代码
post {
    failure {
        mail to: 'team@example.com',
             subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
             body: "Something is wrong with ${env.BUILD_URL}"
    }
}

5.2.2 Hipchat 通知

复制代码
post {
    failure {
        hipchatSend message: "Attention @here ${env.JOB_NAME} #${env.BUILD_NUMBER} has failed.",
                    color: 'RED'
    }
}

5.2.3 Slack 通知

复制代码
post {
    success {
        slackSend channel: '#ops-room',
                  color: 'good',
                  message: "The pipeline ${currentBuild.fullDisplayName} completed successfully."
    }
}

六、部署

6.1 基本部署 Pipeline

阶段 作用
Build 编译构建
Test 测试验证
Deploy 部署发布
复制代码
pipeline {
    agent any
    stages {
        stage('Build')  { steps { echo 'Building' } }
        stage('Test')   { steps { echo 'Testing' } }
        stage('Deploy') { steps { echo 'Deploying' } }
    }
}

前序阶段失败时,后续部署不会执行。

6.2 Stage即部署环境

使用清晰的 Stage 名称区分部署目标,例如 Deploy - Staging 和 Deploy - Production。

复制代码
stage('Deploy - Staging') {
    steps {
        sh './deploy staging'      // 部署到预发布
        sh './run-smoke-tests'     // 冒烟测试
    }
}
stage('Deploy - Production') {
    steps {
        sh './deploy production'     // 部署到生产
    }
}

部署到 Staging 后执行冒烟测试,验证基础功能正常,再考虑发布 Production。

6.3 持续部署 vs 持续交付

持续部署(Continuous Deployment) 持续交付(Continuous Delivery)
定义 代码自动部署到生产环境 代码可自动部署,但需人工触发
人工确认 不需要 需要
风险 高,问题直接上线 可控,有人工把关
适用 高度自动化、测试完善 大多数企业场景

官方页面观点:纯自动持续部署不一定是好实践,持续交付更稳妥。

6.4 人工确认:input 步骤

用途 在阶段间暂停,等待人工审批
场景 Staging 验证通过后,人工确认再上 Production
效果 Pipeline 暂停,页面显示交互按钮
复制代码
stage('Sanity check') {
    steps {
        input "Does the staging environment look ok?"  // 等待人工确认
    }
}

执行效果:

复制代码
Pipeline paused at: Sanity check
[Proceed] [Abort]  ← 页面上出现按钮,需人工点击

完整 Pipeline 示例:

复制代码
pipeline {
    agent any
    stages {
        stage('Build') {
            steps { sh './build' }
        }
        stage('Test') {
            steps { sh './test' }
        }
        stage('Deploy - Staging') {
            steps {
                sh './deploy staging'
                sh './run-smoke-tests'
            }
        }
        stage('Sanity check') {          // 人工卡点
            steps {
                input "Does the staging environment look ok?"
            }
        }
        stage('Deploy - Production') {
            steps { sh './deploy production' }
        }
    }
}

七、补充

7.1 Jenkinsfile存放位置

  1. 存放在GitLab端

如果Jenkinsfile存放在GitLab端,是否还需要Pull SourceCode阶段?(Jenkins是否会拉取项目其他代码?)

参考链接1:Using a Jenkinsfile

参考链接2: Getting started with Pipeline

情况 是否要在 Jenkinsfile 写 checkout scm
使用默认检出 不需要。Jenkins 在进入第一个可执行 Stage 前自动检出项目代码。
显式控制检出流程 需要。关闭默认检出后,自己写 checkout scm。
按指定 Tag、额外仓库或自定义 Git 行为检出 需要。写完整 checkout(...)配置。
  1. 存放在Jenkins端

7.2 凭证创建

凭证创建在项目目录下,而不是个人的凭证库

7.3 问题

  1. 为什么需要先打包上传到Nexus?可以本地打包,也可以由Dockerfile包含打包。

答:(1)解耦,编译环境和运行环境分离(2)中间的打包产物可以存档,并且被多个环境使用(3)镜像构建过程更快只需要COPY现成的。

  1. Jenkins怎样将各个过程连通起来的?以及中间产生的产物?

Jenkins 每个 Pipeline 运行时,会在 Agent(构建节点)上创建一个工作目录,所有步骤共享这个目录。中间产物就是靠文件系统传递的,而非网络。

  1. 为什么Jenkins可以做到打包、构建?这应该不是借助自身的能力

Jenkins 本身并不内置打包或 Docker 的能力,它是调度器 + 插件系统,真正起作用的是所在的服务器环境。实际上是解析 Pipeline 脚本 → 生成 Shell 命令 → 调用服务器上的外部工具(Maven、Docker、Git...),所以这就要求Jenkins Agent / Node 服务器预先安装要使用到的工具(比如Git、mvn、java等)

  1. Jenkins的Agent和Node 服务器

Agent 是 Jenkins 的"抽象概念",Node 是"物理实体"。

参考

Jenkins用户手册:Jenkins Handbook

和GitLab联动:Jenkins | GitLab Docs


如有问题或建议,欢迎在评论区中留言~

相关推荐
吴声子夜歌42 分钟前
Nginx应用与运维——Nginx在Kubernetes中的应用(二)
运维·nginx·kubernetes
海绵宝宝转agent9 小时前
learn-claude-code第1-5章开源学习笔记分享
人工智能·笔记·python·学习
Ruiery9 小时前
Linux 6.6内核 CPU 深度解析(七):调度器启动 — 从单核到多核,调度器分阶段点亮
linux·运维·服务器
50万马克的面包9 小时前
CSDN-栈队列数组-知识点整理
linux·运维·服务器
每天都要写算法(努力版)10 小时前
【行业前沿报告】DAgger:让智能体在自己走到的状态上学习
人工智能·学习·机器学习
MicrosoftCloud10 小时前
用户权限 04|/etc/sudoers 安全配置:从最小授权到「别把 ALL 随便给人」
运维·安全·ubuntu·sudo·sudoers
꯭自꯭闭꯭11 小时前
达梦事物特性及MVCC
linux·运维·数据库
亚川楼宇自控系统数据中心厂家13 小时前
实验室智能化管理系统|人环物智一体化管控平台
运维
sunshine22 girl13 小时前
Java学习六 Java常见API-2--String-3-字符串的截取替换和其他方法
java·开发语言·学习
zmsup14 小时前
Agent 上下文调优:结合 OpsArk 运维智能体,设计模型每一步真正需要的信息
运维·agent·上下文压缩·运维智能体·上下文调优