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
|