ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Jenkins任务实战:五种类型、配置与排错指南

Jenkins任务实战:五种类型、配置与排错指南 装完 Jenkins 打开首页很多人第一反应是懵的左侧新建任务点进去一堆类型摆在那——自由风格、流水线、多配置、多分支、文件夹名字看着都认识合起来就不知道选哪个。更麻烦的是任务建好之后跑一次失败一次控制台日志翻半天也看不出到底是拉代码挂了还是脚本写错了。这篇就把 Jenkins 的任务从概念到落地拆开讲一遍偏实战不堆概念适合刚接手 CI 的运维、后端以及被自动化部署这个词吸引过来但还没真正跑通第一套流程的人。我把任务理解成流水线上的一个工位它知道原料从哪来源码、什么时候开工触发器、用哪些工具加工构建环境与步骤、成品放哪归档、出问题怎么报警构建后操作。把这五件事理顺剩下的都是配置项填空。1. Jenkins 任务不是点一下就跑先搞懂它的五种形态新手最容易犯的错是拿自由风格项目去硬干流水线该干的活或者反过来。类型选错了后面每一步都别扭。所以先把五种任务的边界讲清楚再谈怎么建。1.1 自由风格项目为什么至今还在用自由风格Freestyle Project是 Jenkins 最老、也最所见即所得的任务类型。整个配置界面就是一堆勾选框源码管理、构建触发器、构建环境、构建步骤、构建后操作从上到下填一遍就完事。它的优势是零学习成本一个只会写 Shell 的人十分钟就能把拉代码 打包 拷贝到服务器这条链路跑通。但它的短板也很明显。所有逻辑都固化在界面的输入框里想改就得点进页面一项项改换一个环境比如从测试切到生产要复制一份任务再手改任务一多就变成复制粘贴地狱版本控制更是无从谈起谁什么时候改了哪个参数界面本身不给你留痕迹。所以自由风格不是过时而是有明确的适用区间单条链路、结构简单、改动不频繁的任务比如每天凌晨清理一次临时目录定时拉取某个数据接口落库。这类任务本就没有复杂的分支判断用流水线反而杀鸡用牛刀。1.2 流水线任务把构建逻辑写成代码流水线Pipeline是把整个构建过程写成一份 Groovy 脚本通常放在项目根目录的Jenkinsfile里跟业务代码一起进版本库。这一点是它和自由风格最本质的差别——构建逻辑变成了可评审、可回滚、可复用的代码而不是散落在界面上的配置。Jenkinsfile 有两种写法声明式Declarative和脚本式Scripted。新手建议从声明式入手结构规整不容易写出失控的脚本pipeline { agent any stages { stage(拉取代码) { steps { checkout scm } } stage(编译打包) { steps { sh mvn clean package -DskipTests } } stage(归档制品) { steps { archiveArtifacts artifacts: target/*.jar, fingerprint: true } } } post { failure { echo 构建失败了编号 ${env.BUILD_NUMBER} } } }这段脚本的价值不在语法而在可复现换台 Jenkins 只要指向同一个仓库行为完全一致。声明式的stages强制你把流程切成阶段post块则把成功做什么、失败做什么、永远做什么统一收口比自由风格里东一个构建后操作、西一个邮件通知要清晰得多。选型建议很直接凡是需要分支逻辑比如不同分支走不同部署策略、需要多人协作维护、需要回滚构建逻辑的一律上流水线。反过来说如果一条链路永远不变用流水线就是给自己加学习成本。1.3 多配置、多分支与文件夹任务分别解决什么剩下三种类型各自解决一个特定问题混用会很难受。多配置项目Matrix Project解决的是同一套流程跑多组参数。比如同一份代码要在 JDK 8、11、17 三个版本上分别编译测试。它允许你定义多个轴axis比如 jdk 轴取值 8/11/17os 轴取值 linux/windowsJenkins 会自动做笛卡尔积生成 6 个组合并行跑。手写 6 个任务再手动维护成本高到没人愿意干。多分支流水线Multibranch Pipeline解决的是每个分支自动有自己的构建任务。它扫描指定仓库发现一个分支就自动建一个子任务分支删了这个任务也跟着消失。配合Jenkinsfile里的分支判断开发分支只跑测试、主分支才做部署是这样落地的stage(部署) { when { branch main } steps { sh ./deploy.sh } }文件夹Folder不是构建任务是组织容器。它把任务按业务线、环境或团队分组还能对文件夹整体做权限控制。任务上百之后没有文件夹的 Jenkins 首页基本没法看。任务类型最擅长的事典型误用自由风格单条简单链路拿它维护十几套环境流水线复杂逻辑、需版本化简单定时任务强行上多配置多参数组合矩阵参数其实是固定两套多分支分支自动建任务仓库分支成百上千文件夹分组与权限隔离当成构建任务使用把这张表对着自己的场景过一遍选型基本不会错。2. 一个任务从源码到制品中间要经过哪几道关任务类型定下来接下来是配置。不管是哪种类型主链路都逃不出四关拉代码、定触发、跑构建、收尾处理。这一节按执行顺序拆。2.1 源码管理Git 拉取失败的三个高频原因源码管理Source Code ManagementSCM里最常见的就是 Git。填仓库地址、选凭据、指定分支看起来比写代码简单但实际报错里一大半都出在这。第一类问题是凭据类型选错。Jenkins 的凭据分 Username/Password、SSH Username with private key、Secret text 等。用 SSH 地址git...却配了账密凭据或者用 HTTPS 地址却配了 SSH 私钥都会认证失败。判断方法很简单地址前缀是git就用 SSH 私钥是https://就用账密或 Token。报错通常长这样Permission denied (publickey)看到这个别急着改代码先看凭据。第二类问题是known_hosts 校验。Jenkins 机器第一次连某台 Git 服务器时会问是否信任这台主机但构建过程是非交互的没人能回答 yes于是直接失败。解决办法是在源码管理里选对应凭据或者在 Jenkins 所在机器上用ssh-keyscan提前把主机指纹写进 known_hosts。这一步在离线内网环境尤其关键因为内网机器上阵前根本没连过 Git 服务器。第三类问题是分支名写死。很多人填master但仓库其实叫main或者想构建任意分支却在Branch Specifier里写死了具体名字。这里推荐用*/分支名这样的通配形式或者干脆交给参数化构建后面第三节细讲来动态传。提示配置完源码管理后先在任务页面点一次立即构建看日志里 checkout 那一段确认能把代码拉到$WORKSPACE目录再往下配构建步骤。很多构建失败其实是代码压根没拉下来。2.2 触发器轮询、Webhook 和上游触发怎么选触发器决定任务什么时候自动开跑三种方式各有取舍。轮询 SCMPoll SCM让 Jenkins 定时去问 Git 服务器代码变了没。它填的是类似 cron 的表达式比如H/5 * * * *表示每 5 分钟查一次。H是 Jenkins 特有的散列写法用来把整点任务打散避免所有任务都在 00:00 同时启动把机器压垮。写法对照如下表达式含义H/5 * * * *每 5 分钟检查一次H 2 * * *每天凌晨 2 点左右检查H H(0-6) * * 1-5工作日 0 到 6 点之间某时刻检查轮询的缺点是延迟和浪费代码提交后要等到下一个轮询周期才触发而且代码没变时也在白跑查询请求。Webhook 触发是 Git 服务器在收到推送时主动通知 Jenkins实时且零浪费。GitLab 侧配置 webhook 指向 Jenkins 地址Jenkins 侧勾选Build when a change is pushed to GitLab两边对上就通了。它比轮询好但依赖网络通、依赖 Git 服务器能访问到 Jenkins内网隔离环境下经常行不通。上游任务触发是任务之间串联A 构建成功后自动触发 B。这在先编译公共库再构建业务应用的场景里非常常见配置在构建后操作里选构建其他工程即可。现实中的组合拳通常是核心仓库用 Webhook 保证实时网络受限的用轮询兜底有依赖关系的用上游触发。三者不冲突可以同时挂在一个任务上。2.3 构建环境与构建步骤脚本写在哪、怎么跑构建环境是给这次构建准备场地的比如设置超时时间、注入环境变量、准备构建节点。比较实用的两项是构建超时和使用自定义工作空间。构建超时报错卡死是运维的噩梦。很多卡死在拉取依赖或等待某个服务上不设超时任务能挂一整天占着执行器不放。建议给每个任务设一个合理上限比如30分钟超了直接失败并告警。构建步骤Build Steps是干活的地方。自由风格里可以选执行 Shell或执行 Windows 批处理命令流水线里就是sh和bat。脚本写在这里有几个常年被忽视的要点#!/bin/bash # 关键任何一步出错就退出避免错误被吞掉 set -e echo 当前构建编号: $BUILD_NUMBER echo 工作目录: $WORKSPACE # 清理旧产物避免残留文件混进新构建 rm -rf target/ echo 开始打包... mvn clean package -DskipTestsset -e这一行价值极高。默认情况下 Shell 脚本是最后一条命令的退出码决定整体成败中间某一步失败了它还会继续往下跑最后可能得到一个构建成功的假象产物其实是坏的。加上set -e任何一步非零退出立刻中断日志里一眼就能定位。另外$WORKSPACE是当前任务独占的工作目录。别在不同任务里通过写死绝对路径去共享文件那是并发冲突的头号来源后面第五节还会展开。2.4 构建后操作归档、报告与失败通知构建跑完不算结束产物要收、报告要看、失败要通知构建后操作就是干这个的。归档制品Archive the artifacts把打包出来的 jar、war、zip 存进 Jenkins构建历史里可以直接下载。它解决的是我上个月那版制品去哪找的问题。归档路径用相对$WORKSPACE的模式比如target/*.jar。发布 JUnit 测试报告做单元测试的团队一定要开。它把target/surefire-reports/*.xml解析成趋势图哪次构建开始出现测试用例变红一目了然。没这个测试结果只能靠翻日志数Tests run: 120, Failures: 2。失败通知通常是发邮件或发钉钉。这块内容比较独立放到第四节专门讲怎么把消息拼得清楚不啰嗦。这里有个常被忽略的细节归档要趁早。如果构建后面还有一步部署部署过程中清理了产物目录再归档就会报没有匹配的文件。归档路径的匹配要在部署步骤之前完成。3. 环境变量与参数化让任务从死板变得可配置如果说任务是流水线工位环境变量就是工位之间传话的通道。它让脚本能感知我在被谁跑、跑第几次、跑的是哪个分支也让同一份脚本能适配不同环境。3.1 Jenkins 自带的环境变量清单与取用姿势Jenkins 在每次构建时会自动注入一批环境变量常用的有这么几个变量名含义典型用途BUILD_NUMBER当前构建序号制品命名、日志标记BUILD_ID构建时间戳形式的 ID需要按时间排序时用JOB_NAME任务名称通知消息里标明来源WORKSPACE工作目录绝对路径脚本内路径拼接BUILD_URL本次构建的页面地址通知里附直达链接GIT_COMMIT本次构建对应的提交哈希制品打标、追溯GIT_BRANCH构建的分支按分支走不同逻辑取用方式分两套。Shell 脚本里直接用$BUILD_NUMBER流水线 Groovy 里用env.BUILD_NUMBER。写流水线时混用是最常见的低级错误——在 Groovy 的字符串里写$BUILD_NUMBER不会被 Jenkins 替换得写成env.BUILD_NUMBER或者${BUILD_NUMBER}双引号才会展开。这些变量里我最常用的是BUILD_URL。任何一条通知消息末尾附上这个链接收到消息的人点一下就能跳到日志页比在群里问哪次构建失败了效率高太多。3.2 自定义环境变量的作用域坑除了自带的Jenkins 允许你定义自己的环境变量位置在构建环境里勾选注入环境变量或设置环境变量流水线里则是environment块pipeline { agent any environment { APP_NAME user-service DEPLOY_ENV staging } stages { stage(构建) { environment { LOCAL_ONLY just-here } steps { sh echo $APP_NAME $DEPLOY_ENV $LOCAL_ONLY } } } }这里有个作用域陷阱顶层environment块里的变量对所有 stage 可见stage 内定义的只对当前 stage 可见。曾经踩过的坑是把编译参数定义在最后一个 stage 里前面几个 stage 引用的时候拿到的却是空值排查半天才发现是作用域问题。另一个坑是变量覆盖顺序。Jenkins 的变量优先级大致是任务级设置 参数化构建传入 系统级全局变量。也就是说任务里显式设了DEPLOY_ENVprod就算参数化构建传了staging最终生效的还是prod。生产环境部署这种敏感操作一定要确认这个覆盖关系否则很容易把测试代码发到生产。3.3 参数化构建的七种参数类型与传参实战参数化构建让同一个任务能在启动时接收外部输入是提升复用率的关键。常见参数类型和用途String Parameter普通文本输入比如版本号、镜像 tag。Boolean Parameter勾选框比如是否跳过测试。Choice Parameter下拉单选比如环境选择dev/test/prod。Password Parameter密码输入日志里自动打码。Text Parameter多行文本比如批量主机列表。File Parameter上传文件构建时放进$WORKSPACE。Git Parameter从仓库动态拉取分支或 tag 供选择。一个体会很深的设计原则凡是会变化、又不该写死在脚本里的值都做成参数。比如部署目标机器 IP、发布版本号、数据库连接地址。把这些硬编码进 Shell 脚本换环境就得改脚本、提交、等上线参数化之后在页面上选一下就行。调用时将参数传给脚本有两种方式。Shell 里直接读环境变量if [ $SKIP_TEST true ]; then echo 跳过测试 mvn package -DskipTests else mvn package fi流水线里则通过params.访问stage(部署) { steps { sh ./deploy.sh ${params.DEPLOY_ENV} ${params.APP_VERSION} } }注意参数化构建一旦勾选这个任务就不能用普通的立即构建来传参了得点Build with Parameters。团队协作时要把这个约定写进文档否则会有人抱怨我传的参数怎么没生效。4. 让任务自己说话通知、串联与定时策略任务跑起来了但如果没人知道它跑得怎么样自动化的价值就折损一半。这一节讲怎么让构建结果主动找到人以及任务之间怎么接力。4.1 钉钉自定义机器人的消息拼装即时通知里钉钉机器人是使用率最高的方案之一。思路是在群里创建一个自定义机器人拿到 Webhook 地址和加签密钥然后在 Jenkins 构建后调用它。最朴素的方式是直接在构建后步骤里用 curl 发请求#!/bin/bash WEBHOOKhttps://oapi.dingtalk.com/robot/send?access_token你的token curl -s -X POST $WEBHOOK \ -H Content-Type: application/json \ -d { \msgtype\: \markdown\, \markdown\: { \title\: \构建通知\, \text\: \### 构建结果\\n- 任务$JOB_NAME\\n- 编号$BUILD_NUMBER\\n- 状态失败\\n- [点击查看日志]($BUILD_URL)\ } }把这段封装成一个独立脚本文件比如notify.sh各任务调用它并传参比在每个任务里复制一遍 curl 要干净。密钥这类敏感信息不要硬编码在脚本里用 Jenkins 凭据管理构建时通过环境变量注入。一个经验消息里最重要的不是成功两个字而是可点击的直达链接和关键上下文。只说构建失败的通知等于把排查工作原封不动推给了别人。4.2 构建状态判断与消息模板设计光发一条消息还不够谁都有这次失败是偶发还是真的坏了的疑问。所以通知要分场景设计。流水线的post块天然支持状态分支可以把不同结果发到不同地方post { success { sh ./notify.sh success } failure { sh ./notify.sh failure } unstable { sh ./notify.sh unstable } aborted { sh ./notify.sh aborted } }unstable这个状态值得单独说。它通常表示构建本身成功但测试有失败用例。把它和failure混在一起告警会让真正的构建失败被淹没。合理做法是failure立即相关负责人unstable只发到群里做日报汇总。再进阶一点是失败重试抑制。同一任务连续失败 10 次就往群里刷 10 条消息属于典型的告警风暴。可以在通知脚本里做判断只有状态从成功变成失败的那一次才 全员后续持续失败只记录不打扰。这需要缓存上一次构建状态实现方式可以用一个状态文件思路是状态变化才告警。4.3 上下游任务串联与并发控制任务之间接力最常见的是公共库先构建业务应用后构建。在构建后操作里勾选构建其他工程填上游成功后要触发的下游任务名就串起来了。但串联有几个坑要防。循环触发A 触发 BB 又配置了触发 A两个任务互相叫板能把执行器瞬间占满。配置下游时一定要在脑子里画一遍依赖图确认没有环。并发冲突同一个任务被上游和定时两个触发器同时唤起两份构建共享工作空间脚本写的临时文件互相覆盖。Jenkins 有个必要时并发执行选项默认关闭意味着同一任务同一时刻只跑一个后来者排队。新手建议保持默认别急着开并发真需要并发时应该拆成两个任务而不是让一个任务自己撞自己。执行器耗尽Jenkins 每个节点有固定的执行器数量默认 2 个。任务多、又都赶在同一时间跑就会出现pending排队。解决办法有两个一是把定时任务的 cron 用H打散别都堆在整点二是给不同任务分配不同节点把负载摊开。5. 任务跑不起来时按这个顺序排查前面讲的是怎么建这一节讲建完之后跑不通怎么办。我习惯按实例是否在线 → 插件源是否可用 → 工作空间与权限 → 资源是否耗尽的顺序查从外到内能过滤掉大部分低级问题。5.1 实例离线与插件源不可用的处理打开 Jenkins 页面顶部飘红提示该 Jenkins 实例似乎已离线先别怀疑配置。这个提示通常有三种含义Jenkins 主进程没启动、主进程启动了但页面加载的资源CSS/JS取不到、或者主从节点通信断了。第一种看进程第二种多半是浏览器到服务器网络问题第三种看节点的Launch agent日志。内网离线环境里插件装不上是另一个高频问题。Jenkins 默认去公网插件站点拉元数据连不上就一直转圈。处理办法是进系统管理 → 插件管理 → 高级把 Update Site 换成内网可达的镜像地址或者干脆手动下载.hpi文件后上传安装。手动装插件时要注意依赖关系一个插件往往依赖另外几个版本对不上会启动报错。安装环节如果打算离线部署建议提前在有网络的机器上把jenkins.war和常用插件一并下载好把插件放进$JENKINS_HOME/plugins目录再整体拷贝过去。这比到了内网再一个个找插件要省事得多。5.2 工作空间冲突与权限问题构建日志里出现大量Permission denied先分清两类。一类是文件权限比如 Jenkins 用户对$WORKSPACE没有写权限或者执行脚本没有x位。另一类是系统调用权限比如某些操作需要更高权限这在容器化部署的 Jenkins 里尤其常见。工作空间冲突的典型症状是构建时快时慢偶尔产物损坏。根源常常是多个任务共用了同一份目录。Jenkins 的$WORKSPACE设计上就是给单个任务独占的跨任务共享文件应该走归档制品或专门的共享存储而不是直接去读写别人的工作目录。还有一种隐蔽情况脚本里用了相对路径但构建步骤的默认工作目录和你想的不一样。养成在构建脚本开头加cd $WORKSPACE或者打印pwd的习惯能省下大量我的文件呢的困惑。5.3 并发、磁盘与执行器耗尽任务卡在pending不跑常见原因是执行器满了。进节点管理页面看看有多少个 executor再看看有多少构建在排队。临时解法是调大执行器数量长期解法是优化任务时长、把重任务分散到不同节点。磁盘写满也经常被忽视。Jenkins 的构建历史默认一直保留日积月累$JENKINS_HOME/jobs下的旧构建产物能把磁盘吃干净。构建一失败就开始各种诡异报错清理磁盘后又好了。建议给每个任务设置构建保留策略比如最多保留 30 次构建或保留最近 7 天用丢弃旧的构建配置项就能做到。这个设置越早开越好等磁盘满了再清理运维成本会翻几倍。我把这些年在 Jenkins 上踩的坑归纳成一句话构建失败十次里有七八次问题不在脚本而在环境、权限和依赖这些任务之外的东西。所以排查时别一头扎进 Shell 代码先确认基础条件齐不齐。最后再分享一个自己一直在用的习惯每建一个新任务第一次先加一句echo 变量: $BUILD_NUMBER, 目录: $WORKSPACE, 分支: $GIT_BRANCH跑通了再往里填真正的构建逻辑。这一句话看起来笨但它能在几秒钟内证明任务确实被触发了、环境确实进来了、代码确实在正确的目录比盲猜配置快得多。任务多了之后把这句探测语句固化成一个任务模板新建任务时先复制模板再改比从空白页开始配要省心。
返回列表