🔧 Windows 服务器 Jenkins 节点开机自启

遇到的问题

最近在工作中遇到一个比较冷门的问题,让我头疼了很久。我们的自动化测试环境是这样的:

  • Jenkins Master:1 台 Linux 服务器(Ubuntu)
  • Jenkins 节点:5 台 Windows 10 服务器运行自动化测试任务

问题就出在这些 Windows 服务器上。由于公司安全要求,服务器必须设置密码,我之前的解决方案是:

  • 设置计划任务在开机时启动 Jenkins 节点
  • 使用开机自启动文件夹(shell:startup)放置启动脚本

但是这两种方法都有一个致命问题:必须要用户登录后才能执行

这就导致了一个很麻烦的情况:每次服务器重启后(无论是定期维护重启还是意外重启),我都必须手动 RDP 连接到每台服务器登录一次,Jenkins 节点才能正常启动。

💡 想象一下这个场景:凌晨 3 点服务器自动重启了,第二天上班发现所有自动化测试都没跑,然后我要一台一台去连接登录…

这个问题困扰了我挺久,一直没有集中精力去解决,这次决定一劳永逸地解决它。

第一次尝试:使用 sc 命令

通过搜集资料,我了解到 shell:startup计划任务 都需要登录后才执行,这不符合我的需求。然后我发现了一个新思路:Windows 系统服务

系统服务的特点是:

  • 开机自动启动,无需用户登录
  • 在后台运行,不依赖用户会话
  • 可以设置自动重启策略

看起来很完美!我立即动手尝试。

创建服务

我使用管理员身份运行 cmd,用 sc 命令注册 Jenkins 服务:

1
sc create "JenkinsNodeService" binPath= "\"[Java安装路径]\bin\java.exe\" -jar \"[Jenkins工作目录]\agent.jar\" -url http://[Jenkins-Master-IP]:[端口]/ -secret [节点密钥] -name \"[节点名称]\" -webSocket -workDir \"[Jenkins工作目录]\"" start= auto DisplayName= "Jenkins 节点服务"

命令参数说明

  • JenkinsNodeService:服务名称
  • binPath:服务程序的完整启动命令
  • start= auto:设置为自动启动
  • DisplayName:在服务管理器中显示的名称

✅ 服务创建成功了,在 Windows 服务管理器中也能看到”Jenkins 节点服务”。

我心想:这下应该没问题了吧!但是当我启动服务时,现实给了我一记重锤…

遇到的挫折:1053 错误

启动服务后,系统无情地提示:

“[SC] StartService 失败 1053:服务没有及时响应启动或控制请求”

更奇怪的是,我在 Jenkins Master 上观察到节点确实连接上了,但是持续十几秒后又掉线了。这让我很困惑:明明程序启动了,为什么服务还是失败?

深入调查

经过一番调查和查阅资料,我终于找到了问题的根源:

Windows 服务的生命周期管理机制

  1. 当启动一个服务时,系统会启动指定的程序
  2. 系统期望程序在 30 秒内 调用 SetServiceStatus API 告诉系统”我已经启动成功了”
  3. 如果 30 秒内没有收到确认信号,系统就认为服务启动失败
  4. 系统会强制终止该进程,并标记服务为”失败”状态

而我用 sc 命令注册的服务程序(java.exe 启动的 Jenkins 节点)是一个普通的后台进程,它:

  • ✅ 能正常启动并连接到 Jenkins Master
  • ❌ 但不知道要向 Windows 系统报告服务状态
  • ❌ 不会调用 SetServiceStatus API

所以系统等了 30 秒没收到确认信号,就认为服务启动失败,强制停止了进程。这就是 1053 错误的根本原因

😤 这个方法行不通,我需要找其他解决方案。

找到解决方案:NSSM

在继续搜索解决方案时,我发现了一个神器:NSSM(Non-Sucking Service Manager)

NSSM 的作用就像一个”服务代理”或”翻译官”:

  • 它本身是一个标准的 Windows 服务
  • 它会启动并监控你指定的程序(比如 Java 进程)
  • 它负责与 Windows 系统进行服务状态的通信
  • 完美解决普通程序无法作为服务运行的问题

💡 简单来说:NSSM 帮你的程序”伪装”成一个标准的 Windows 服务。

下载 NSSM

我从以下地址下载了 NSSM:

下载的是 nssm-2.24.zip,解压后有 32 位和 64 位两个版本,根据系统选择对应的 nssm.exe

安装过程

下载解压后,打开管理员命令提示符,进入到 nssm 目录,执行:

1
nssm.exe install JenkinsNodeService

这会打开一个图形化的 NSSM Service Installer 配置界面,比命令行友好多了!

我在界面中填入了以下信息:

