123
This commit is contained in:
parent
371d1c134c
commit
b3b7b59284
|
|
@ -0,0 +1,295 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Redis哨兵集群部署与卸载脚本
|
||||||
|
|
||||||
|
# 颜色配置
|
||||||
|
GREEN="\033[32m"
|
||||||
|
YELLOW="\033[33m"
|
||||||
|
BLUE="\033[34m"
|
||||||
|
RED="\033[31m"
|
||||||
|
RESET="\033[0m"
|
||||||
|
|
||||||
|
# 提示函数
|
||||||
|
info() { echo -e "[ ${BLUE}INFO ${RESET}] $1"; }
|
||||||
|
success() { echo -e "[ ${GREEN}SUCCESS ${RESET}] $1"; }
|
||||||
|
warning() { echo -e "[ ${YELLOW}WARNING ${RESET}] $1"; }
|
||||||
|
error() { echo -e "[ ${RED}ERROR ${RESET}] $1"; exit 1; }
|
||||||
|
|
||||||
|
# 基础配置
|
||||||
|
REDIS_PORT=6379
|
||||||
|
SENTINEL_PORT=26379
|
||||||
|
SENTINEL_NAME="mymaster"
|
||||||
|
LOG_DIR="/var/log/redis"
|
||||||
|
CONFIG_DIR="/etc/redis"
|
||||||
|
SSH_OPTS="-T -o StrictHostKeyChecking=no -o LogLevel=ERROR"
|
||||||
|
|
||||||
|
# 全局变量
|
||||||
|
ACTION=""
|
||||||
|
NODES=()
|
||||||
|
NODE_COUNT=0
|
||||||
|
MASTER=""
|
||||||
|
SLAVES=()
|
||||||
|
QUORUM=1
|
||||||
|
PASSWORD=""
|
||||||
|
|
||||||
|
# 参数解析(支持--install/--uninstall、--ip、--passwd参数)
|
||||||
|
parse_args() {
|
||||||
|
# 初始化参数变量
|
||||||
|
local ip_provided=0
|
||||||
|
local passwd_provided=0
|
||||||
|
|
||||||
|
# 遍历解析参数
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--install|--uninstall)
|
||||||
|
ACTION="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--ip=*)
|
||||||
|
IP_LIST="${1#*=}"
|
||||||
|
ip_provided=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--passwd=*)
|
||||||
|
PASSWORD="${1#*=}"
|
||||||
|
passwd_provided=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "无效参数: $1 (使用帮助:--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# 验证必要参数
|
||||||
|
if [[ -z "$ACTION" ]]; then
|
||||||
|
error "必须指定参数:--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
|
||||||
|
fi
|
||||||
|
if [[ $ip_provided -eq 0 ]]; then
|
||||||
|
error "必须指定参数:--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
|
||||||
|
fi
|
||||||
|
if [[ $passwd_provided -eq 0 ]]; then
|
||||||
|
error "必须指定参数:--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解析节点列表
|
||||||
|
IFS=',' read -ra NODES <<< "$IP_LIST"
|
||||||
|
NODE_COUNT=${#NODES[@]}
|
||||||
|
if [[ $NODE_COUNT -lt 1 ]]; then
|
||||||
|
error "IP列表不能为空,至少需要1个节点"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 配置主从节点和投票阈值
|
||||||
|
MASTER="${NODES[0]}"
|
||||||
|
SLAVES=("${NODES[@]:1}")
|
||||||
|
QUORUM=$((NODE_COUNT / 2 + 1)) # 自动计算投票阈值
|
||||||
|
}
|
||||||
|
|
||||||
|
# 安装流程核心函数
|
||||||
|
install() {
|
||||||
|
echo -e "=========================================="
|
||||||
|
echo -e "=== ${GREEN}Redis哨兵集群安装部署${RESET} ==="
|
||||||
|
echo -e "=========================================="
|
||||||
|
info "部署节点总数:$NODE_COUNT 个(${NODES[*]})"
|
||||||
|
info "主节点:$MASTER | 从节点:${SLAVES[*]}(共${#SLAVES[@]}个)"
|
||||||
|
info "哨兵投票阈值(QUORUM):$QUORUM(自动计算:$NODE_COUNT/2 +1)"
|
||||||
|
info "Redis密码:******(已通过命令行传入)"
|
||||||
|
info "预估总耗时:9-14 分钟(视节点数和网络)"
|
||||||
|
echo -e "==========================================\n"
|
||||||
|
|
||||||
|
# 步骤1:初始化环境
|
||||||
|
info "步骤1/5:初始化所有节点环境 [${YELLOW}预估:5-9 分钟${RESET}]"
|
||||||
|
info "正在安装依赖、配置日志目录和防火墙..."
|
||||||
|
for node in "${NODES[@]}"; do
|
||||||
|
ssh $SSH_OPTS $node "
|
||||||
|
apt-get update -y >/dev/null 2>&1;
|
||||||
|
apt-get install -y redis-server redis-sentinel net-tools >/dev/null 2>&1;
|
||||||
|
mkdir -p $CONFIG_DIR $LOG_DIR;
|
||||||
|
chown -R redis:redis $CONFIG_DIR $LOG_DIR;
|
||||||
|
ufw disable >/dev/null 2>&1;
|
||||||
|
iptables -F INPUT >/dev/null 2>&1;
|
||||||
|
" >/dev/null 2>&1 || error "节点 $node 环境初始化失败"
|
||||||
|
done
|
||||||
|
success "步骤1完成:所有节点环境初始化完毕\n"
|
||||||
|
|
||||||
|
# 步骤2:配置主节点
|
||||||
|
info "步骤2/5:配置主节点 $MASTER [${YELLOW}预估:30秒${RESET}]"
|
||||||
|
ssh $SSH_OPTS $MASTER "
|
||||||
|
cat > $CONFIG_DIR/redis.conf <<EOF
|
||||||
|
bind 0.0.0.0
|
||||||
|
protected-mode no
|
||||||
|
port $REDIS_PORT
|
||||||
|
requirepass $PASSWORD
|
||||||
|
masterauth $PASSWORD
|
||||||
|
daemonize no
|
||||||
|
logfile "$LOG_DIR/redis.log"
|
||||||
|
dir /tmp
|
||||||
|
replica-serve-stale-data yes
|
||||||
|
replica-read-only yes
|
||||||
|
EOF
|
||||||
|
chown redis:redis $CONFIG_DIR/redis.conf;
|
||||||
|
cat > /etc/systemd/system/redis.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Redis Master Node
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
User=redis
|
||||||
|
ExecStart=/usr/bin/redis-server $CONFIG_DIR/redis.conf
|
||||||
|
ExecStop=/usr/bin/redis-cli -p $REDIS_PORT -a $PASSWORD shutdown
|
||||||
|
Restart=always
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload;
|
||||||
|
systemctl restart redis;
|
||||||
|
systemctl enable redis;
|
||||||
|
" >/dev/null 2>&1 || error "主节点 $MASTER 配置失败"
|
||||||
|
success "步骤2完成:主节点配置完毕\n"
|
||||||
|
|
||||||
|
# 步骤3:配置从节点
|
||||||
|
info "步骤3/5:配置从节点 [${YELLOW}预估:${#SLAVES[@]}*30秒${RESET}]"
|
||||||
|
info "从节点列表:${SLAVES[*]}"
|
||||||
|
for slave in "${SLAVES[@]}"; do
|
||||||
|
info "正在配置从节点:$slave"
|
||||||
|
ssh $SSH_OPTS $slave "
|
||||||
|
cat > $CONFIG_DIR/redis.conf <<EOF
|
||||||
|
bind 0.0.0.0
|
||||||
|
protected-mode no
|
||||||
|
port $REDIS_PORT
|
||||||
|
requirepass $PASSWORD
|
||||||
|
masterauth $PASSWORD
|
||||||
|
daemonize no
|
||||||
|
logfile "$LOG_DIR/redis.log"
|
||||||
|
dir /tmp
|
||||||
|
replica-serve-stale-data yes
|
||||||
|
replica-read-only yes
|
||||||
|
replicaof $MASTER $REDIS_PORT
|
||||||
|
EOF
|
||||||
|
chown redis:redis $CONFIG_DIR/redis.conf;
|
||||||
|
cat > /etc/systemd/system/redis.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Redis Slave Node
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
User=redis
|
||||||
|
ExecStart=/usr/bin/redis-server $CONFIG_DIR/redis.conf
|
||||||
|
ExecStop=/usr/bin/redis-cli -p $REDIS_PORT -a $PASSWORD shutdown
|
||||||
|
Restart=always
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload;
|
||||||
|
systemctl restart redis;
|
||||||
|
systemctl enable redis;
|
||||||
|
" >/dev/null 2>&1 || error "从节点 $slave 配置失败"
|
||||||
|
done
|
||||||
|
success "步骤3完成:所有从节点配置完毕\n"
|
||||||
|
|
||||||
|
# 步骤4:配置哨兵集群
|
||||||
|
info "步骤4/5:配置哨兵集群 [${YELLOW}预估:$NODE_COUNT*30秒${RESET}]"
|
||||||
|
info "哨兵投票阈值:$QUORUM(需$QUORUM个哨兵确认主节点下线才触发转移)"
|
||||||
|
for node in "${NODES[@]}"; do
|
||||||
|
info "正在配置哨兵节点:$node"
|
||||||
|
ssh $SSH_OPTS $node "
|
||||||
|
cat > $CONFIG_DIR/sentinel.conf <<EOF
|
||||||
|
port $SENTINEL_PORT
|
||||||
|
daemonize no
|
||||||
|
logfile "$LOG_DIR/sentinel.log"
|
||||||
|
sentinel monitor $SENTINEL_NAME $MASTER $REDIS_PORT $QUORUM
|
||||||
|
sentinel down-after-milliseconds $SENTINEL_NAME 5000
|
||||||
|
sentinel auth-pass $SENTINEL_NAME $PASSWORD
|
||||||
|
sentinel config-epoch $SENTINEL_NAME 0
|
||||||
|
EOF
|
||||||
|
chown redis:redis $CONFIG_DIR/sentinel.conf;
|
||||||
|
cat > /etc/systemd/system/redis-sentinel.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Redis Sentinel
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
User=redis
|
||||||
|
ExecStart=/usr/bin/redis-sentinel $CONFIG_DIR/sentinel.conf
|
||||||
|
ExecStop=/usr/bin/redis-cli -p $SENTINEL_PORT shutdown
|
||||||
|
Restart=always
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload;
|
||||||
|
systemctl restart redis-sentinel;
|
||||||
|
systemctl enable redis-sentinel;
|
||||||
|
" >/dev/null 2>&1 || error "哨兵节点 $node 配置失败"
|
||||||
|
done
|
||||||
|
success "步骤4完成:哨兵集群配置完毕\n"
|
||||||
|
|
||||||
|
# 步骤5:验证集群
|
||||||
|
info "步骤5/5:验证集群状态 [${YELLOW}预估:1分钟${RESET}]"
|
||||||
|
info "验证主节点 $MASTER..."
|
||||||
|
master_info=$(ssh $SSH_OPTS $MASTER "redis-cli -p $REDIS_PORT -a $PASSWORD info replication | grep -E 'role:|connected_slaves'" 2>/dev/null)
|
||||||
|
echo " $master_info"
|
||||||
|
|
||||||
|
for slave in "${SLAVES[@]}"; do
|
||||||
|
info "验证从节点 $slave..."
|
||||||
|
slave_info=$(ssh $SSH_OPTS $slave "redis-cli -p $REDIS_PORT -a $PASSWORD info replication | grep -E 'role:|master_host|master_link_status'" 2>/dev/null)
|
||||||
|
echo " $slave_info"
|
||||||
|
done
|
||||||
|
|
||||||
|
info "验证哨兵集群..."
|
||||||
|
sentinel_info=$(ssh $SSH_OPTS $MASTER "redis-cli -p $SENTINEL_PORT info sentinel | grep 'master0:'" 2>/dev/null)
|
||||||
|
echo " $sentinel_info"
|
||||||
|
|
||||||
|
success "步骤5完成:集群验证完毕\n"
|
||||||
|
|
||||||
|
# 部署总结
|
||||||
|
echo -e "=========================================="
|
||||||
|
echo -e "=== ${GREEN}部署成功!${RESET} ==="
|
||||||
|
echo -e "☆ 集群架构:$NODE_COUNT节点(1主${#SLAVES[@]}从$NODE_COUNT哨兵)"
|
||||||
|
echo -e "☆ 核心配置:Redis端口$REDIS_PORT | 哨兵端口$SENTINEL_PORT | 投票阈值$QUORUM"
|
||||||
|
echo -e "☆ 功能状态:主从同步正常 | 哨兵监控正常 | 故障转移就绪"
|
||||||
|
echo -e "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
# 卸载流程核心函数
|
||||||
|
uninstall() {
|
||||||
|
echo -e "=========================================="
|
||||||
|
echo -e "=== ${RED}Redis哨兵集群彻底卸载${RESET} ==="
|
||||||
|
echo -e "=========================================="
|
||||||
|
info "卸载节点列表:${NODES[*]}(共$NODE_COUNT个节点)"
|
||||||
|
info "Redis密码:******(已通过命令行传入)"
|
||||||
|
info "预估耗时:3-6 分钟(清理所有资源)"
|
||||||
|
echo -e "==========================================\n"
|
||||||
|
|
||||||
|
# 逐节点卸载
|
||||||
|
for i in "${!NODES[@]}"; do
|
||||||
|
node="${NODES[$i]}"
|
||||||
|
idx=$((i + 1))
|
||||||
|
info "正在卸载节点($idx/$NODE_COUNT):$node"
|
||||||
|
ssh $SSH_OPTS $node "
|
||||||
|
# 停止服务(使用传入的密码)
|
||||||
|
systemctl stop redis-sentinel >/dev/null 2>&1;
|
||||||
|
redis-cli -p $REDIS_PORT -a '$PASSWORD' shutdown >/dev/null 2>&1;
|
||||||
|
# 禁用服务
|
||||||
|
systemctl disable redis redis-sentinel >/dev/null 2>&1;
|
||||||
|
# 清理文件
|
||||||
|
rm -rf $CONFIG_DIR $LOG_DIR /etc/systemd/system/redis* >/dev/null 2>&1;
|
||||||
|
# 卸载依赖
|
||||||
|
apt-get remove -y redis-server redis-sentinel >/dev/null 2>&1;
|
||||||
|
apt-get autoremove -y >/dev/null 2>&1;
|
||||||
|
" >/dev/null 2>&1 || error "节点 $node 卸载失败"
|
||||||
|
success "节点 $node 卸载完成"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 卸载总结
|
||||||
|
echo -e "\n=========================================="
|
||||||
|
echo -e "=== ${GREEN}卸载成功!${RESET} ==="
|
||||||
|
echo -e "✓ 已彻底清理所有Redis相关资源:"
|
||||||
|
echo -e " - 服务:redis-server、redis-sentinel(停止+禁用)"
|
||||||
|
echo -e " - 文件:配置目录、日志目录、systemd服务文件"
|
||||||
|
echo -e " - 依赖:redis相关安装包及依赖组件"
|
||||||
|
echo -e "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
# 执行入口
|
||||||
|
parse_args "$@"
|
||||||
|
if [ "$ACTION" = "--install" ]; then
|
||||||
|
install
|
||||||
|
elif [ "$ACTION" = "--uninstall" ]; then
|
||||||
|
uninstall
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# 多节点互相同步SSH密钥脚本(支持从文件读取IP、指定用户和密码)
|
||||||
|
|
||||||
|
# ==================== 颜色与样式定义 ====================
|
||||||
|
GREEN="\033[32m" # 成功/完成
|
||||||
|
YELLOW="\033[33m" # 进行中/提示
|
||||||
|
RED="\033[31m" # 错误/失败
|
||||||
|
BLUE="\033[34m" # 标题/分隔线
|
||||||
|
CYAN="\033[36m" # 信息/说明
|
||||||
|
NC="\033[0m" # 重置颜色
|
||||||
|
|
||||||
|
# 打印分隔线
|
||||||
|
print_sep() {
|
||||||
|
echo -e "${BLUE}------------------------------------------------${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==================== 参数解析与校验 ====================
|
||||||
|
# 解析命令行参数
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--file=*)
|
||||||
|
IP_FILE="${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--user=*)
|
||||||
|
SSH_USER="${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--passwd=*)
|
||||||
|
SSH_PASSWD="${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}未知参数: $1${NC}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# 检查必要参数
|
||||||
|
if [ -z "$IP_FILE" ] || [ -z "$SSH_USER" ] || [ -z "$SSH_PASSWD" ]; then
|
||||||
|
echo -e "\n${YELLOW}用法:${NC} --file=IP文件路径 --user=用户名 --passwd=密码"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查IP文件是否存在
|
||||||
|
if [ ! -f "$IP_FILE" ]; then
|
||||||
|
echo -e "${RED}错误:IP文件 $IP_FILE 不存在${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 从文件读取IP列表(去重、过滤空行)
|
||||||
|
NODES=()
|
||||||
|
while IFS= read -r ip; do
|
||||||
|
if [ -n "$ip" ] && ! [[ " ${NODES[@]} " =~ " $ip " ]]; then
|
||||||
|
NODES+=("$ip")
|
||||||
|
fi
|
||||||
|
done < "$IP_FILE"
|
||||||
|
|
||||||
|
if [ ${#NODES[@]} -eq 0 ]; then
|
||||||
|
echo -e "${RED}错误:IP文件 $IP_FILE 中未找到有效IP${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==================== 核心功能函数 ====================
|
||||||
|
# 安装sshpass(处理自动输入密码)
|
||||||
|
install_sshpass() {
|
||||||
|
echo -e "\n${YELLOW}【步骤1/3】检查并安装sshpass工具...${NC}"
|
||||||
|
if ! command -v sshpass &> /dev/null; then
|
||||||
|
echo -e " ${YELLOW}→ sshpass未安装,正在安装...${NC}"
|
||||||
|
if command -v apt &> /dev/null; then
|
||||||
|
apt update -y >/dev/null && apt install -y sshpass >/dev/null
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
yum install -y sshpass >/dev/null
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗ 未找到apt或yum,无法安装sshpass${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# 验证安装结果
|
||||||
|
if command -v sshpass &> /dev/null; then
|
||||||
|
echo -e " ${GREEN}✓ sshpass安装成功${NC}"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗ sshpass安装失败,请手动安装后重试${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e " ${GREEN}✓ sshpass已安装${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 在目标节点生成SSH密钥(若不存在)
|
||||||
|
generate_key() {
|
||||||
|
local node=$1
|
||||||
|
echo -e " ${YELLOW}→ 处理节点 $node...${NC}"
|
||||||
|
# 远程生成密钥(静默模式)
|
||||||
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$node << EOF >/dev/null 2>&1
|
||||||
|
if [ ! -f ~/.ssh/id_rsa ]; then
|
||||||
|
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
# 检查执行结果
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e " ${GREEN}✓ 密钥生成完成(已存在则跳过)${NC}"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗ 生成失败(可能密码错误或节点不可达)${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取目标节点的公钥
|
||||||
|
get_public_key() {
|
||||||
|
local node=$1
|
||||||
|
# 静默获取公钥,忽略错误输出
|
||||||
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$node "cat ~/.ssh/id_rsa.pub" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# 将公钥追加到目标节点的authorized_keys
|
||||||
|
append_public_key() {
|
||||||
|
local pub_key="$1"
|
||||||
|
local target_node=$2
|
||||||
|
# 远程执行追加公钥操作
|
||||||
|
sshpass -p "$SSH_PASSWD" ssh -o StrictHostKeyChecking=no ${SSH_USER}@$target_node << EOF >/dev/null 2>&1
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
if ! grep -q "$pub_key" ~/.ssh/authorized_keys 2>/dev/null; then
|
||||||
|
echo "$pub_key" >> ~/.ssh/authorized_keys
|
||||||
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
# 反馈结果
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e " ${GREEN}→ 同步成功${NC}"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}→ 同步失败${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==================== 主流程 ====================
|
||||||
|
main() {
|
||||||
|
# 欢迎信息
|
||||||
|
clear
|
||||||
|
print_sep
|
||||||
|
echo -e "${BLUE} 多节点SSH密钥互相同步工具 ${NC}"
|
||||||
|
print_sep
|
||||||
|
echo -e " ${CYAN}节点列表:${NC} ${NODES[*]}"
|
||||||
|
echo -e " ${CYAN}操作用户:${NC} $SSH_USER"
|
||||||
|
echo -e " ${CYAN}开始时间:${NC} $(date +'%Y-%m-%d %H:%M:%S')"
|
||||||
|
print_sep
|
||||||
|
|
||||||
|
# 1. 安装依赖工具
|
||||||
|
install_sshpass
|
||||||
|
print_sep
|
||||||
|
|
||||||
|
# 2. 为所有节点生成密钥
|
||||||
|
node_count=${#NODES[@]}
|
||||||
|
echo -e "\n${YELLOW}【步骤2/3】为所有节点生成SSH密钥(共 $node_count 个节点)...${NC}"
|
||||||
|
for i in "${!NODES[@]}"; do
|
||||||
|
echo -e "\n 节点 ${i+1}/$node_count: ${NODES[$i]}"
|
||||||
|
generate_key ${NODES[$i]}
|
||||||
|
done
|
||||||
|
print_sep
|
||||||
|
|
||||||
|
# 3. 收集公钥并互相同步
|
||||||
|
echo -e "\n${YELLOW}【步骤3/3】公钥互相同步(共 $node_count 个节点)...${NC}"
|
||||||
|
for i in "${!NODES[@]}"; do
|
||||||
|
current_node=${NODES[$i]}
|
||||||
|
echo -e "\n 处理第 ${i+1}/$node_count 个节点: $current_node"
|
||||||
|
|
||||||
|
# 获取当前节点公钥
|
||||||
|
echo -e " ${YELLOW}→ 获取公钥...${NC}"
|
||||||
|
pub_key=$(get_public_key $current_node)
|
||||||
|
if [ -z "$pub_key" ]; then
|
||||||
|
echo -e " ${RED}✗ 无法获取 $current_node 的公钥${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 同步到所有节点
|
||||||
|
echo -e " ${YELLOW}→ 同步到所有节点...${NC}"
|
||||||
|
for target in "${NODES[@]}"; do
|
||||||
|
echo -e " 目标节点: $target"
|
||||||
|
append_public_key "$pub_key" $target
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# 完成提示
|
||||||
|
print_sep
|
||||||
|
echo -e "\n${GREEN}=== 所有操作完成!===${NC}"
|
||||||
|
echo -e " ${CYAN}验证方法:${NC} 在任意节点执行 'ssh ${NODES[1]}' 测试免密登录"
|
||||||
|
echo -e " ${CYAN}结束时间:${NC} $(date +'%Y-%m-%d %H:%M:%S')"
|
||||||
|
print_sep
|
||||||
|
}
|
||||||
|
|
||||||
|
# 执行主流程
|
||||||
|
main
|
||||||
Loading…
Reference in New Issue