在 Proxmox VE 虚拟化环境中搭建集群时,大量节点间的认证交互往往会成为自动化道路上的第一只拦路虎。如果你正准备用 Ansible、SaltStack 或简单的批量脚本管理 9 台 Ubuntu 节点,那么一个稳定、免密的 SSH 通信环境就是基础设施的基石。本文将记录一次从零开始为 9 个节点配置完全 SSH 互信、验证网络连通性并固化环境的实战过程,内容涵盖原理、命令脚本和常见坑点,适合快速复现和参考。
环境总览与实训任务
这次操作的物理/虚拟环境如下:
- 虚拟化平台:Proxmox VE,9 台已克隆的 Ubuntu 22.04 LTS 虚拟机
- 网络规划:所有节点位于同一虚拟网桥平面,已分配静态 IP 与主机名
- 管理方式:可使用 PVE Web 控制台或外部 SSH 连接到各节点
- 权限:拥有各节点 root 或 sudo 权限的用户凭据
总体目标非常明确:**实现任一节点到其他 8 个节点的 SSH 无密码登录,为后续自动化批量管理(如 Ansible 主机清单)铺平道路**。整个过程分为清单核对、连通性验证、密钥生成与分发、全互信配置、全覆盖验证、环境快照与交付共计六个阶段。
1. 清单核对:先看清楚再动手
养成"先列清单再操作"的工程习惯,可以减少大量误操作。整理一张简单的对照表,包含序号、主机名、静态 IP 和在线状态,例如:
|-------------------|---------------|-------------|---------|
| 主机名 | IP 地址 | 网关 | DNS |
| ControlNodeA | 192.168.0.151 | 192.168.0.1 | 8.8.8.8 |
| ControlNodeB | 192.168.0.152 | 192.168.0.1 | 8.8.8.8 |
| ControlNodeC | 192.168.0.153 | 192.168.0.1 | 8.8.8.8 |
| WorkNodeA | 192.168.0.154 | 192.168.0.1 | 8.8.8.8 |
| WorkNodeB | 192.168.0.155 | 192.168.0.1 | 8.8.8.8 |
| DataMidNode | 192.168.0.156 | 192.168.0.1 | 8.8.8.8 |
| DevOpsToolNode | 192.168.0.157 | 192.168.0.1 | 8.8.8.8 |
| ObservabilityNode | 192.168.0.158 | 192.168.0.1 | 8.8.8.8 |
| DSDRNode | 192.168.0.159 | 192.168.0.1 | 8.8.8.8 |
快速抽检时,在其中一台节点上执行循环 ping:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash #只显示通/不通,执行更快 for host in {151..159}; do ping -c 2 -W 1 -q 192.168.0.host \> /dev/null if \[ ? -eq 0 ]; then echo "✅ 192.168.0.host 连通正常" else echo "❌ 192.168.0.host 连通失败" fi done |

如果某些主机名不通但 IP 可达,说明是名称解析的问题;此时检查 /etc/hosts 或 DNS 配置,确保所有节点的映射都已添加。
2. 全互通网络深度验证
在分发密钥之前,必须保证 IP 层和主机名解析完全正常。从管理节点(假设为 ControlNodeA)出发,用循环脚本完成两项测试:
测试 IP 连通性:
|---------------------------------------------------------------------------------------|
| Bash for ip in 192.168.0.{151..159}; do echo -n "ip: " ping -c 4 ip | tail -2 done |
测试主机名解析:
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash for host in ControlNodeA ControlNodeB ControlNodeC WorkNodeA WorkNodeB DataMidNode DevOpsToolNode ObservabilityNode DSDRNode; do echo -n "检查 host ... " ip=(getent hosts "host" \| awk '{print 1}') if [ -n "ip" \]; then echo "✅ 解析成功:ip" else echo "❌ 解析失败!" fi done |

如果某些地址丢包,大概率是防火墙禁用了 ICMP,或者虚拟网桥绑定出错。可以通过 ufw status 或 iptables -L 检查。主机名解析失败时,建议在 /etc/hosts 文件中统一追加:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Plain Text sudo tee -a /etc/hosts << 'EOF' 192.168.0.151 ControlNodeA 192.168.0.152 ControlNodeB 192.168.0.153 ControlNodeC 192.168.0.154 WorkNodeA 192.168.0.155 WorkNodeB 192.168.0.156 DataMidNode 192.168.0.157 DevOpsToolNode 192.168.0.158 ObservabilityNode 192.168.0.159 DSDRNode EOF |

