Jenkins Slave 节点重建后 SSH 认证失败的排查与恢复

生产服务器意外崩溃,重新申请了相同 IP 的机器并重做了免密登录,但 Jenkins slave 节点持续离线,日志显示 SSH 认证失败。本文记录完整的排查与恢复过程。

问题现象

打开 Jenkins → Nodes → slave-01 → Log,看到如下循环报错:

[05/07/26 17:11:54] [SSH] Opening SSH connection to 10.0.0.10:22.
Searching for 10.0.0.10 in /root/.ssh/known_hosts
Searching for 10.0.0.10:22 in /root/.ssh/known_hosts
[05/07/26 17:11:54] [SSH] SSH host key matches key in Known Hosts file.
ERROR: Failed to authenticate as root. Wrong password.
(credentialId:jenkins-slave-01/method:password)
[05/07/26 17:11:57] [SSH] Authentication failed.
Authentication failed.
[05/07/26 17:11:57] Launch failed – cleaning up connection
[05/07/26 17:11:57] [SSH] Connection closed.

节点状态显示为 offline,每隔几分钟自动重试,均以失败告终。


根因分析

很多人第一反应是”新机器缺少 Java 环境”,但仔细阅读日志,连接在认证阶段就已失败,根本没有到达 JVM 启动环节。

真正的问题链条如下:

旧机器崩溃

新机器申请(相同 IP:10.0.0.10)

重做了系统层面的 SSH 免密(authorized_keys)

但 Jenkins 的 Credential 存储的是「密码」而非「SSH Key」

新机器 root 密码 ≠ Jenkins 存储的旧密码

认证失败,节点无法上线

关键日志特征:method:password —— 说明 Jenkins 走的是密码认证,不是 SSH Key 认证,所以手动配的免密对 Jenkins 完全没有生效。


完整恢复步骤

Step 1 — 验证网络和 SSH 基础连通性

先在 Jenkins Master 上确认能正常 SSH 登录新机器:

ssh root@10.0.0.10

如果提示 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED,说明新机器的主机指纹和 known_hosts 里的旧记录冲突,需要先清理:

# 删除旧指纹
ssh-keygen -R 10.0.0.10

# 重新连接,接受新指纹
ssh root@10.0.0.10

这一步经常被忽略,但 Jenkins 的 KnownHostsFileKeyVerificationStrategy 依赖本机 known_hosts,指纹不匹配会导致连接直接被拒绝。


Step 2 — 切换为 SSH Key 认证(推荐,一劳永逸)

2.1 生成或复用 Jenkins Master 的密钥对

# 检查是否已有密钥
ls ~/.ssh/id_rsa

# 没有则生成
ssh-keygen -t rsa -b 4096 -C "jenkins-master" -f ~/.ssh/id_rsa -N ""

2.2 将公钥写入新 slave 机器

ssh-copy-id root@10.0.0.10

# 或手动方式
cat ~/.ssh/id_rsa.pub | ssh root@10.0.0.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

2.3 验证免密登录

ssh -o PasswordAuthentication=no root@10.0.0.10 "echo OK"
# 输出 OK 则成功

Step 3 — 更新 Jenkins Credential

进入 Jenkins Web UI:

Manage Jenkins → Credentials → System → Global credentials
→ 找到 jenkins-slave-01 → 点击修改

将凭据类型从 Username with password 修改为 SSH Username with private key

字段
Kind SSH Username with private key
Username root
Private Key 选择 Enter directly,粘贴 ~/.ssh/id_rsa 私钥内容
Passphrase 生成时设置了则填写,否则留空

私钥内容获取:

cat ~/.ssh/id_rsa
# 复制全部内容,包括 -----BEGIN/END----- 行

Step 4 — 确认 slave 节点的 Java 环境

认证问题解决后,Jenkins 会尝试通过 SSH 在 slave 上启动 agent。
查看 slave 节点的 Configure 页面,找到 JavaPath 配置项:

/opt/jdk-17/bin/java

在新机器上确认该路径存在:

ls /opt/jdk-17/bin/java
java -version

如果路径不存在,有两种处理方式:

方式 A:安装 Java 到相同路径

# 下载对应版本的 JDK(以 Eclipse Temurin 为例)
wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz
mkdir -p /opt
tar -xzf OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz -C /opt/

方式 B:安装系统 Java 并更新 Jenkins 配置

# Ubuntu/Debian
apt update && apt install -y openjdk-17-jdk

# CentOS/RHEL
yum install -y java-17-openjdk

# 获取实际路径
which java # 或 update-alternatives --list java

然后在 Jenkins slave 节点 Configure → JavaPath 中填写新路径。


Step 5 — 重启 slave 节点连接

在 Jenkins slave 节点页面点击 Launch agent 或等待自动重试,观察 Log 输出:

[SSH] Opening SSH connection to 10.0.0.10:22.
[SSH] SSH host key matches key in Known Hosts file. Connection will be allowed.
[SSH] Authentication successful.
Remoting version: ...
Agent successfully connected and online

看到 Authentication successfulonline 即恢复成功。


问题复盘

排查点 状态 说明
网络连通性 正常 SSH 端口 22 正常
known_hosts 指纹 需清理 新机器指纹变更,旧记录需删除
Jenkins Credential 类型 根本原因 password 方式,密码与新机器不符
slave 上的 Java 环境 需确认 新机器需重新安装并确认路径一致

经验总结

1. 优先使用 SSH Key 认证,而不是密码

密码认证在机器重建时必然失效;SSH Key 认证只要提前同步公钥,重建后无需修改 Jenkins 任何配置。

2. 机器重建后必须清理 known_hosts

ssh-keygen -R <ip>

这一步是 checklist 里必须有的一项,否则即使认证方式正确,指纹不匹配也会导致连接被拒绝。

3. 将 slave 初始化写成脚本

新机器上线时一键初始化,避免手工遗漏:

#!/bin/bash
# jenkins-slave-init.sh

set -e

JAVA_INSTALL_DIR="/opt"
JENKINS_MASTER_PUBKEY="ssh-rsa AAAA... jenkins-master"

echo "[1/4] Installing Java..."
apt update -qq && apt install -y openjdk-17-jdk

echo "[2/4] Setting up SSH authorized_keys..."
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "$JENKINS_MASTER_PUBKEY" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

echo "[3/4] Creating Jenkins workspace directory..."
mkdir -p /data/jenkins/workspace

echo "[4/4] Done. Java path: $(which java)"
java -version

4. 考虑使用 Jenkins Configuration as Code(JCasC)

将 slave 节点配置纳入版本控制,机器重建后配置自动恢复,彻底消除人工操作失误的可能。


参考资料

  • Jenkins SSH Build Agents Plugin
  • Eclipse Temurin JDK Downloads
  • Jenkins Configuration as Code Plugin