#!/bin/bash set -e set -o pipefail # ================= 颜色与日志 ================= RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${BLUE}[STEP]${NC} $1"; } log_success() { echo -e "${CYAN}[OK]${NC} $1"; } # ================= 参数检查 ================= if [ "$#" -lt 4 ]; then echo "========================================" log_error "参数数量错误!需要至少 4 个参数" echo "用法:$0 <主机名> <用户名> <密码> [hosts 文件路径]" echo "示例:$0 minio1 10.10.21.151 zhengyu MyPass123 /root/.cluster_hosts_temp" echo "========================================" exit 1 fi TARGET_NAME="$1" TARGET_IP="$2" TARGET_USER="$3" TARGET_PASS="$4" HOSTS_FILE="${5:-}" # 可选参数:集群 hosts 文件路径 KEY_FILE="$HOME/.ssh/id_ed25519_cluster" SSH_CONFIG="$HOME/.ssh/config" # 检查并安装sshpass|jq for pkg in sshpass jq; do if ! command -v $pkg &> /dev/null; then log_warn "未找到 $pkg,正在安装..." if command -v apt &> /dev/null; then sudo apt update >/dev/null 2>&1 && sudo apt install -y $pkg >/dev/null 2>&1 elif command -v yum &> /dev/null; then sudo yum install -y $pkg >/dev/null 2>&1 elif command -v dnf &> /dev/null; then sudo dnf install -y $pkg >/dev/null 2>&1 else log_error "请手动安装 $pkg" exit 1 fi log_success "$pkg 安装完成" fi done log_step "开始初始化单节点:${TARGET_NAME} (${TARGET_IP})" # ================= 基础环境准备 (本地) ================= mkdir -p "$HOME/.ssh" touch "$SSH_CONFIG" chmod 700 "$HOME/.ssh" chmod 600 "$SSH_CONFIG" # 生成密钥 (如果不存在) if [ ! -f "$KEY_FILE" ]; then log_step "生成 SSH 密钥对..." ssh-keygen -t ed25519 -f "$KEY_FILE" -N "" -q log_success "密钥生成成功" else log_info "密钥已存在,跳过生成" fi PUB_KEY=$(cat "${KEY_FILE}.pub") # ================= 准备集群 Hosts 内容 ================= CLUSTER_HOSTS_CONTENT="" if [ -n "$HOSTS_FILE" ] && [ -f "$HOSTS_FILE" ]; then CLUSTER_HOSTS_CONTENT=$(cat "$HOSTS_FILE") log_info "已加载集群 Hosts 配置(${#CLUSTER_HOSTS_CONTENT} 字节)" else log_warn "未提供 Hosts 文件,仅配置当前节点解析" CLUSTER_HOSTS_CONTENT="$TARGET_IP $TARGET_NAME" fi # ================= 更新本地配置 (Hosts & SSH Config) ================= log_step "更新本机配置..." # 1. 更新 /etc/hosts(添加当前节点) if grep -q "$TARGET_NAME" /etc/hosts; then if ! grep "$TARGET_NAME" /etc/hosts | grep -q "$TARGET_IP"; then log_warn "Hosts 中 $TARGET_NAME 已存在但 IP 可能不匹配,跳过修改。" else log_info "Hosts 记录已存在:$TARGET_NAME" fi else echo "$TARGET_IP $TARGET_NAME" | sudo tee -a /etc/hosts > /dev/null log_success "已添加 Hosts: $TARGET_IP $TARGET_NAME" fi # 2. 更新 SSH Config MARKER_START="# --- NODE_${TARGET_NAME}_START ---" MARKER_END="# --- NODE_${TARGET_NAME}_END ---" if grep -q "$MARKER_START" "$SSH_CONFIG"; then sed -i "/$MARKER_START/,/$MARKER_END/d" "$SSH_CONFIG" fi cat >> "$SSH_CONFIG" << EOF $MARKER_START Host $TARGET_IP $TARGET_NAME User $TARGET_USER IdentityFile $KEY_FILE IdentitiesOnly yes StrictHostKeyChecking no UserKnownHostsFile /dev/null LogLevel ERROR $MARKER_END EOF log_success "SSH Config 已更新:$TARGET_NAME" # ================= 构建并执行远程脚本 ================= log_step "配置远程节点 ($TARGET_NAME)..." # 动态生成远程脚本内容 read -r -d '' REMOTE_SCRIPT_CONTENT << EOF || true #!/bin/bash USER="\$1" PASS="\$2" PUB_KEY="$PUB_KEY" TARGET_NAME="$TARGET_NAME" TARGET_IP="$TARGET_IP" CLUSTER_HOSTS='$CLUSTER_HOSTS_CONTENT' echo "[Remote] 开始配置用户 \$USER..." # 1. 配置公钥 mkdir -p ~/.ssh chmod 700 ~/.ssh if [ ! -f ~/.ssh/authorized_keys ] || ! grep -qF "\$PUB_KEY" ~/.ssh/authorized_keys; then echo "\$PUB_KEY" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys echo "[OK] 公钥已添加" else echo "[SKIP] 公钥已存在" fi # 2. 配置 Sudo SUDOERS_FILE="/etc/sudoers.d/nopasswd_\${USER}_auto" if echo "\$PASS" | sudo -S bash -c "echo '\${USER} ALL=(ALL:ALL) NOPASSWD: ALL' > \$SUDOERS_FILE && chmod 440 \$SUDOERS_FILE"; then echo "[OK] Sudo 免密已配置" else echo "[FAIL] Sudo 配置失败" exit 1 fi # 3. 配置集群 Hosts 解析(所有节点互通) echo "[Remote] 配置集群 Hosts 解析..." HOSTS_BACKUP="/etc/hosts.backup.\$(date +%Y%m%d_%H%M%S)" # 备份现有 hosts sudo cp /etc/hosts "\$HOSTS_BACKUP" echo "[OK] Hosts 已备份:\$HOSTS_BACKUP" # 逐行添加集群 hosts(去重) while IFS= read -r host_line; do [ -z "\$host_line" ] && continue # 提取主机名和 IP h_ip=\$(echo "\$host_line" | awk '{print \$1}') h_name=\$(echo "\$host_line" | awk '{print \$2}') [ -z "\$h_ip" ] || [ -z "\$h_name" ] && continue # 检查是否已存在,不存在则添加 if sudo grep -q "\$h_name" /etc/hosts; then # 检查 IP 是否匹配 if ! sudo grep "\$h_name" /etc/hosts | grep -q "\$h_ip"; then echo "[WARN] \$h_name 已存在但 IP 不匹配,跳过:\$h_ip \$h_name" else echo "[SKIP] \$h_name 已存在:\$h_ip \$h_name" fi else echo "\$h_ip \$h_name" | sudo tee -a /etc/hosts > /dev/null echo "[OK] 已添加:\$h_ip \$h_name" fi done <<< "\$CLUSTER_HOSTS" # 4. 验证 hosts 解析 echo "[Remote] 验证 Hosts 解析..." if sudo grep -q "\$TARGET_NAME" /etc/hosts; then echo "[OK] 当前节点解析验证通过" else echo "[FAIL] 当前节点解析验证失败" fi # 显示当前 hosts 配置 echo "" echo "[Remote] 当前 /etc/hosts 配置:" sudo grep -E "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" /etc/hosts | tail -n 20 echo "" echo "[Remote] 单节点初始化完成!" EOF # 上传脚本 TMP_REMOTE="/tmp/init_single_node.sh" echo "$REMOTE_SCRIPT_CONTENT" > /tmp/local_tmp_script.sh chmod +x /tmp/local_tmp_script.sh if ! sshpass -p "$TARGET_PASS" scp -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null /tmp/local_tmp_script.sh "$TARGET_USER@$TARGET_IP:$TMP_REMOTE" 2>/dev/null; then log_error "上传脚本失败" rm -f /tmp/local_tmp_script.sh exit 1 fi # 执行脚本 CMD="chmod +x $TMP_REMOTE && $TMP_REMOTE \"$TARGET_USER\" \"$TARGET_PASS\"" if sshpass -p "$TARGET_PASS" ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -n "$TARGET_USER@$TARGET_IP" "$CMD"; then log_success "节点 $TARGET_NAME 初始化成功!" else log_error "节点 $TARGET_NAME 执行失败" rm -f /tmp/local_tmp_script.sh exit 1 fi # 清理 rm -f /tmp/local_tmp_script.sh echo "========================================" log_success "✅ 节点 ${TARGET_NAME} 就绪!" log_info " 测试连接:ssh $TARGET_NAME" echo "========================================"