This commit is contained in:
joy 2025-11-20 10:41:39 +08:00
parent 371d1c134c
commit b3b7b59284
2 changed files with 490 additions and 0 deletions

295
scripts/redis.sh Normal file
View File

@ -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

195
scripts/ssh.sh Normal file
View File

@ -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