#!/bin/bash set -e set -o pipefail # ================= 1. 颜色与日志 ================= 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"; } # ================= 2. 参数检查 ================= if [ "$#" -ne 4 ]; then echo "========================================" log_error "参数数量错误!需要 4 个参数" echo "用法: $0 <主机名> <用户名> <密码>" echo "示例: $0 minio5 10.10.21.155 zhengyu MyPass123" echo "========================================" exit 1 fi TARGET_NAME="$1" TARGET_IP="$2" TARGET_USER="$3" TARGET_PASS="$4" KEY_FILE="$HOME/.ssh/id_ed25519_minio_cluster" REMOTE_SCRIPT_PATH="/tmp/remote_setup.sh" SSH_CONFIG="$HOME/.ssh/config" log_step "开始初始化单节点: ${TARGET_NAME} (${TARGET_IP})" # ================= 3. 基础环境准备 (本地) ================= 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") # ================= 4. 更新本地配置 (Hosts & SSH Config) ================= log_step "更新本机配置..." # 1. 更新 /etc/hosts if grep -q "$TARGET_NAME" /etc/hosts; then # 检查 IP 是否匹配,不匹配则警告 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" # ================= 5. 构建并执行远程脚本 ================= 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" 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 (添加自己和其他节点,这里只添加自己,其他节点由后续脚本或手动补充,或者你可以在这里硬编码集群列表) # 为了通用性,这里只确保当前节点自己的解析正确 (通常远程机器自己知道自己的 IP,但为了统一 hostname 解析) if ! sudo grep -q "\$TARGET_NAME" /etc/hosts; then echo "\$TARGET_IP \$TARGET_NAME" | sudo tee -a /etc/hosts > /dev/null echo "[OK] Hosts 已添加: \$TARGET_NAME" else echo "[SKIP] Hosts 已存在: \$TARGET_NAME" fi 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 "========================================"