Jenkins节点离线自动通知怎么实现?配置怎么做?

文章导读
节点离线告警这件事,大多数情况下问题不在“怎么发消息”,而在“别误报”。我见过不少团队把脚本写完,结果每次重启节点或调整Kubernetes节点池时,告警群就炸一遍。所以下面的处理顺序是:先确认离线判断的条件,再配置定时任务,最后验证通知链路。
📋 目录
  1. 先区分“真离线”和“临时离线”
  2. 用 Freestyle 任务做定时检查,别一上来就写管道
  3. 邮件发送:方法对,但SMTP配置通常才是瓶颈
  4. 脚本里要加超时、去重和冷却,否则通知会变成新的故障
  5. 如果团队不用邮件,改成企业微信/钉钉通知
  6. 改完后看这几个信号
A A

节点离线告警这件事,大多数情况下问题不在“怎么发消息”,而在“别误报”。我见过不少团队把脚本写完,结果每次重启节点或调整Kubernetes节点池时,告警群就炸一遍。所以下面的处理顺序是:先确认离线判断的条件,再配置定时任务,最后验证通知链路。

Jenkins节点离线不能只看页面状态,脚本中要通过实例化节点对象来获取准确信息。在Groovy中,使用`Jenkins.instance.getNode(name)`获取节点,然后通过`computer.isOffline()`判断是否离线。注意`isOffline()`返回`true`表示节点处于离线状态,且当节点被临时断连(如用户手动暂停)时也会返回`true`。如果只想检查真正故障,还需检查`computer.isTemporarilyOffline()`,并将两者结合。否则可能会在运维重启节点时误发告警。

一个常见做法是创建一个“节点健康检查”的Freestyle任务,配置为每5分钟构建一次。构建步骤选择“执行系统Groovy脚本”,脚本中遍历所有节点,将离线节点信息汇总,如果有离线节点就调用`Mailer`发送通知。这种方案不需要额外插件,仅依赖Jenkins自带能力。关键点在于任务要使用系统凭证,且脚本能访问Jenkins内部API。如果担心多个节点同时离线造成通知风暴,可以在脚本中加入去重或者冷却时间。

先区分“真离线”和“临时离线”

Jenkins节点离线不能只看页面状态,脚本中要通过实例化节点对象来获取准确信息。在Groovy中,使用Jenkins.instance.getNode(name)获取节点,然后通过computer.isOffline()判断是否离线。注意isOffline()返回true表示节点处于离线状态,且当节点被临时断连(如用户手动暂停)时也会返回true。如果只想检查真正故障,还需检查computer.isTemporarilyOffline(),并将两者结合。否则可能会在运维重启节点时误发告警。

这段逻辑可以直接在脚本控制台验证,先针对一个正常节点跑,再针对一个手动Disconnect的节点跑。示例判断片段如下:

Jenkins节点离线自动通知怎么实现?配置怎么做?
def node = Jenkins.instance.getNode('agent-01')
def computer = node.getComputer()
println('offline=' + computer.isOffline())
println('temporarilyOffline=' + computer.isTemporarilyOffline())

如果两个布尔值都返回true,而你是在界面上手动Disconnect的,就应该过滤掉这次离线。如果只有isOffline()是true,isTemporarilyOffline()是false,那多半是连接断了,可以告警。不同版本的Jenkins在节点“启动中”状态时,两个值可能都是true,建议在你们实际环境里的启动阶段记录一次返回值。

用 Freestyle 任务做定时检查,别一上来就写管道

一个常见做法是创建一个“节点健康检查”的Freestyle任务,配置为每5分钟构建一次。构建步骤选择“执行系统Groovy脚本”,脚本中遍历所有节点,将离线节点信息汇总,如果有离线节点就调用Mailer发送通知。这种方案不需要额外插件,仅依赖Jenkins自带能力。关键点在于任务要使用系统凭证,且脚本能访问Jenkins内部API。如果担心多个节点同时离线造成通知风暴,可以在脚本中加入去重或者冷却时间。

补充一点,这里的“执行系统Groovy脚本”运行在主节点JVM内,脚本能直接访问Jenkins内部对象,所以不需要在某个节点上安装额外环境。任务触发方式用“Build periodically”,在Schedule里填H/5 * * * *。但H/5表示在5分钟窗口内分散执行,不是精确的每5分钟整点。如果节点很多,建议把周期拉长到10分钟或15分钟。脚本里最好用deadline变量控制总时长,避免某一次网络超时拖垮整个任务。