3. 消除 "yes/no" 交互:巧用 ssh-keyscan
首次 SSH 连接时总会提示是否信任主机公钥,需要手动输入 yes,这在批量操作中是严重阻碍。解决办法是提前用 ssh-keyscan 采集所有节点的公钥,并写入 ~/.ssh/known_hosts 文件。
示例脚本如下:
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash > ~/.ssh/known_hosts # 清空旧记录(可选,更干净) for ip in {151..159}; do ssh-keyscan -H 192.168.0.$ip >> ~/.ssh/known_hosts 2>/dev/null done echo "✅ 所有节点公钥已添加到信任列表,SSH 不再提示 yes!" |

这样做之后,后续的连接将不再出现交互确认。需要注意的是,ssh-keyscan 仅在可信网络环境使用,并且采集后应检查 known_hosts 内容是否正确。
4. SSH 免密原理简述
理解密钥认证流程有助于排错。基本过程是:
- 客户端发起连接请求,携带用户名;
- 服务端查找该用户家目录下的 ~/.ssh/authorized_keys 文件;
- 若文件中存在客户端对应的公钥,服务端生成一段随机字符串,用该公钥加密后发给客户端;
- 客户端用私钥解密得到随机串并返回;
- 服务端比对一致,认证通过,无需密码。
这背后的关键文件权限必须严格:
- ~/.ssh 目录:700
- authorized_keys 文件:600
- 私钥文件:600
为满足全自动化,我们通常生成无密码短语的密钥(即 -N ""),但在生产环境中强烈建议配合 ssh-agent 使用,以提升私钥安全性。
5. 密钥生成与分发:从管理节点到全互信
5.1 生成 RSA 4096 位密钥
在管理主控节点(例如 ControlNodeA)上执行:
|--------------------------------------------------------|
| Bash ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa |
这会在 ~/.ssh/ 下产生 id_rsa(私钥)和 id_rsa.pub(公钥)。

5.2 分发公钥到所有节点
用 ssh-copy-id 循环推送公钥,包括本机也需要推送以便本地免密:
|--------------------------------------------------------------------------------------------------------|
| Bash USER=jack for i in {151..159}; do ssh-copy-id -o StrictHostKeyChecking=no USER@192.168.0.i done |

每台节点需要输入一次用户密码。推送完成后,可在目标节点上检查 ~/.ssh/authorized_keys 文件中是否已包含管理节点的公钥串。

5.3 全互信配置(任意两节点均免密)
如果只想从 ControlNodeA 管理其他节点,上述分发已经足够。但如果希望任意两节点之间都可以相互免密,可以采用"统一私钥"方案:
- 将 ControlNodeA 上的 id_rsa、id_rsa.pub 和 authorized_keys 文件复制到其余 8 个节点的对应路径;
- 在所有节点上统一修正权限:
一键批量复制脚本
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash # 要同步的节点:152~159(共8台) for i in {152..159}; do echo "===== 同步到 192.168.0.i =====" # 同步私钥、公钥、认证文件 scp \~/.ssh/{id_rsa,id_rsa.pub,authorized_keys} jack@192.168.0.i:~/.ssh/ # 必须设置权限(SSH 强制要求) ssh jack@192.168.0.$i "chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_rsa && chmod 644 ~/.ssh/id_rsa.pub && chmod 600 ~/.ssh/authorized_keys" done echo -e "\n✅ 所有节点密钥同步完成!" |

