![]()
![]()
![]()
![]()
![]()
![]()
#!/usr/bin/env python3""" Redis Cluster三主三从自动化部署脚本 支持CentOS7.x系统 作者: Redis自动化部署工具 版本:1.0"""importosimportsysimportsubprocessimportshutilimportargparseimportsocketimporttimefrom pathlibimportPath class RedisClusterDeployer: def __init__(self, args): self.args=args self.redis_version="6.2.6"self.redis_url=f"https://download.redis.io/releases/redis-{self.redis_version}.tar.gz"self.redis_user="redis"# 使用redis用户self.redis_password=args.password or"RedisPass@123"self.install_dir="/opt/redis"self.nodes=args.nodes# 节点列表,格式: ip1,ip2,ip3# 三主三从集群端口配置self.master_ports=[7000,7001,7002]# 主节点端口self.slave_ports=[7003,7004,7005]# 从节点端口self.all_ports=self.master_ports + self.slave_ports# 所有节点IPself.node_ips=self.nodes.split(',')ifself.nodeselseself.get_local_ips()def get_local_ips(self):"""获取本机IP地址""" try:# 获取非localhost的IPs=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(('8.8.8.8',80))local_ip=s.getsockname()[0]s.close()return[local_ip]except:return['127.0.0.1']def run_command(self, cmd,shell=True,check=True,capture_output=False):"""执行Shell命令""" print(f"执行命令: {cmd}")try:ifcapture_output:# Python 3.6兼容版本result=subprocess.run(cmd,shell=shell,check=check,stdout=subprocess.PIPE,stderr=subprocess.PIPE,universal_newlines=True)returnresult.stdout.strip()else: subprocess.run(cmd,shell=shell,check=check)returnTrue except subprocess.CalledProcessError as e: print(f"命令执行失败: {e}")ifcapture_output: print(f"错误输出: {e.stderr}")ifnot self.args.force: sys.exit(1)returnFalse def install_dependencies(self):"""安装系统依赖""" print("="*60)print("开始安装系统依赖...")# 检查系统ifnot os.path.exists('/etc/redhat-release'): print("警告: 当前系统可能不是CentOS/RHEL")# 安装基础依赖deps=['gcc','tcl','make','wget','tar','systemd-devel']ifself.args.offline: print("离线模式: 请确保已上传依赖包到 /tmp/rpms/")ifos.path.exists('/tmp/rpms/'): self.run_command('yum localinstall -y /tmp/rpms/*.rpm')else: self.run_command('yum install -y epel-release')self.run_command(f'yum install -y {" ".join(deps)}')# 创建redis用户self.run_command(f'id {self.redis_user} &>/dev/null || useradd -r -s /sbin/nologin {self.redis_user}')print("系统依赖安装完成!")def download_redis(self):"""下载并编译Redis""" print("="*60)print("开始下载和编译Redis...")redis_tar=f"/tmp/redis-{self.redis_version}.tar.gz"redis_src=f"/tmp/redis-{self.redis_version}"# 下载Redisifnot os.path.exists(redis_tar):ifself.args.offline: print(f"离线模式: 请确保Redis安装包已上传到 {redis_tar}")ifnot os.path.exists(redis_tar): print("错误: Redis安装包不存在!")sys.exit(1)else: print(f"下载Redis {self.redis_version}...")self.run_command(f'wget {self.redis_url} -O {redis_tar}')# 解压print("解压Redis源码...")self.run_command(f'tar -xzf {redis_tar} -C /tmp/')# 编译安装print("编译安装Redis...")os.chdir(redis_src)self.run_command('make clean')self.run_command('make')self.run_command('make install PREFIX=/usr/local')# 创建软链接和目录self.run_command(f'mkdir -p {self.install_dir}')ifos.path.exists(f'{self.install_dir}/redis-{self.redis_version}'): shutil.rmtree(f'{self.install_dir}/redis-{self.redis_version}')shutil.copytree(redis_src, f'{self.install_dir}/redis-{self.redis_version}')print("Redis编译安装完成!")def setup_environment(self):"""设置环境变量""" print("="*60)print("设置环境变量...")# 添加环境变量env_lines=['# Redis Environment', f'export PATH={self.install_dir}/redis-{self.redis_version}/src:$PATH','export REDIS_HOME=/usr/local/share/redis']with open('/etc/profile.d/redis.sh','w')as f: f.write('\n'.join(env_lines)+'\n')self.run_command('source /etc/profile.d/redis.sh')# 验证安装 - 使用which命令先找到redis-cli路径redis_cli_path=self.run_command('which redis-cli',capture_output=True)ifredis_cli_path: result=self.run_command(f'{redis_cli_path} --version',capture_output=True)print(f"Redis版本: {result}")else: print("警告: redis-cli未找到在PATH中,可能需要手动添加")print("环境变量设置完成!")def create_cluster_configs(self):"""创建集群配置文件""" print("="*60)print("创建Redis集群配置文件...")# 对每个端口创建配置forportinself.all_ports: conf_dir=f"/etc/redis/{port}"data_dir=f"/data/redis/{port}"log_dir=f"/var/log/redis"# 创建目录fordir_pathin[conf_dir, data_dir, log_dir]: self.run_command(f'mkdir -p {dir_path}')# 确定节点类型(主节点还是从节点)cluster_mode='yes'ifportinself.master_ports: node_type='master'else: node_type='slave'# 生成配置文件config=f"""# Redis Cluster 配置 - 端口{port}bind0.0.0.0 port{port}daemonizeyespidfile /var/run/redis_{port}.pid logfile{log_dir}/redis_{port}.logdir{data_dir}dbfilename dump_{port}.rdb appendonlyyesappendfilename"appendonly_{port}.aof"appendfsync everysec# 集群配置cluster-enabledyescluster-config-file{conf_dir}/nodes_{port}.conf cluster-node-timeout15000# 安全配置requirepass{self.redis_password}masterauth{self.redis_password}# 性能优化maxmemory 2gb maxmemory-policy allkeys-lru tcp-backlog511timeout0tcp-keepalive300# 持久化save9001save30010save6010000stop-writes-on-bgsave-erroryesrdbcompressionyesrdbchecksumyes# 复制replica-serve-stale-datayesreplica-read-onlyyesrepl-diskless-sync no repl-diskless-sync-delay5# 集群总线端口 (端口 + 10000)cluster-announce-port{port}cluster-announce-bus-port{port +10000}"""# 写入配置文件config_file=f"{conf_dir}/redis_{port}.conf"with open(config_file,'w')as f: f.write(config)# 设置权限self.run_command(f'chown -R {self.redis_user}:{self.redis_user} {conf_dir}')self.run_command(f'chown -R {self.redis_user}:{self.redis_user} {data_dir}')self.run_command(f'chown -R {self.redis_user}:{self.redis_user} {log_dir}')print(f"端口 {port} ({node_type}) 配置创建完成")# 创建systemd服务文件self.create_systemd_service()print("集群配置文件创建完成!")def create_systemd_service(self):"""创建systemd服务文件""" service_template="""[Unit]Description=Redis Cluster Node %iAfter=network.target[Service]Type=forkingUser=redisGroup=redisExecStart=/usr/local/bin/redis-server /etc/redis/%i/redis_%i.confExecStop=/usr/local/bin/redis-cli -p %i -a{password}shutdownRestart=alwaysRestartSec=10[Install]WantedBy=multi-user.target""".format(password=self.redis_password)forportinself.all_ports: service_file=f"/etc/systemd/system/redis-cluster@{port}.service"with open(service_file,'w')as f: f.write(service_template)# 创建启停脚本start_script="""#!/bin/bash# Redis Cluster 启动脚本forportin700070017002700370047005;dosystemctl start redis-cluster@$portecho"启动 Redis 端口$port"sleep1doneecho"所有Redis节点已启动!"""" stop_script="""#!/bin/bash# Redis Cluster 停止脚本forportin700070017002700370047005;dosystemctl stop redis-cluster@$portecho"停止 Redis 端口$port"doneecho"所有Redis节点已停止!"""" status_script="""#!/bin/bash# Redis Cluster 状态脚本forportin700070017002700370047005;dosystemctl status redis-cluster@$port--no-pager -lecho"----------------------------------------"done""" 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}forscript_path, contentinscripts.items(): with open(script_path,'w')as f: f.write(content)self.run_command(f'chmod +x {script_path}')print("Systemd服务文件创建完成!")def configure_firewall(self):"""配置防火墙""" print("="*60)print("配置防火墙...")# 检查firewalld是否运行try: self.run_command('systemctl is-active firewalld',capture_output=True)firewall_active=True except: firewall_active=Falseiffirewall_active: print("配置firewalld规则...")forportinself.all_ports:# 数据端口self.run_command(f'firewall-cmd --permanent --add-port={port}/tcp')# 集群总线端口self.run_command(f'firewall-cmd --permanent --add-port={port+10000}/tcp')self.run_command('firewall-cmd --reload')print("防火墙规则已添加!")else: print("firewalld未运行,跳过防火墙配置")def start_redis_nodes(self):"""启动Redis节点""" print("="*60)print("启动Redis节点...")# 重新加载systemdself.run_command('systemctl daemon-reload')# 启动所有节点forportinself.all_ports: self.run_command(f'systemctl enable redis-cluster@{port}')self.run_command(f'systemctl start redis-cluster@{port}')time.sleep(1)print(f"端口 {port} 启动完成")# 等待节点启动print("等待节点启动...")time.sleep(5)# 检查节点状态forportinself.all_ports: try: result=self.run_command(f'redis-cli -p {port} -a {self.redis_password} ping',capture_output=True)ifresult=='PONG':print(f"✓ 端口 {port}: 运行正常")else: print(f"✗ 端口 {port}: 启动失败 - {result}")except: print(f"✗ 端口 {port}: 启动失败")print("所有Redis节点启动完成!")def create_cluster(self):"""创建Redis集群""" print("="*60)print("创建Redis Cluster集群...")# 如果只在单机部署,使用本地IPiflen(self.node_ips)==1:ip=self.node_ips[0]# 单机部署三主三从nodes=[]forportinself.master_ports + self.slave_ports: nodes.append(f"{ip}:{port}")cluster_cmd=(f'redis-cli --cluster create 'f'{" ".join(nodes)} 'f'--cluster-replicas 1 'f'-a {self.redis_password} 'f'--cluster-yes')else:# 多机部署 - 这里简化处理,实际需要更复杂的逻辑print("多机部署需要手动配置节点映射...")print("请手动执行以下命令创建集群:")print(f"redis-cli --cluster create <节点列表> --cluster-replicas 1 -a {self.redis_password}")returnprint(f"执行集群创建命令:")print(cluster_cmd)# 执行集群创建try:# 这里使用subprocess.Popen以便可以输入yesprocess=subprocess.Popen(cluster_cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,universal_newlines=True)# 集群创建过程可能需要一些时间stdout, stderr=process.communicate(timeout=60)print("集群创建输出:")print(stdout)ifstderr: print("错误信息:")print(stderr)ifprocess.returncode==0: print("✓ Redis Cluster集群创建成功!")else: print("✗ 集群创建失败,请检查日志")except subprocess.TimeoutExpired: process.kill()print("集群创建超时,请手动检查集群状态")print("集群创建完成!")def verify_cluster(self):"""验证集群状态""" print("="*60)print("验证Redis Cluster状态...")# 检查集群信息check_cmd=f'redis-cli -p {self.all_ports[0]} -a {self.redis_password} --cluster check 127.0.0.1:{self.all_ports[0]}'result=self.run_command(check_cmd,capture_output=True)print("集群状态检查结果:")print(result)# 测试集群读写print("\n测试集群读写...")test_cmd=f'redis-cli -p {self.all_ports[0]} -a {self.redis_password} -c set test_key "Hello Redis Cluster"'self.run_command(test_cmd)get_cmd=f'redis-cli -p {self.all_ports[0]} -a {self.redis_password} -c get test_key'result=self.run_command(get_cmd,capture_output=True)if'Hello Redis Cluster'inresult: print("✓ 集群读写测试成功!")else: print("✗ 集群读写测试失败!")print("集群验证完成!")def print_summary(self):"""打印部署摘要""" print("\n"+"="*60)print("Redis Cluster 部署完成!")print("="*60)print("\n部署信息:")print(f" Redis版本: {self.redis_version}")print(f" 运行用户: {self.redis_user}")print(f" 节点数量: 3主3从 (共6个节点)")print(f" 数据端口: {', '.join(map(str, self.all_ports))}")print(f" 集群总线端口: {', '.join(map(str, [p+10000 for p in self.all_ports]))}")print(f" 密码: {self.redis_password}")print("\n重要目录:")print(f" 配置文件: /etc/redis/{{port}}/")print(f" 数据目录: /data/redis/{{port}}/")print(f" 日志目录: /var/log/redis/")print(f" 安装目录: {self.install_dir}/")print("\n管理命令:")print(" 启动所有节点: redis-cluster-start")print(" 停止所有节点: redis-cluster-stop")print(" 查看状态: redis-cluster-status")print(" 单个节点管理: systemctl [start|stop|status] redis-cluster@<port>")print("\n连接集群:")print(f" 命令行: redis-cli -p 7000 -a {self.redis_password} -c")print(" 检查集群: redis-cli --cluster check 127.0.0.1:7000 -a <password>")print(" 集群信息: redis-cli --cluster info 127.0.0.1:7000 -a <password>")print("\n下一步:")print(" 1. 确保防火墙已开放对应端口")print(" 2. 使用 redis-cluster-status 检查所有节点状态")print(" 3. 使用 redis-cli --cluster check 验证集群健康状态")print(" 4. 配置监控和备份策略")print("\n"+"="*60)def cleanup(self):"""清理安装文件""" print("\n清理临时文件...")redis_tar=f"/tmp/redis-{self.redis_version}.tar.gz"redis_src=f"/tmp/redis-{self.redis_version}"ifos.path.exists(redis_tar): os.remove(redis_tar)ifos.path.exists(redis_src): shutil.rmtree(redis_src)print("清理完成!")def main(): parser=argparse.ArgumentParser(description='Redis Cluster三主三从自动化部署脚本')parser.add_argument('--nodes',help='节点IP列表,用逗号分隔 (例: 192.168.1.10,192.168.1.11,192.168.1.12)')parser.add_argument('--password',help='Redis密码 (默认: RedisPass@123)')parser.add_argument('--offline',action='store_true',help='离线模式')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()# 检查是否为root用户ifos.geteuid()!=0: print("错误: 需要root权限运行此脚本!")print("请使用: sudo python3 redis_cluster_deploy.py")sys.exit(1)print("Redis Cluster三主三从自动化部署脚本")print("="*60)# 确认部署confirm=input("确认部署Redis三主三从集群? (yes/no): ")ifconfirm.lower()!='yes':print("部署取消")sys.exit(0)# 创建部署器实例deployer=RedisClusterDeployer(args)try:# 执行部署步骤deployer.install_dependencies()deployer.download_redis()deployer.setup_environment()deployer.create_cluster_configs()ifnot args.skip_firewall: deployer.configure_firewall()deployer.start_redis_nodes()ifnot args.skip_cluster: deployer.create_cluster()time.sleep(3)# 等待集群稳定deployer.verify_cluster()deployer.cleanup()deployer.print_summary()print("\n部署完成! ✓")except KeyboardInterrupt: print("\n\n部署被用户中断!")sys.exit(1)except Exception as e: print(f"\n部署过程中发生错误: {e}")importtraceback traceback.print_exc()sys.exit(1)if__name__=="__main__":main()
使用方法:
1. 运行部署:# 给予执行权限chmod+x redis_cluster_kylin.py# 运行完整部署脚本sudopython3 redis_cluster_kylin.py# 或者运行快速部署脚本sudopython3 redis_kylin_quick.py
- 自定义配置:
# 自定义密码sudopython3 redis_cluster_kylin.py --password"YourStrongPassword@123"# 跳过防火墙配置sudopython3 redis_cluster_kylin.py --skip-firewall# 强制模式(忽略错误继续)sudopython3 redis_cluster_kylin.py --force