一、前置准备

1.1 说明文档里给出的基础要求

  • HOSTADDR_PRE:集群网段前缀。
  • USER_PASSWD:待分发公钥账号的初始密码。
  • HOST_LIST:需要做免密认证的 IP 列表。
  • HOSTNAME_LIST:需要设置的主机名列表。
  • 适用系统:Ubuntu 24.04。

1.2 建议先配置控制节点的 /etc/hosts

echo "<node-ip-1> node-1" >> /etc/hosts
echo "<node-ip-2> node-2" >> /etc/hosts
echo "<node-ip-3> node-3" >> /etc/hosts

二、脚本的核心参数

2.1 环境变量集中定义

USER_NAME='root'
USER_HOME="/${USER_NAME}/.ssh"
SSH_CONFIG_FILE='/etc/ssh/ssh_config'
USER_PASSWD='<your-password>'
HOSTADDR_PRE='<network-prefix>'
HOST_LIST="${HOSTADDR_PRE}.80 ${HOSTADDR_PRE}.81 ${HOSTADDR_PRE}.13"
HOSTNAME_LIST='node-80 node-81 node-13'
HOSTS_FILE='/etc/hosts'

2.2 适合写进正文的参数解释

  • USER_HOME:密钥生成目录。
  • SSH_CONFIG_FILE:用于关闭首次连接确认。
  • HOSTS_FILE:同步到远端主机的 hosts 文件。
  • HOST_LISTHOSTNAME_LIST:共同驱动远程主机初始化。

三、自动化流程拆解

3.1 基础环境准备

apt install expect -y
rm -rf "${USER_HOME}"
ssh-keygen -t rsa -P "" -f "${USER_HOME}/id_rsa"
sed -i '/ask/{s/#/ /; s/ask/no/}' "${SSH_CONFIG_FILE}"

3.2 使用 Expect 自动输入密码

expect -c "
    spawn ssh-copy-id -i ${USER_HOME}/id_rsa.pub $1
    expect {
        \"*yes/no*\" {send \"yes\r\"; exp_continue}
        \"*password*\" {send \"${USER_PASSWD}\r\"; exp_continue}
    }
"

3.3 分发公钥并统一主机名

for i in ${HOST_LIST} ${HOSTNAME_LIST}; do
    expect_auto ${USER_NAME}@$i
    scp -rp "${HOSTS_FILE}" "${USER_NAME}@${i}:${HOSTS_FILE}"
done

for i in ${HOSTNAME_LIST}; do
    ssh "${USER_NAME}@${i}" "hostnamectl set-hostname $i"
done

四、与 Ansible 的联动整理

4.1 说明文档里的后续优化项

[defaults]
deprecation_warnings = False
interpreter_python = /usr/bin/python3
module_name = shell

4.2 发布前建议

  • 建议把密码改成交互输入,不要明文放在脚本里。
  • 建议补充 ssh-copy-id 的失败重试和异常主机跳过逻辑。
  • 如果后续要写成生产文章,可以把“控制节点准备”“免密认证”“Ansible 验证”拆成三篇。

五、完整脚本

以下为本文对应的完整脚本,便于直接复制复用。

5.1 集群主机免密认证.sh

#!/bin/bash

# 设置环境变量
USER_NAME='root'
USER_HOME="/${USER_NAME}/.ssh"
SSH_CONFIG_FILE='/etc/ssh/ssh_config'
USER_PASSWD='123456'
HOSTADDR_PRE='10.0.0'
HOST_LIST="${HOSTADDR_PRE}.80 ${HOSTADDR_PRE}.81 ${HOSTADDR_PRE}.13"
HOSTNAME_LIST='ubuntu24-80 ubuntu24-81 rocky9-13'
HOSTS_FILE='/etc/hosts'

# 准备基本环境
base_env() {
    apt install expect -y
    [ -d "${USER_HOME}" ] && rm -rf "${USER_HOME}"
    ssh-keygen -t rsa -P "" -f "${USER_HOME}/id_rsa"
    sed -i '/ask/{s/#/ /; s/ask/no/}' "${SSH_CONFIG_FILE}"
}

# expect自动化交互过程
expect_auto() {
    local remote_host="$1"
    expect -c "
        spawn ssh-copy-id -i ${USER_HOME}/id_rsa.pub $1
        expect {
            \"*yes/no*\" {send \"yes\r\"; exp_continue}
            \"*password*\" {send \"$USER_PASSWD\r\"; exp_continue}
            \"*Password*\" {send \"$USER_PASSWD\r\";}
        }
    "
}

# 跨主机免认证环境
auth_auto() {
    for i in ${HOST_LIST} ${HOSTNAME_LIST}; do
        expect_auto ${USER_NAME}@$i
        scp -rp "${HOSTS_FILE}" "${USER_NAME}@${i}:${HOSTS_FILE}"
    done
}

# 设定主机名
hostname_set() {
    for i in ${HOSTNAME_LIST}; do
        ssh "${USER_NAME}@${i}" "hostnamectl set-hostname $i"
    done
}

# 主函数执行
main() {
    # 基本环境准备
    base_env

    # 跨主机免密认证
    auth_auto

    # 设定主机名
    hostname_set
}

# 执行主函数
main