这样,每一台节点都拥有相同的密钥对,且信任该公钥,实现了真正意义上的全网无密码互访。
|-----------------------------------------------------------------------------------------------|
| ⚠️ 安全提示:该方案适用于隔离、可信的实训或内部开发环境。在生产环境中,推荐为每个节点生成独立密钥,并通过配置管理工具(如 Ansible)维护 authorized_keys 文件。 |
6. 全覆盖验证:零死角测试
直接在当前的 ControlNodeA 执行这一条命令,采集所有大小写、IP、主机名的公钥,彻底覆盖::
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash # 清空旧记录,重新采集所有节点公钥(彻底杜绝弹框) > ~/.ssh/known_hosts for host in ControlNodeA ControlNodeB ControlNodeC WorkNodeA WorkNodeB DataMidNode DevOpsToolNode ObservabilityNode DSDRNode; do ssh-keyscan -H host \>\> \~/.ssh/known_hosts 2\>/dev/null ssh-keyscan -H {host,,} >> ~/.ssh/known_hosts 2>/dev/null # 小写也加进去 done for ip in {151..159}; do ssh-keyscan -H 192.168.0.$ip >> ~/.ssh/known_hosts 2>/dev/null done echo "✅ 所有主机名/小写/IP 公钥已全部信任 → 再也不会弹 yes 确认!" |
验证是确保环境质量不可省略的环节。编写一个简单的脚本,从管理节点强制关闭密码认证,逐一测试连接并获取主机名:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash # 集群全覆盖免密验证(强制禁止密码,只允许密钥登录) for host in ControlNodeA ControlNodeB ControlNodeC WorkNodeA WorkNodeB DataMidNode DevOpsToolNode ObservabilityNode DSDRNode; do echo -n "验证免密 -> host : " ssh -o PasswordAuthentication=no jack@host hostname done |

预期结果是无任何密码提示,直接返回对应节点的主机名。如果某个节点失败,常见原因及排查步骤如下:
- authorized_keys 权限 :必须为 600,ls -la ~/.ssh/ 检查;
- .ssh 目录权限:必须为 700;
- 私钥未分发 :确认目标节点家目录下存在 id_rsa 且权限为 600;
- 公钥内容 :检查 authorized_keys 中是否确实包含管理节点的公钥。
还可以随机登录一个节点(如 ObservabilityNode),尝试 SSH 到 DataMidNode 和 ControlNodeA 并执行远程命令,确认双向互通:
|--------------------------------------------------------------------------------------------------|
| Bash ssh DataMidNode 'hostname' # 应返回 DataMidNode ssh ControlNodeA 'hostname' # 应返回 ControlNodeA |

7. 环境固化与交付标准
在全部验证通过后,立即对环境进行快照和归档,才能形成稳定的基线。
- 创建 PVE 快照 :在 Proxmox VE 管理界面为 9 台虚拟机分别创建快照,命名遵循规范,例如 ssh_trust_setup_20260505,方便后续回滚或状态对比。

- 整理交付物:
- 最终的 IP--主机名对照表;
- 密钥存放位置说明(如 ~/.ssh/id_rsa);
- 验证脚本和测试截图/日志。
- 环境清理:
- 删除测试用的临时脚本;
- 确保每节点 .ssh 目录下仅保留一套标准密钥和配置文件,避免混乱。
8. 后续步骤与闭环
SSH 互信通道打通后,可以立即投入到自动化部署中:
- 编写 Ansible 主机清单,利用免密通道并行管理所有节点;
- 批量部署 Docker、Kubernetes 或 Ceph 等集群服务,所有操作无需再处理认证;
- 将当前快照作为基础设施的"基线存档",后续任何变更都有可回溯的起点。
9. 常见问题排故速查
|------------------|-------------------------------------------------|-------------------------------------------------------------------|
| 现象 | 可能原因 | 解决方案 |
| SSH 仍要求密码 | 公钥未追加成功或权限错误;authorized_keys 非600;家目录或.ssh 权限错误 | 登录目标节点执行 chmod 600 ~/.ssh/authorized_keys; chmod 700 ~/.ssh,并重试 |
| ping 不通但 SSH 可通 | 防火墙禁止 ICMP 但放行 TCP 22 | 检查 ufw status 或 iptables 规则,按需放行 ICMP |
| 主机名 ping 不通,IP 通 | /etc/hosts 缺少对应条目或 DNS 配置错误 | 在 /etc/hosts 中添加正确映射 |
| ssh-keyscan 失败 | 目标节点 SSH 服务未启动或 22 端口未放行 | 使用 nc -zv IP 22 检查端口可达性,确认 sshd 服务运行 |
本文为"搭建DevOps企业级仿真实验环境"系列的一部分,所有内容均基于实际硬件环境(32核64线程 / 128G内存 / 6T硬盘)编写,力求贴近真实企业部署场景。
欢迎各位 DevOps、SRE 爱好者,在评论区留言交流探讨,互相学习。