#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Redis Cluster三主三从自动化部署脚本
适配系统:CentOS 7.x 64位(最小化安装即可)
Redis版本:6.2.6(稳定版,生产环境推荐)
部署模式:单机三主三从(可扩展多机,脚本内有标注)
作者:Redis自动化部署工具
版本:2.0(优化版)
注意:需以root权限运行,单机部署需保证服务器内存≥4G
"""
import os
import sys
import subprocess
import shutil
import argparse
import socket
import time
from pathlib import Path
# 彩色输出配置(提升可读性,兼容CentOS7终端)
class Color:
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
RESET = '\033[0m'
# 全局常量(便于后续修改配置)
REDIS_VERSION = "6.2.6"
REDIS_URL = f"https://download.redis.io/releases/redis-{REDIS_VERSION}.tar.gz"
REDIS_USER = "redis"
DEFAULT_PASSWORD = "RedisPass@123"
INSTALL_DIR = "/opt/redis"
MASTER_PORTS = [7000, 7001, 7002] # 主节点端口
SLAVE_PORTS = [7003, 7004, 7005] # 从节点端口
ALL_PORTS = MASTER_PORTS + SLAVE_PORTS
BUS_PORTS = [p + 10000 for p in ALL_PORTS] # 集群总线端口(固定+10000)
class RedisClusterDeployer:
def __init__(self, args):
self.args = args
self.redis_password = args.password or DEFAULT_PASSWORD
# 节点IP:指定则用指定的,未指定则获取本机非回环IP
self.node_ips = self.args.nodes.split(',') if self.args.nodes else self.get_local_ips()
# 本机IP(集群公告用,避免使用127.0.0.1)
self.local_ip = self.get_local_ips()[0]
def echo(self, msg, color=Color.BLUE):
"""彩色打印输出"""
print(f"{color}{msg}{Color.RESET}")
def success(self, msg):
"""成功信息打印"""
self.echo(f"✓ {msg}", Color.GREEN)
def error(self, msg):
"""错误信息打印"""
self.echo(f"✗ {msg}", Color.RED)
def warn(self, msg):
"""警告信息打印"""
self.echo(f"⚠ {msg}", Color.YELLOW)
def get_local_ips(self):
"""获取本机非回环、非docker的IPv4地址"""
try:
ip_list = []
for iface in socket.if_nameindex():
if iface[1] in ['lo', 'docker0']:
continue
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.bind((iface[1], 0))
ip = sock.getsockname()[0]
ip_list.append(ip)
except:
continue
finally:
sock.close()
# 若未获取到,用公网检测方式兜底
if not ip_list:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip_list = [s.getsockname()[0]]
s.close()
return ip_list
except Exception as e:
self.error(f"获取本机IP失败:{e}")
return ['127.0.0.1']
def check_port_used(self, port):
"""检查端口是否被占用"""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(1)
return s.connect_ex(('0.0.0.0', port)) == 0
except:
return True
def run_command(self, cmd, shell=True, check=True, capture_output=False):
"""执行Shell命令,带异常捕获和结果返回"""
self.echo(f"执行命令:{cmd}")
try:
if capture_output:
result = subprocess.run(
cmd, shell=shell, check=check,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, encoding='utf-8'
)
return result.stdout.strip(), result.stderr.strip()
else:
subprocess.run(cmd, shell=shell, check=check)
return True, ""
except subprocess.CalledProcessError as e:
err_msg = f"命令执行失败:{e.stderr.strip() if e.stderr else str(e)}"
self.error(err_msg)
if not self.args.force:
self.error("非强制模式,退出部署")
sys.exit(1)
self.warn("强制模式,忽略错误继续执行")
return False, err_msg
except Exception as e:
err_msg = f"命令执行异常:{str(e)}"
self.error(err_msg)
if not self.args.force:
sys.exit(1)
self.warn("强制模式,忽略错误继续执行")
return False, err_msg
def pre_check(self):
"""部署前前置校验(关键,避免后续失败)"""
self.echo("="*60, Color.BLUE)
self.echo("开始部署前前置校验...", Color.BLUE)
# 1. 检查是否为root
if os.geteuid() != 0:
self.error("必须以root/管理员权限运行脚本!")
self.echo("请执行:sudo python3 redis_cluster_3m3s.py", Color.YELLOW)
sys.exit(1)
# 2. 检查系统是否为CentOS7
if not os.path.exists('/etc/redhat-release'):
self.error("当前系统非CentOS/RHEL系列,不支持部署!")
sys.exit(1)
with open('/etc/redhat-release', 'r') as f:
os_ver = f.read().strip()
if '7.' not in os_ver:
self.error(f"当前系统为{os_ver},仅支持CentOS 7.x!")
sys.exit(1)
# 3. 检查端口是否被占用
for port in ALL_PORTS + BUS_PORTS:
if self.check_port_used(port):
self.error(f"端口{port}已被占用,部署失败!")
self.echo(f"请执行:netstat -tulnp | grep {port} 查看占用进程并关闭", Color.YELLOW)
sys.exit(1)
# 4. 检查内存是否≥4G(单机三主三从最小要求)
mem_total = os.popen('free -g | grep Mem | awk \'{print $2}\'').read().strip()
if int(mem_total) < 4:
self.warn(f"当前服务器内存为{mem_total}G,建议≥4G,可能影响Redis运行!")
confirm = input("是否继续部署?(yes/no):")
if confirm.lower() != 'yes':
self.echo("用户取消部署", Color.BLUE)
sys.exit(0)
self.success("所有前置校验通过!")
def install_dependencies(self):
"""安装系统编译和运行依赖"""
self.echo("="*60, Color.BLUE)
self.echo("开始安装系统依赖...", Color.BLUE)
deps = ['gcc', 'tcl', 'make', 'wget', 'tar', 'systemd-devel', 'net-tools', 'lsof']
if self.args.offline:
self.warn("离线模式:请确保依赖包已上传至 /tmp/rpms/ 目录!")
if not os.path.exists('/tmp/rpms/') or len(os.listdir('/tmp/rpms/')) == 0:
self.error("/tmp/rpms/ 目录为空,离线安装失败!")
sys.exit(1)
self.run_command('yum localinstall -y /tmp/rpms/*.rpm --nogpgcheck')
else:
self.run_command('yum install -y epel-release')
self.run_command(f'yum install -y {" ".join(deps)}')
# 创建redis系统用户(无登录权限,更安全)
self.run_command(f'id {REDIS_USER} &>/dev/null || useradd -r -s /sbin/nologin -M {REDIS_USER}')
self.success("系统依赖安装完成!")
def download_redis(self):
"""下载并编译安装Redis"""
self.echo("="*60, Color.BLUE)
self.echo(f"开始下载并编译Redis {REDIS_VERSION}...", Color.BLUE)
redis_tar = f"/tmp/redis-{REDIS_VERSION}.tar.gz"
redis_src = f"/tmp/redis-{REDIS_VERSION}"
# 下载Redis安装包
if not os.path.exists(redis_tar):
if self.args.offline:
self.warn(f"离线模式:请确保Redis包已上传至 {redis_tar}!")
if not os.path.exists(redis_tar):
self.error(f"Redis安装包{redis_tar}不存在!")
sys.exit(1)
else:
self.run_command(f'wget {REDIS_URL} -O {redis_tar} --no-check-certificate')
# 解压源码
if os.path.exists(redis_src):
shutil.rmtree(redis_src)
self.run_command(f'tar -xzf {redis_tar} -C /tmp/')
# 编译安装(指定CC=gcc,避免编译错误)
os.chdir(redis_src)
self.run_command('make clean')
self.run_command('make CC=gcc -j $(nproc)') # 多核编译,提升速度
self.run_command('make install PREFIX=/usr/local/redis')
# 创建安装目录和软链接
self.run_command(f'mkdir -p {INSTALL_DIR}')
if os.path.exists(f'{INSTALL_DIR}/redis-{REDIS_VERSION}'):
shutil.rmtree(f'{INSTALL_DIR}/redis-{REDIS_VERSION}')
shutil.copytree(redis_src, f'{INSTALL_DIR}/redis-{REDIS_VERSION}')
self.run_command('ln -sf /usr/local/redis/bin/* /usr/local/bin/')
self.success(f"Redis {REDIS_VERSION} 编译安装完成!")
def setup_environment(self):
"""设置Redis环境变量,确保全局可用"""
self.echo("="*60, Color.BLUE)
self.echo("开始设置Redis环境变量...", Color.BLUE)
env_file = '/etc/profile.d/redis.sh'
env_content = f"""# Redis Cluster 环境变量配置
export REDIS_VERSION={REDIS_VERSION}
export REDIS_HOME={INSTALL_DIR}/redis-{REDIS_VERSION}
export PATH=$REDIS_HOME/src:$PATH:/usr/local/redis/bin
"""
with open(env_file, 'w', encoding='utf-8') as f:
f.write(env_content)
# 使环境变量立即生效
os.system('source /etc/profile.d/redis.sh')
# 验证Redis是否安装成功
redis_cli, err = self.run_command('redis-cli --version', capture_output=True)
if redis_cli:
self.success(f"Redis版本验证成功:{redis_cli}")
else:
self.error(f"Redis版本验证失败:{err}")
self.warn("请手动执行 source /etc/profile 使环境变量生效")
self.success("Redis环境变量设置完成!")
def create_cluster_configs(self):
"""为每个节点创建独立的Redis配置文件"""
self.echo("="*60, Color.BLUE)
self.echo("开始创建Redis集群节点配置...", Color.BLUE)
for port in ALL_PORTS:
# 定义各目录(每个端口独立目录,避免冲突)
conf_dir = f"/etc/redis/{port}"
data_dir = f"/data/redis/{port}"
log_dir = f"/var/log/redis"
pid_dir = f"/var/run/redis"
# 创建目录并设置权限
for dir_path in [conf_dir, data_dir, log_dir, pid_dir]:
self.run_command(f'mkdir -p {dir_path}')
self.run_command(f'chown -R {REDIS_USER}:{REDIS_USER} {dir_path}')
self.run_command(f'chmod 750 {dir_path}')
# 节点类型
node_type = "主节点" if port in MASTER_PORTS else "从节点"
# Redis核心配置(生产环境优化版)
redis_conf = f"""# Redis Cluster {node_type} 配置文件 - 端口{port}
# 基础网络配置
bind 0.0.0.0
port {port}
protected-mode no # 关闭保护模式,集群模式必须关闭
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes # 后台运行
pidfile {pid_dir}/redis_{port}.pid
logfile {log_dir}/redis_{port}.log
loglevel notice
# 数据存储配置
dir {data_dir}
dbfilename dump_{port}.rdb
rdbcompression yes
rdbchecksum yes
stop-writes-on-bgsave-error yes
# AOF持久化(集群推荐开启)
appendonly yes
appendfilename "appendonly_{port}.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 集群核心配置
cluster-enabled yes
cluster-config-file {conf_dir}/nodes_{port}.conf
cluster-node-timeout 15000
cluster-announce-ip {self.local_ip} # 公告本机真实IP,集群通信必备
cluster-announce-port {port}
cluster-announce-bus-port {port+10000}
# 安全认证配置
requirepass {self.redis_password} # 访问密码
masterauth {self.redis_password} # 从节点连接主节点的密码
# 内存限制(根据服务器内存调整,单机3主3从各分配2G)
maxmemory 2gb
maxmemory-policy allkeys-lru # 内存满时淘汰策略
maxmemory-samples 5
# 复制配置
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-ping-replica-period 10
repl-timeout 60
# 性能优化
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
"""
# 写入配置文件
conf_file = f"{conf_dir}/redis_{port}.conf"
with open(conf_file, 'w', encoding='utf-8') as f:
f.write(redis_conf)
# 设置配置文件权限
self.run_command(f'chown {REDIS_USER}:{REDIS_USER} {conf_file}')
self.run_command(f'chmod 640 {conf_file}')
self.success(f"端口{port} {node_type} 配置文件创建完成")
# 创建systemd服务文件
self.create_systemd_service()
self.success("所有Redis集群节点配置创建完成!")
def create_systemd_service(self):
"""创建systemd服务文件,便于系统管理Redis节点"""
self.echo("开始创建Redis systemd服务文件...", Color.BLUE)
# 服务模板(使用@参数化,适配不同端口)
service_tpl = f"""[Unit]
Description=Redis Cluster Node %i
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=forking
User={REDIS_USER}
Group={REDIS_USER}
# 解决文件句柄不足问题(CentOS7常见坑)
LimitNOFILE=65535
LimitNPROC=65535
LimitCORE=infinity
# 启动/停止命令
ExecStart=/usr/local/bin/redis-server /etc/redis/%%i/redis_%%i.conf
ExecStop=/usr/local/bin/redis-cli -p %%i -a {self.redis_password} shutdown
ExecReload=/usr/local/bin/redis-cli -p %%i -a {self.redis_password} config rewrite
# 重启策略
Restart=on-failure
RestartSec=3
TimeoutSec=300
[Install]
WantedBy=multi-user.target
"""
# 为每个端口创建服务文件
for port in ALL_PORTS:
service_file = f"/etc/systemd/system/redis-cluster@{port}.service"
with open(service_file, 'w', encoding='utf-8') as f:
f.write(service_tpl)
self.run_command(f'chmod 644 {service_file}')
# 创建集群批量管理脚本(一键启停/查看状态)
self.create_manage_scripts()
self.success("Redis systemd服务文件创建完成!")
def create_manage_scripts(self):
"""创建集群批量管理脚本,提升运维效率"""
# 一键启动
start_script = """#!/bin/bash
# Redis Cluster 批量启动脚本
for port in 7000 7001 7002 7003 7004 7005; do
systemctl start redis-cluster@$port
echo "启动Redis节点 $port ..."
sleep 0.5
done
echo -e "\\033[32m所有Redis集群节点启动完成!\\033[0m"
"""
# 一键停止
stop_script = """#!/bin/bash
# Redis Cluster 批量停止脚本
for port in 7000 7001 7002 7003 7004 7005; do
systemctl stop redis-cluster@$port
echo "停止Redis节点 $port ..."
done
echo -e "\\033[32m所有Redis集群节点停止完成!\\033[0m"
"""
# 一键查看状态
status_script = """#!/bin/bash
# Redis Cluster 批量状态查看脚本
for port in 7000 7001 7002 7003 7004 7005; do
echo -e "\\033[34m========== Redis节点 $port 状态 ==========\\033[0m"
systemctl status redis-cluster@$port --no-pager -l
echo ""
done
"""
# 一键重启
restart_script = """#!/bin/bash
# Redis Cluster 批量重启脚本
for port in 7000 7001 7002 7003 7004 7005; do
systemctl restart redis-cluster@$port
echo "重启Redis节点 $port ..."
sleep 0.5
done
echo -e "\\033[32m所有Redis集群节点重启完成!\\033[0m"
"""
# 脚本路径和内容映射
scripts = {
'/usr/local/bin/redis-cluster-start': start_script,
'/usr/local/bin/redis-cluster-stop': stop_script,
'/usr/local/bin/redis-cluster-status': status_script,
'/usr/local/bin/redis-cluster-restart': restart_script
}
# 写入并赋予执行权限
for path, content in scripts.items():
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
self.run_command(f'chmod +x {path}')
self.success("Redis集群批量管理脚本创建完成!")
def configure_firewall(self):
"""配置firewalld防火墙,开放Redis数据端口和集群总线端口"""
self.echo("="*60, Color.BLUE)
self.echo("开始配置防火墙规则...", Color.BLUE)
# 检查firewalld是否运行
is_active, err = self.run_command('systemctl is-active firewalld', capture_output=True)
if is_active not in ['active', 'running']:
self.warn("firewalld服务未运行,跳过防火墙配置!")
self.warn("若开启防火墙,请手动开放端口7000-7005、17000-17005/tcp")
return
# 开放端口(批量开放,减少命令执行次数)
self.run_command('firewall-cmd --permanent --add-port=7000-7005/tcp')
self.run_command('firewall-cmd --permanent --add-port=17000-17005/tcp')
self.run_command('firewall-cmd --reload')
# 验证端口是否开放
check, err = self.run_command('firewall-cmd --list-ports', capture_output=True)
self.echo(f"当前开放的端口:{check}", Color.BLUE)
self.success("防火墙规则配置完成!")
def start_redis_nodes(self):
"""启动所有Redis节点并验证运行状态"""
self.echo("="*60, Color.BLUE)
self.echo("开始启动Redis集群节点...", Color.BLUE)
# 重新加载systemd配置
self.run_command('systemctl daemon-reload')
# 启动并设置开机自启
for port in ALL_PORTS:
self.run_command(f'systemctl enable --now redis-cluster@{port}')
time.sleep(0.5)
# 等待节点完全启动(至少5秒)
self.echo("等待Redis节点初始化...(5秒)", Color.BLUE)
time.sleep(5)
# 验证每个节点的运行状态
self.echo("开始验证Redis节点状态...", Color.BLUE)
fail_ports = []
for port in ALL_PORTS:
ping, err = self.run_command(f'redis-cli -p {port} -a {self.redis_password} ping', capture_output=True)
if ping == 'PONG':
self.success(f"节点{port}:运行正常")
else:
self.error(f"节点{port}:启动失败,错误:{err}")
fail_ports.append(port)
# 若有节点启动失败,给出解决提示
if fail_ports:
self.error(f"以下节点启动失败:{fail_ports}")
self.echo("解决方法:1. 查看日志:tail -f /var/log/redis/redis_{port}.log", Color.YELLOW)
self.echo("2. 手动重启:systemctl restart redis-cluster@{port}", Color.YELLOW)
if not self.args.force:
sys.exit(1)
self.success("Redis集群节点启动完成!")
def create_cluster(self):
"""创建Redis Cluster三主三从集群(--cluster-replicas 1 表示1主1从)"""
self.echo("="*60, Color.BLUE)
self.echo("开始创建Redis三主三从集群...", Color.BLUE)
# 单机部署(核心场景):拼接所有节点地址
if len(self.node_ips) == 1:
node_list = [f"{self.local_ip}:{port}" for port in ALL_PORTS]
cluster_cmd = (
f'redis-cli --cluster create {" ".join(node_list)} '
f'--cluster-replicas 1 -a {self.redis_password} --cluster-yes'
)
# 执行集群创建命令
result, err = self.run_command(cluster_cmd, capture_output=True)
if 'OK' in result or 'cluster created correctly' in result:
self.success("Redis三主三从集群创建成功!")
else:
self.error(f"集群创建失败,错误:{err}")
self.echo("手动执行集群创建命令:\n" + cluster_cmd, Color.YELLOW)
if not self.args.force:
sys.exit(1)
# 多机部署(扩展场景):给出手动配置提示(需先在各节点部署单节点,再拼接)
else:
self.warn("检测到多节点IP,脚本暂不支持自动多机部署!")
self.echo("多机部署步骤:", Color.BLUE)
self.echo("1. 在每个节点执行本脚本,添加--skip-cluster 参数(仅部署节点,不创建集群)", Color.YELLOW)
self.echo("2. 在任意节点执行:redis-cli --cluster create 节点1:7000 节点1:7001 ... 节点3:7005 --cluster-replicas 1 -a 密码 --cluster-yes", Color.YELLOW)
time.sleep(3) # 等待集群状态稳定
def verify_cluster(self):
"""验证集群健康状态和读写功能"""
self.echo("="*60, Color.BLUE)
self.echo("开始验证Redis集群健康状态...", Color.BLUE)
# 1. 检查集群整体状态
check_cmd = f'redis-cli -p 7000 -a {self.redis_password} --cluster check {self.local_ip}:7000'
cluster_status, err = self.run_command(check_cmd, capture_output=True)
self.echo("集群状态检查结果:", Color.BLUE)
print(cluster_status)
# 2. 检查集群信息
info_cmd = f'redis-cli -p 7000 -a {self.redis_password} cluster info'
info, err = self.run_command(info_cmd, capture_output=True)
self.echo("\n集群核心信息:", Color.BLUE)
print(info)
# 3. 测试集群读写(-c 表示集群模式,自动重定向)
self.echo("\n开始测试集群读写功能...", Color.BLUE)
set_cmd = f'redis-cli -p 7000 -a {self.redis_password} -c set cluster_test "Hello Redis Cluster 3m3s"'
self.run_command(set_cmd)
get_cmd = f'redis-cli -p 7000 -a {self.redis_password} -c get cluster_test'
get_result, err = self.run_command(get_cmd, capture_output=True)
if get_result == 'Hello Redis Cluster 3m3s':
self.success("集群读写测试成功!")
else:
self.error(f"集群读写测试失败,结果:{get_result},错误:{err}")
self.success("Redis集群状态验证完成!")
def cleanup(self):
"""清理部署过程中的临时文件,释放磁盘空间"""
self.echo("="*60, Color.BLUE)
self.echo("开始清理部署临时文件...", Color.BLUE)
# 清理Redis源码和压缩包
redis_tar = f"/tmp/redis-{REDIS_VERSION}.tar.gz"
redis_src = f"/tmp/redis-{REDIS_VERSION}"
for f in [redis_tar, redis_src]:
if os.path.exists(f):
if os.path.isfile(f):
os.remove(f)
else:
shutil.rmtree(f)
self.echo(f"清理临时文件:{f}")
self.success("临时文件清理完成!")
def print_deploy_summary(self):
"""打印部署完成摘要,包含所有运维信息"""
self.echo("\n" + "="*80, Color.GREEN)
self.echo("🎉 Redis Cluster 三主三从 部署完成!🎉", Color.GREEN)
self.echo("="*80, Color.GREEN)
# 部署核心信息
self.echo(f"\n【核心部署信息】", Color.BLUE)
self.echo(f"Redis版本:{REDIS_VERSION}")
self.echo(f"集群节点:3主(7000/7001/7002) + 3从(7003/7004/7005)")
self.echo(f"访问密码:{self.redis_password}")
self.echo(f"运行用户:{REDIS_USER}")
self.echo(f"本机IP:{self.local_ip}")
self.echo(f"开放端口:7000-7005/tcp(数据)、17000-17005/tcp(集群总线)")
# 重要目录
self.echo(f"\n【重要目录】", Color.BLUE)
self.echo(f"配置文件:/etc/redis/{port}/ (每个端口独立目录)")
self.echo(f"数据目录:/data/redis/{port}/ (RDB/AOF文件)")
self.echo(f"日志目录:/var/log/redis/ (节点运行日志)")
self.echo(f"安装目录:{INSTALL_DIR}/redis-{REDIS_VERSION}/")
# 核心运维命令
self.echo(f"\n【核心运维命令】", Color.BLUE)
self.echo(f"一键启动集群:redis-cluster-start")
self.echo(f"一键停止集群:redis-cluster-stop")
self.echo(f"一键重启集群:redis-cluster-restart")
self.echo(f"查看集群状态:redis-cluster-status")
self.echo(f"单个节点管理:systemctl [start/stop/restart/status] redis-cluster@端口")
# 集群连接和检查
self.echo(f"\n【集群连接与检查】", Color.BLUE)
self.echo(f"连接集群:redis-cli -p 7000 -a {self.redis_password} -c")
self.echo(f"检查集群:redis-cli --cluster check {self.local_ip}:7000 -a {self.redis_password}")
self.echo(f"集群信息:redis-cli -p 7000 -a {self.redis_password} cluster info")
self.echo(f"节点信息:redis-cli -p 7000 -a {self.redis_password} cluster nodes")
# 故障排查提示
self.echo(f"\n【常见故障排查】", Color.BLUE)
self.echo(f"1. 节点启动失败:tail -f /var/log/redis/redis_7000.log")
self.echo(f"2. 集群连接失败:检查防火墙端口、集群公告IP是否正确")
self.echo(f"3. 内存不足:修改配置文件maxmemory参数,重启节点")
self.echo(f"4. 密码忘记:修改/etc/redis/端口/redis_端口.conf,重启节点")
self.echo("\n" + "="*80, Color.GREEN)
def main():
# 解析命令行参数
parser = argparse.ArgumentParser(
description='Redis Cluster 三主三从自动化部署脚本(CentOS7.x)',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('--nodes', help='集群节点IP列表,逗号分隔(多机扩展用,单机无需指定)')
parser.add_argument('--password', help=f'Redis访问密码(默认:{DEFAULT_PASSWORD},建议包含大小写+数字+特殊字符)')
parser.add_argument('--offline', action='store_true', help='离线模式(需提前准备依赖包和Redis安装包)')
parser.add_argument('--force', action='store_true', help='强制模式(忽略错误继续执行,仅用于排错)')
parser.add_argument('--skip-firewall', action='store_true', help='跳过防火墙配置(已手动配置时使用)')
parser.add_argument('--skip-cluster', action='store_true', help='跳过集群创建(仅部署节点,多机部署时使用)')
args = parser.parse_args()
# 打印脚本头部
print(Color.BLUE + "="*60 + Color.RESET)
print(Color.BLUE + "Redis Cluster 三主三从自动化部署脚本(CentOS7.x 优化版)" + Color.RESET)
print(Color.BLUE + "版本:2.0 | 适配:Redis 6.2.6 | 模式:单机三主三从" + Color.RESET)
print(Color.BLUE + "="*60 + Color.RESET)
# 创建部署实例并执行前置校验
deployer = RedisClusterDeployer(args)
deployer.pre_check()
# 部署前配置预览并确认
deployer.echo("\n【部署配置预览】", Color.BLUE)
deployer.echo(f"Redis版本:{REDIS_VERSION}")
deployer.echo(f"访问密码:{deployer.redis_password}")
deployer.echo(f"本机IP:{deployer.local_ip}")
deployer.echo(f"节点端口:{ALL_PORTS}")
deployer.echo(f"总线端口:{BUS_PORTS}")
deployer.echo(f"离线模式:{args.offline} | 强制模式:{args.force}")
deployer.echo(f"跳过防火墙:{args.skip_firewall} | 跳过集群创建:{args.skip_cluster}")
confirm = input(Color.YELLOW + "\n确认按以上配置部署?(yes/no):" + Color.RESET)
if confirm.lower() != 'yes':
deployer.echo("用户取消部署,退出程序!", Color.BLUE)
sys.exit(0)
# 执行核心部署步骤
try:
deployer.install_dependencies()
deployer.download_redis()
deployer.setup_environment()
deployer.create_cluster_configs()
if not args.skip_firewall:
deployer.configure_firewall()
deployer.start_redis_nodes()
if not args.skip_cluster:
deployer.create_cluster()
deployer.verify_cluster()
deployer.cleanup()
deployer.print_deploy_summary()
deployer.success("✅ Redis Cluster 三主三从部署全流程完成!")
except KeyboardInterrupt:
deployer.error("\n部署被用户手动中断!")
sys.exit(1)
except Exception as e:
deployer.error(f"\n部署过程中发生未捕获异常:{str(e)}")
import traceback
traceback.print_exc()
deployer.echo("建议查看以上错误信息,修复后重新执行脚本!", Color.YELLOW)
sys.exit(1)
if __name__ == "__main__":
main()
1分钟搭建 Redis三主三从集群!附完整自动化脚本(直接复制可用)
刘子毅2026-02-04 17:28