Administrator
Administrator
发布于 2026-10-31 / 0 阅读
0
0

第一条 Jenkins 流水线怎么写:让失败可见,让产物可追踪

面向初级运维:已经能登录 Jenkins,准备写第一条 Pipeline。本文使用单独的练习任务,在 Linux agent 上生成文本和压缩包,不连接生产发布环境。文中的运行结果与故障现象均为教学预期。

Jenkins 首条流水线:选择节点、准备、检查、打包与归档

1. 第一条流水线应该验证什么

一条能打印 Hello World 的流水线,可以证明任务被启动了。但真正接手构建任务时,还需要知道:命令在哪里运行、错误能否传给 Jenkins、产物保存在哪、失败后能留下什么信息。

本篇把这四件事放在一个小练习里。正常运行时生成报告并打包;勾选一个参数后,让检查阶段故意失败,观察后续阶段和产物的变化。

2. 先确认命令运行在 agent 上

Jenkins controller 负责协调任务,agent 提供执行环境。sh 命令在被分配的 agent 及其工作区里执行,不一定是你打开浏览器时想到的那台机器。

本例要求:已经安装 Pipeline 及 Declarative Pipeline 相关插件,有一台在线 Linux agent,标签包含 linux,并安装了普通 Shell、grep 和 tar。用独立的练习任务和工作区执行。若实际标签不同,应修改下面的 label。

在 Jenkins 新建一个 Pipeline 类型任务,定义选择 Pipeline script。首次练习直接填写脚本,后续可以迁移到代码仓库的 Jenkinsfile。节点和步骤的对应关系见 Pipeline Nodes and Processes 文档。

3. 一份可以逐段阅读的 Jenkinsfile

pipeline {
    agent { label 'linux' }

    options {
        skipDefaultCheckout()
        disableConcurrentBuilds()
        timeout(time: 5, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }

    parameters {
        booleanParam(name: 'FAIL_DEMO', defaultValue: false,
                     description: 'Enable an intentional failure in the Check stage')
    }

    stages {
        stage('Prepare') {
            steps {
                sh '''
                    set -eu
                    REPORT_DIR="reports/$BUILD_NUMBER"
                    mkdir -p "$REPORT_DIR"
                    echo "build=$BUILD_NUMBER" > "$REPORT_DIR/report.txt"
                    echo "agent=$NODE_NAME" >> "$REPORT_DIR/report.txt"
                    echo "fail_demo=$FAIL_DEMO" >> "$REPORT_DIR/report.txt"
                    pwd
                '''
            }
        }

        stage('Check') {
            steps {
                sh '''
                    set -eu
                    if [ "$FAIL_DEMO" = "true" ]; then
                        echo "Intentional failure for learning" >&2
                        exit 1
                    fi
                    grep -q '^build=' "reports/$BUILD_NUMBER/report.txt"
                    echo "Report check passed"
                '''
            }
        }

        stage('Package') {
            steps {
                sh '''
                    set -eu
                    REPORT_DIR="reports/$BUILD_NUMBER"
                    tar -czf "$REPORT_DIR/report.tar.gz" \
                        -C "$REPORT_DIR" report.txt
                '''
            }
        }
    }

    post {
        always {
            archiveArtifacts artifacts: "reports/${env.BUILD_NUMBER}/*",
                             allowEmptyArchive: true,
                             fingerprint: true
        }
        success {
            echo 'Demo pipeline completed successfully'
        }
        failure {
            echo 'Demo failed; inspect the first failed step and console log'
        }
    }
}

这里用声明式 Pipeline 组织 agent、options、parameters、stages 和 post。完整语法可查 Jenkins Pipeline Syntax。练习中的 Shell 代码使用普通 POSIX 写法,没有依赖 Bash 数组或 [[ ... ]]。

4. 第一次运行:看阶段,也看实际产物

保存后执行一次构建,保持 FAIL_DEMO=false。某些 Jenkins 界面要先运行一次,才显示参数化构建入口;之后可以使用 Build with Parameters。

正常预期如下:

位置 应看到的结果
Prepare 创建本次编号的目录,日志显示工作区路径
Check 输出 Report check passed
Package 生成 report.tar.gz
构建结果 SUCCESS
构建产物 本次编号下的 report.txt 和 report.tar.gz

下载文本文件,确认 build 与当前构建编号一致。再查看压缩包里的文件,应该只有这次生成的 report.txt。

按构建编号使用子目录,可以避免把上一次工作区里的同名产物误认成本次结果。归档模式也只匹配当前编号。archiveArtifacts 的路径相对于工作区,不能归档任意系统路径;详见 Jenkins Core 归档说明。

5. 第二次运行:故意失败一次,观察错误是否可见

再次构建,勾选 FAIL_DEMO。这次预期:

  1. Prepare 完成,留下当前构建的报告。
  2. Check 输出教学错误,并以 1 退出。
  3. Package 因前面失败而跳过。
  4. post 的 always 尝试归档已经生成的报告,failure 输出提示。
  5. 构建结果为 FAILURE,本次没有成功打包的压缩包。

普通 sh 步骤在脚本返回非零状态时会失败。如果使用 returnStatus: true,就需要自己检查返回值并决定是否终止,否则有可能把失败吞掉。这个区别见 sh 步骤的官方参数说明。

有一份报告能下载,只能证明该文件被生成并归档。它是在检查前创建的,不能作为本次构建成功的证明。

6. 为什么失败后还要归档,为什么允许归档为空

失败后,诊断日志和中间报告往往比最终压缩包更有价值。因此把归档放进 post { always { ... } },可以在步骤正常失败时保留已有证据。

若 Prepare 在创建文件之前就失败,归档可能找不到内容。allowEmptyArchive: true 允许这种情况,不会仅因为没有匹配文件再产生一个归档错误;它并不会把之前的构建失败改成成功。

如果 agent 断连、工作区不可访问或 Jenkins 出现基础设施故障,归档仍可能无法完成,always 也不是产物必定送达的保证。要同时查看失败步骤和 post 阶段的日志。

这里的 fingerprint 用于产物来源和使用关系追踪,不是代码签名或安全校验凭证。归档文件本身也不是长期备份;本例只保留最近 10 次构建记录及关联产物。工作区中的旧目录不由这个保留选项自动清理,需要按团队策略另行管理。

7. 遇到报错,先定位在分配节点、解析还是执行阶段

现象 优先检查
一直等待可用 executor agent 是否在线、label 是否匹配、执行槽是否空闲
Jenkinsfile 解析失败 括号、声明式结构、插件是否支持所用指令
sh 无法执行 agent 是否为 Linux、Shell 是否可用
tar: not found 工具是否安装在实际 agent 的 PATH 中
Permission denied agent 执行用户、工作区和文件权限
有日志却没有归档 路径模式、本次构建目录、post 是否成功

Pipeline 的 Snippet Generator 和声明式校验器,适合核对当前 Jenkins 实际支持的语法;入口与用法见 Pipeline Development Tools。本地 Shell 语法检查不能代替 Jenkins 自己的解析和调度验证。

8. 跑通后怎样接入真实项目

下一步可以把 Jenkinsfile 放进仓库,将 Prepare 换成代码检出,将 Check 换成真正的单元测试,将 Package 换成项目构建。先在测试项目上验证成功和失败两条路径,再考虑部署步骤。

仓库密码和发布凭据通过 Jenkins 凭据功能提供,并限制使用范围;不要直接写进 Jenkinsfile 或输出到控制台。这样第一条流水线留下的就不只是绿色状态,还有可核对的执行位置、失败信号和本次产物。


评论