296 lines
10 KiB
Bash
296 lines
10 KiB
Bash
#!/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
|