Jenkins节点离线自动通知怎么实现?配置怎么做?

邮件发送:方法对,但SMTP配置通常才是瓶颈

在Groovy脚本中发送邮件可以先构造MimeMessage,或者直接调用jenkins.model.JenkinsgetMailer()把消息发往所有管理员。更灵活的方式是使用hudson.tasks.Mailer类,设置收件人、主题和正文。示例代码片段如下:def mailer = new hudson.tasks.Mailer("recipient@example.com", "subject", "body"); mailer.send()。但必须确认Jenkins已配置好SMTP服务器,否则发送会静默失败。建议先在脚本控制台测试一条邮件再部署到任务中。

在写脚本之前,先检查系统管理 — 系统配置 — E-mail Notification里SMTP服务器、使用SSL、认证信息是否完整。很多团队只填了发件地址,没有填认证密码,测试邮件偶尔通过,但脚本执行时会抛AuthenticationFailedException。另外,因为脚本运行在主节点,Java的DNS解析和代理设置也可能影响发送。如果公司邮件网关要求发件域名与服务器一致,也需要提前确认,否则测试邮件能到,任务触发时却被服务端拦截。

脚本里要加超时、去重和冷却,否则通知会变成新的故障

直接写一个循环遍历所有节点,发现一个离线就立刻发邮件,这样会有两个问题:一是节点多时,脚本运行时间会被网络超时拖长;二是同一个节点断连再恢复再断连,会重复告警。我习惯加两个开关:第一个是冷却时间,用Jenkins的一个隐藏文件记录每个节点上次告警时间,例如在${JENKINS_HOME}/offline-notify.properties里写时间戳,15分钟之内同一个节点不重复发送。第二个是连续确认,连续两次检查都判定离线,并且不是临时离线,才发送。这样虽然会延迟最多一个周期,但能滤掉大量抖动。

脚本本身必须设置超时控制。如果使用HttpURLConnection发送Webhook,设置connectTimeout=5000readTimeout=5000,防止通知接口卡住。使用HttpClient则需要额外引入依赖,我更建议用JDK自带的方式。

Jenkins节点离线自动通知怎么实现?配置怎么做?

如果团队不用邮件,改成企业微信/钉钉通知

企业微信或钉钉机器人不需要再配SMTP,但Webhook地址需要能被Jenkins主节点访问。在Groovy脚本中,检测到离线节点后,调用Webhook即可。下面是一个最小发送片段,注意不要放在循环里重复创建连接:

def sendMsg(String webhook, String content) {
    def data = '{"msgtype":"text","text":{"content":"' + content + '"}}'
    def conn = new URL(webhook).openConnection()
    conn.setRequestMethod('POST')
    conn.setDoOutput(true)
    conn.setConnectTimeout(5000)
    conn.setReadTimeout(5000)
    conn.getOutputStream().write(data.getBytes('UTF-8'))
    println(conn.getResponseCode())
}

这段代码没有处理JSON转义,如果节点名里包含引号或换行,消息体就会解析失败。实际使用时建议先用JsonOutput构造消息体,或者对content做转义。Webhook地址不应硬编码在脚本里,最好放到Jenkins全局凭据中,用withCredentials读取。钉钉的机器人消息格式略有不同,需要把消息体改成markdown或actionCard,这个根据团队实际使用的机器人类型调整。

改完后看这几个信号

  • 在脚本控制台手动执行第一小节的判断逻辑,先对一个正常节点和一个手动断开的节点分别测试,记录两个返回值的组合。
  • 配置完Freestyle任务后,先点“立即构建”触发一次,不要等周期调度。如果已经加了冷却时间,要等冷却结束后再测。
  • 打开任务控制台输出,确认脚本打印的节点列表和离线条数符合预期,没有异常堆栈。
  • 检查收件箱和垃圾箱。如果邮件没到达,看Jenkins日志或使用tcpdump抓包,而不是反复点发送。
  • 企业微信/钉钉场景下,确认机器人有发送权限,Webhook地址没有被防火墙拦截。

离线通知的最终目标是减少人工盯着页面。如果有条件,建议把通知脚本纳入版本库,让团队评审。每次Jenkins大版本升级后,重新在脚本控制台跑一遍判断逻辑,因为Groovy对象的行为可能在插件更新后改变。