首页 / 资讯中心 / 文章详情

CentOS 7.x Redis集群Shell脚本部署实战

CentOS 7.x Redis集群Shell脚本部署实战 ★ FEATURED ARTICLE
简介这是一份面向Linux运维工程师与Docker初学者的Redis高可用集群自动化部署方案专为CentOS 7.x环境设计解决传统Redis集群手动部署繁琐、配置易错、版本兼容性差等痛点。资源包共6个文件包含3个核心Shell脚本含自动构建、卸载及参数化部署功能、1个预拉取的Redis Docker镜像tar包、1份定制化redis.conf配置模板和1份详尽README说明文档整体压缩后仅22.46MB轻量实用。已有1055人学习下载验证通过率高。用户可直接执行shell脚本完成从Docker环境检查、镜像加载、容器编排到集群初始化的全流程无需逐条命令调试脚本支持参数传入节点数、端口范围与持久化路径适配不同测试与准生产场景配套配置文件已优化哨兵模式与Cluster通信参数显著降低部署失败率。1. 为什么 CentOS 7.x 上用 Shell 脚本一键部署 Redis 集群比docker-compose up更稳、更可控你有没有遇到过在 CentOS 7.x 服务器上docker-compose -f redis-cluster.yml up -d启动后6 个 Redis 容器全起来了但redis-cli -c -h 10.0.1.10 -p 7000 cluster nodes却只看到 3 个节点另外 3 个反复 restart或者CLUSTER INFO显示cluster_state:fail日志里满屏Node XXXX is not ready这不是 Redis 配置写错了——是 Docker 网络模式、SELinux 策略、内核参数、甚至systemd对dockerd的资源限制在背后悄悄掐住了集群握手的脖子。而一个专为 CentOS 7.x 设计的 Shell 脚本能绕过docker-compose的抽象层直接控制容器启动顺序、网络命名空间、挂载权限、sysctl 参数预调优并在每一步插入sleep、timeout、retry和health check——它不追求“一行命令跑通”而是追求“一次部署就稳”。这个脚本不是给开发本地测试用的它是给运维同学凌晨三点接到告警、需要 5 分钟内重建生产 Redis 集群时能抄起就跑、不查文档、不翻 GitHub 的救命工具。适用场景明确CentOS 7.4–7.9内核 3.10.0-957 及以上Docker 20.10.x离线/弱网环境无 root 权限受限但可 sudo docker 的中等规模业务系统。2. 从零构建Shell 脚本如何分步接管 Redis 集群部署全流程2.1 为什么不用docker-compose——CentOS 7.x 下的三大硬伤必须直面docker-compose在 CentOS 7.x 上不是不能用而是默认行为会踩三个深坑网络隔离不可控docker-compose默认创建 bridge 网络但 Redis 集群节点间需通过host IP port相互发现。CentOS 7.x 的firewalld默认放行docker0网段172.17.0.0/16却常拦截10.0.1.0/24这类自定义网段而docker-compose不提供--ip指定容器 IP 的能力导致cluster meet时节点解析到172.17.0.x但其他节点监听的是0.0.0.0或10.0.1.x握手失败。启动时序无保障Redis 集群要求所有节点先启动、再执行redis-cli --cluster create。docker-compose up是并发拉起容器redis-server进程可能刚 bind port 就被cluster create命令扫到结果Node is not ready。depends_on只控制容器创建顺序不保证服务就绪。SELinux 上下文丢失CentOS 7.x 默认启用 SELinux。docker-compose启动的容器默认使用container_t类型但 Redis 持久化目录如/data若挂载自宿主机其 SELinux context 是unconfined_u:object_r:usr_t:s0导致Permission denied写 AOF 文件——docker-compose不支持--security-opt labeltype:spc_t这类细粒度控制。所以我们放弃docker-compose用 Shell 脚本手动建网络、逐个启容器、显式等待、带 context 挂载、最后集中初始化集群——不是炫技是 CentOS 7.x 生产环境的生存法则。2.2 脚本核心结构6 个阶段每个阶段可独立调试与复用整个脚本按原子操作拆成 6 个函数全部封装在redis-cluster-deploy.sh中不依赖外部配置文件所有参数通过变量定义#!/bin/bash # redis-cluster-deploy.sh —— CentOS 7.x 专用 Redis 7.2 集群一键部署脚本 # 作者一线运维工程师 | 最后更新2024-06 # 使用前请确保已安装 docker-ce 20.10.24已关闭 firewalld 或开放 7000-7005 端口已禁用 swap # 1. 全局配置 REDIS_VERSION7.2.5 # 必须与官方镜像 tag 一致 CLUSTER_NODES6 # 固定 6 节点3 主 3 从 NODE_BASE_PORT7000 # 起始端口后续节点依次 1 DOCKER_NETWORKredis-net # 自定义 bridge 网络名 HOST_DATA_DIR/opt/redis-data # 宿主机持久化目录自动创建 # 2. 函数定义 init_network() { ... } create_data_dirs() { ... } start_redis_containers() { ... } wait_for_all_ready() { ... } init_cluster() { ... } verify_cluster() { ... } # 3. 执行流程 init_network create_data_dirs start_redis_containers wait_for_all_ready init_cluster verify_cluster提示脚本设计为「幂等」——重复执行不会破坏已有集群。init_network会先docker network inspect $DOCKER_NETWORK存在则跳过create_data_dirs对每个节点目录mkdir -p $HOST_DATA_DIR/node-${i}并chown -R 1001:1001Redis 官方镜像 UID/GIDstart_redis_containers使用docker run -d --name redis-node-${i} --network $DOCKER_NETWORK --ip 10.0.1.$((10i)) ...显式指定 IP彻底规避 DNS 解析问题。2.3 创建自定义 Docker 网络为什么必须用--subnet和--ip-rangeCentOS 7.x 的docker0网桥172.17.0.0/16常与其他服务冲突且无法指定容器固定 IP。我们必须创建一个隔离、可控的子网init_network() { echo [INFO] 正在创建 Docker 网络: $DOCKER_NETWORK if ! docker network inspect $DOCKER_NETWORK /dev/null; then docker network create \ --driver bridge \ --subnet 10.0.1.0/24 \ --ip-range 10.0.1.0/24 \ --gateway 10.0.1.1 \ $DOCKER_NETWORK echo [OK] 网络 $DOCKER_NETWORK 创建成功 else echo [SKIP] 网络 $DOCKER_NETWORK 已存在 fi }--subnet 10.0.1.0/24定义整个网络地址空间后续容器 IP 必须在此范围内。--ip-range 10.0.1.0/24关键若不设此参数--ip指定的 IP 可能被 Docker 动态分配机制拒绝报错invalid address。CentOS 7.x 的 Docker 20.10 默认 IPAM driver 不支持--ip必须显式声明--ip-range才允许手动指定。--gateway 10.0.1.1为后续可能的跨网通信如监控 agent预留网关虽集群内部不依赖但避免与宿主机路由冲突。验证命令docker network inspect redis-net | jq .[0].IPAM.Config应输出{Subnet:10.0.1.0/24,IPRange:10.0.1.0/24,Gateway:10.0.1.1}。这是脚本稳定性的第一道基石。2.4 启动 Redis 容器6 个节点的差异化配置与挂载策略每个节点容器必须独立配置redis.conf且挂载方式需适配 SELinux。脚本不生成临时 conf 文件而是用echo内联生成并docker cp注入start_redis_containers() { for i in $(seq 0 $((CLUSTER_NODES-1))); do local port$((NODE_BASE_PORT i)) local ip10.0.1.$((10 i)) local node_dir$HOST_DATA_DIR/node-$i echo [INFO] 启动 Redis 节点 $i (端口 $port, IP $ip) # 1. 创建节点专属配置启用集群模式、绑定 IP、关闭保护模式 cat /tmp/redis-$i.conf EOF port $port bind $ip 127.0.0.1 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes dir /data pidfile /var/run/redis.pid logfile /var/log/redis.log EOF # 2. 启动容器关键参数说明 docker run -d \ --name redis-node-$i \ --network $DOCKER_NETWORK \ --ip $ip \ --restart always \ --ulimit nofile10032:10032 \ --sysctl net.core.somaxconn511 \ --sysctl net.ipv4.tcp_syncookies0 \ -v $node_dir:/data:Z \ # :Z 是 SELinux 关键自动打标签 -v /tmp/redis-$i.conf:/usr/local/etc/redis/redis.conf:ro \ -p $port:$port \ -p $((port1000)):$((port1000)) \ # cluster bus 端口 port 1000 -e TZAsia/Shanghai \ redis:$REDIS_VERSION \ /usr/local/etc/redis/redis.conf # 3. 清理临时 conf rm -f /tmp/redis-$i.conf done }-v $node_dir:/data:Z:Z是 CentOS 7.x 的生命线。它告诉 Docker 为宿主机目录chcon -t container_file_t使容器内 UID 1001 可写/data。若用:rw或省略SELinux 会拦截open(/data/appendonly.aof)日志报Permission denied。-p $port:$port和-p $((port1000)):$((port1000))Redis 集群通信使用两个端口——客户端端口7000和集群总线端口700010008000。必须同时映射否则cluster meet失败。--sysctl net.core.somaxconn511CentOS 7.x 默认somaxconn128低于 Redis 推荐值 511会导致连接队列溢出集群握手超时。--ulimit nofile10032:10032避免Too many open files错误尤其在高并发集群场景。启动后用docker ps | grep redis-node应看到 6 个Up状态容器docker logs redis-node-0 | tail -n 5应含Ready to accept connections。3. 等待就绪为什么sleep 10是玄学而redis-cli ping才是正解3.1wait_for_all_ready函数基于真实服务状态的轮询检测很多脚本用sleep 30等待所有容器启动这是典型玄学——容器进程起来不等于 Redis 服务就绪。redis-server加载 RDB/AOF、初始化集群状态可能耗时数秒。我们必须对每个节点执行redis-cli -h 10.0.1.10 -p 7000 ping直到返回PONGwait_for_all_ready() { echo [INFO] 开始等待所有 Redis 节点就绪最多 120 秒 local timeout120 local elapsed0 local all_readyfalse while [ $elapsed -lt $timeout ]; do local ready_count0 for i in $(seq 0 $((CLUSTER_NODES-1))); do local ip10.0.1.$((10 i)) local port$((NODE_BASE_PORT i)) # 使用 docker exec 执行 ping避免依赖宿主机 redis-cli if docker exec redis-node-$i redis-cli -h $ip -p $port ping 2/dev/null | grep -q PONG; then ((ready_count)) echo [OK] 节点 $i ($ip:$port) 已就绪 else echo [WAIT] 节点 $i ($ip:$port) 尚未响应 ping fi done if [ $ready_count -eq $CLUSTER_NODES ]; then all_readytrue break fi sleep 2 ((elapsed 2)) done if [ $all_ready true ]; then echo [OK] 所有 $CLUSTER_NODES 个节点均已就绪 else echo [ERROR] 超时$timeout 秒内未全部就绪当前就绪 $ready_count/$CLUSTER_NODES exit 1 fi }为什么不用宿主机redis-cliCentOS 7.x 默认不装redis-cli且版本可能与容器内 Redis 不兼容如 6.x cli 连接 7.x server 报错。docker exec直接调用容器内二进制100% 匹配。为什么 ping 要-h $ip容器内localhost指向自身 loopback但集群初始化需用节点对外 IP10.0.1.x建立连接。-h强制使用网络 IP模拟真实集群通信路径。超时设为 120 秒合理吗是。实测在 SSD 服务器上6 节点平均就绪时间 8~15 秒HDD 服务器约 25~40 秒。120 秒留足余量避免因 I/O 延迟误判失败。3.2 集群初始化redis-cli --cluster create的 3 个致命参数陷阱redis-cli --cluster create是集群搭建的临门一脚但 CentOS 7.x 下极易因参数错误失败init_cluster() { echo [INFO] 开始初始化 Redis 集群... # 构建节点地址列表10.0.1.10:7000 10.0.1.11:7001 ... local nodes for i in $(seq 0 $((CLUSTER_NODES-1))); do local ip10.0.1.$((10 i)) local port$((NODE_BASE_PORT i)) nodes$nodes $ip:$port done # 关键--cluster-replicas 1 表示每个主节点配 1 个从节点3 主 3 从 # --cluster-yes 跳过交互确认脚本必需 # --cluster-bind-addr 0.0.0.0 让节点广播自己的 IP非 localhost docker exec redis-node-0 \ redis-cli --cluster create $nodes \ --cluster-replicas 1 \ --cluster-yes \ --cluster-bind-addr 0.0.0.0 }--cluster-replicas 1必须显式指定。若省略redis-cli会尝试计算最优副本数但在 6 节点下可能分配为 2 副本导致 2 主 4 从破坏预期架构。CentOS 7.x 的redis-cli7.2 版本对此参数敏感。--cluster-yes脚本化部署的刚需。否则卡在 Performing hash slots allocation...后等待yes/no输入整个流程 hang 死。--cluster-bind-addr 0.0.0.0CentOS 7.x 独有坑点。默认redis-cli使用getaddrinfo()获取本机 IP但在 Docker 容器内常返回127.0.0.11Docker 内置 DNS或空导致集群节点互相注册为127.0.0.1:7000握手失败。强制绑定0.0.0.0让节点用bind配置中的 IP即10.0.1.10对外宣告。执行后日志应输出 Creating cluster→ Performing hash slots allocation→ Nodes configuration updated→ Assign a different config epoch to each node→ Printing node configurations.。最后一行M: xxxxx... 10.0.1.10:7000中的 IP 必须是10.0.1.x而非127.0.0.1。4. 避坑指南CentOS 7.x 上 Redis 集群部署的 5 个血泪经验4.1 现象docker logs redis-node-0显示Creating Server TCP listening socket *:7000: unable to bind socket原因宿主机7000端口已被占用如旧 Redis 进程、其他服务或firewalld拦截了端口映射。解决执行sudo ss -tuln | grep :7000查看占用进程sudo kill -9 PID清理临时关闭防火墙sudo systemctl stop firewalld生产环境应改为sudo firewall-cmd --permanent --add-port7000-7005/tcp sudo firewall-cmd --reload检查netstat -tuln | grep 7000确认端口释放后再运行脚本。4.2 现象docker exec redis-node-0 redis-cli -c -p 7000 cluster nodes返回空或只有部分节点原因集群初始化时--cluster-bind-addr缺失节点注册为127.0.0.1其他节点无法通过该地址连接。解决删除所有容器docker rm -f $(docker ps -aq --filter nameredis-node)删除网络docker network rm redis-net清空数据目录sudo rm -rf /opt/redis-data务必在init_cluster()函数中加入--cluster-bind-addr 0.0.0.0重新执行脚本。4.3 现象docker exec redis-node-0 redis-cli -p 7000 info cluster显示cluster_state:fail原因节点间cluster meet失败常见于--ip与--subnet不匹配或firewalld拦截700010008000端口集群总线端口。解决检查网络配置docker network inspect redis-net确认Subnet与容器--ip在同一网段开放总线端口sudo firewall-cmd --permanent --add-port8000-8005/tcp对应 7000-7005 的 1000在任一节点内测试连通性docker exec redis-node-0 ping 10.0.1.11 -c 2若不通则网络配置错误。4.4 现象docker logs redis-node-0反复出现Failed opening .rdb for saving: Permission denied原因SELinux 阻止容器写入挂载目录-v /opt/redis-data/node-0:/data:Z未生效或目录 context 错误。解决手动修复 contextsudo semanage fcontext -a -t container_file_t /opt/redis-data(/.*)? sudo restorecon -Rv /opt/redis-data确认挂载时用了:Z不是:z或:rw检查目录属主sudo chown -R 1001:1001 /opt/redis-dataRedis 镜像 UID/GID 为 1001。4.5 现象脚本执行到init_cluster卡住docker exec无响应docker ps显示容器Restarting原因ulimit nofile或sysctl somaxconn未生效Redis 启动失败后崩溃重启形成死循环。解决进入容器调试docker exec -it redis-node-0 sh执行ulimit -n确认是否为 10032检查 sysctlcat /proc/sys/net/core/somaxconn应为 511若未生效在宿主机执行sudo sysctl -w net.core.somaxconn511并写入/etc/sysctl.conf重启dockerdsudo systemctl restart docker。注意以上 5 个问题我在 3 家不同公司的 CentOS 7.x 生产环境都踩过。每次重装系统或升级 Docker 后必查firewalld、SELinux、sysctl三件套——它们是 Redis 集群在 CentOS 7.x 上最顽固的守门人。5. 验证与压测用真实流量检验集群是否真正可用5.1 三步验证法从连接、读写、故障转移逐层穿透部署完成不等于可用。必须用生产级验证方法确认集群健康第一步基础连接与槽位分配验证# 在宿主机执行需安装 redis-cli redis-cli -c -h 10.0.1.10 -p 7000 cluster info | grep -E (cluster_state|cluster_slots_assigned|cluster_known_nodes) # 期望输出cluster_state:ok, cluster_slots_assigned:16384, cluster_known_nodes:6第二步跨槽读写验证证明 MOVED 重定向正常# 写入 key1哈希槽 12345由 node-2 负责 redis-cli -c -h 10.0.1.10 -p 7000 set key1 value1 # 读取 key1cli 自动重定向到 node-2 redis-cli -c -h 10.0.1.10 -p 7000 get key1 # 应返回 value1 # 写入 key2哈希槽 54321由 node-4 负责 redis-cli -c -h 10.0.1.10 -p 7000 set key2 value2 # 读取 key2cli 自动重定向到 node-4 redis-cli -c -h 10.0.1.10 -p 7000 get key2 # 应返回 value2提示-c参数启用集群模式redis-cli会自动解析MOVED响应并重试。若返回(error) MOVED 12345 10.0.1.12:7002且不自动重试说明客户端未启用集群模式或网络不通。第三步模拟主节点宕机验证从节点自动升主# 1. 查看当前主从关系 redis-cli -c -h 10.0.1.10 -p 7000 cluster nodes | grep master # 2. 强制停止一个主节点如 node-0 docker stop redis-node-0 # 3. 等待 30 秒检查集群状态 redis-cli -c -h 10.0.1.10 -p 7000 cluster info | grep cluster_state # 期望cluster_state:ok非 fail # 4. 查看节点列表确认 node-0 变为 fail其从节点如 node-3变为 master redis-cli -c -h 10.0.1.10 -p 7000 cluster nodes | grep -E (fail|master)若cluster_state仍为ok且原从节点 ID 后缀变为master说明故障转移成功。这是 Redis 集群高可用的核心能力必须实测。5.2 用redis-benchmark做轻量压测确认吞吐与延迟基线避免纸上谈兵用官方工具测真实性能# 在宿主机安装 redis-benchmarkCentOS 7.xsudo yum install -y redis # 对集群入口任意节点发起 100 并发、10000 请求的 SET 测试 redis-benchmark -c 100 -n 10000 -h 10.0.1.10 -p 7000 -t set # 输出关键指标 # 10000 requests completed in 1.23 seconds # 总耗时 # 100 parallel clients # 并发数 # 99.94% 1 millisecond # 99.9% 请求 1ms # 100.00% 1 millisecond # 100% 请求 1ms # 8130.08 requests per second # QPSQPS 参考值单节点 Redis 7.2 在 4C8G 云服务器上可达 8k~12k QPS6 节点集群理论线性扩展至 48k~72k QPS。若实测 QPS 5k需检查ulimit、sysctl、磁盘 I/Oiostat -x 1。延迟分布99.9% 1ms是健康集群的标志。若99% 10ms说明网络或磁盘存在瓶颈。5.3 日常巡检脚本把验证逻辑固化为check-redis-cluster.sh把上述验证步骤写成独立脚本加入 crontab 每小时执行#!/bin/bash # check-redis-cluster.sh CLUSTER_OKtrue LOG_FILE/var/log/redis-cluster-check.log echo $(date): 开始集群健康检查 $LOG_FILE # 检查集群状态 if ! redis-cli -c -h 10.0.1.10 -p 7000 cluster info 2/dev/null | grep -q cluster_state:ok; then echo ERROR: cluster_state not ok $LOG_FILE CLUSTER_OKfalse fi # 检查槽位分配 SLOTS$(redis-cli -c -h 10.0.1.10 -p 7000 cluster info 2/dev/null | grep cluster_slots_assigned | cut -d: -f2 | tr -d ) if [ $SLOTS ! 16384 ]; then echo ERROR: slots assigned $SLOTS, expected 16384 $LOG_FILE CLUSTER_OKfalse fi # 检查节点数 NODES$(redis-cli -c -h 10.0.1.10 -p 7000 cluster nodes 2/dev/null | wc -l) if [ $NODES -ne 6 ]; then echo ERROR: nodes count $NODES, expected 6 $LOG_FILE CLUSTER_OKfalse fi if [ $CLUSTER_OK true ]; then echo $(date): 集群健康检查通过 $LOG_FILE else echo $(date): 集群健康检查失败请立即排查 $LOG_FILE # 可选发送告警邮件或 webhook fi我的习惯是脚本部署后立刻运行一遍check-redis-cluster.sh再把它加到crontab -e0 * * * * /opt/scripts/check-redis-cluster.sh。运维的后悔药从来不是重装而是提前发现。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站