Application 选项卡

  • Path[Java安装路径]\bin\java.exe

    • 作用:指定 Java 可执行文件的完整路径
    • 示例:C:\Program Files\Java\jdk-11\bin\java.exe
  • Startup directory[Jenkins工作目录]

    • 作用:设置程序启动时的工作目录
    • 示例:C:\jenkins
  • Arguments:Jenkins 节点启动参数

    1
    -jar "[Jenkins工作目录]\agent.jar" -url http://[Jenkins-Master-IP]:[端口]/ -secret [节点密钥] -name "[节点名称]" -webSocket -workDir "[Jenkins工作目录]"

    参数说明

    • -jar:指定要运行的 JAR 文件
    • -url:Jenkins Master 的访问地址
    • -secret:节点连接密钥(在 Jenkins 节点配置页面获取)
    • -name:节点名称(必须与 Jenkins 中配置的节点名称一致)
    • -webSocket:使用 WebSocket 连接方式
    • -workDir:指定节点的工作目录

Details 选项卡(可选):

  • Display nameJenkins 节点服务

    • 作用:在 Windows 服务管理器中显示的服务名称
  • DescriptionJenkins 自动化测试节点服务

    • 作用:服务的详细描述信息

点击 “Install service” 按钮后,弹出成功提示:

“Service ‘JenkinsNodeService’ installed successfully!”

服务安装完成!

测试结果

安装完成后,我怀着忐忑的心情启动了服务:

1
nssm.exe start JenkinsNodeService

🎉 奇迹发生了!这次没有出现 1053 错误!

我立即检查服务状态:

1
sc query JenkinsNodeService

显示 STATE: RUNNING,服务正常运行。

更重要的是,我在 Jenkins Master 上看到:

  • ✅ 节点状态变成了”已连接”
  • ✅ 连接状态稳定,没有再掉线
  • ✅ 自动化测试任务可以正常分发到这个节点

验证开机自启动

为了验证是否真的解决了问题,我做了最关键的测试:重启服务器

我重启了其中一台 Windows 服务器,然后:

  1. 没有进行任何手动 RDP 登录操作
  2. 等待服务器完全启动
  3. 🔍 直接检查 Jenkins Master 的节点状态

结果让我激动不已:

🎯 节点已经自动连接上了!

我又测试了其他几台服务器,结果都一样完美。

🎊 问题彻底解决

现在的情况是:

  • ✅ 所有 Windows 服务器重启后,Jenkins 节点都能自动启动
  • ✅ 不再需要手动 RDP 登录
  • ✅ 真正实现了无人值守的自动化测试环境
  • ✅ 再也不用担心凌晨服务器重启导致测试中断

这个困扰了我很久的问题终于彻底解决了!

踩过的坑和经验总结

为什么 sc 命令不行

在解决这个问题的过程中,我深入了解了为什么 sc 命令创建的服务会失败:

Windows 服务有严格的生命周期管理。当你启动一个服务时,系统期望服务程序在 30 秒内调用 SetServiceStatus API 告诉系统”我已经启动成功了”。但是普通的 Java 程序(比如 Jenkins agent)并不知道这个规则,它只是正常启动并运行,不会主动向系统报告状态。

所以系统等了 30 秒没收到确认信号,就认为服务启动失败,强制停止了服务。这就是 1053 错误的根本原因。

NSSM 的作用

NSSM 就像一个”翻译官”,它:

  1. 接收系统的服务控制信号
  2. 启动并监控你的实际程序(Java 进程)
  3. 向系统报告正确的服务状态
  4. 处理服务的启动、停止、重启等操作

这样就完美解决了普通程序无法作为 Windows 服务运行的问题。

配置注意事项

在配置过程中,我踩了几个小坑,总结一下经验:

  1. Secret 要保密

    • ⚠️ 不要在日志、截图或文档中暴露 Jenkins 的 Secret 密钥
    • 💡 可以用 [your-secret-key] 这样的占位符代替
  2. 工作目录权限

    • 确保 Jenkins 工作目录(如 C:\jenkins)有读写权限
    • 服务默认使用 Local System 账户运行,通常权限足够
  3. 环境变量问题

    • ⚠️ 重要:Windows 服务无法访问用户级环境变量
    • 问题现象:该节点执行构建找不到 pnpm、命令
    • 解决方案:将用户级环境变量添加到系统级环境变量
    • 具体操作:
      1. 右键”此电脑” → 属性 → 高级系统设置 → 环境变量
      2. 在”系统变量”的 Path 中添加:C:\Users\[用户名]\AppData\Roaming\npm
      3. 重启服务使环境变量生效

总结

这个困扰了我很久的问题终于解决了。主要收获:

  1. 理解了 Windows 服务机制:普通程序无法直接作为服务运行,需要 NSSM 这样的服务包装器
  2. 学会了 NSSM 工具:不仅适用于 Jenkins,任何控制台程序都可以用它注册为服务
  3. 解决问题要找根本原因:不是头痛医头,而是深入分析本质

现在我们的自动化测试环境实现了真正的无人值守,服务器重启后 Jenkins 节点自动连接,再也不用手动登录了。