CentOS 7.x Docker部署Redis集群避坑指南
简介这是一份面向Linux系统运维工程师与Docker初学者的Redis高可用集群自动化部署工具包专为CentOS 7.x环境设计解决手动搭建Redis Cluster流程繁琐、配置易错、版本兼容性难控等实际痛点。资源共6个文件包含3个核心Shell脚本用于集群构建、镜像导入与卸载、1个定制化redis.conf配置模板、1个Docker镜像离线包tar格式及1份结构清晰的README说明文档总大小22.46MB开箱即用无需联网拉取镜像。已有1055人学习下载实测在标准CentOS 7.6系统上一键执行即可完成6节点Redis Cluster部署涵盖网络配置、容器编排、主从选举与槽位分配全流程。用户可直接复用脚本逻辑适配私有云环境亦可基于conf与build脚本深入理解Redis Cluster通信机制与Docker化运维最佳实践。1. Docker 一键部署 Redis 集群CentOS 7.x 上最易翻车的“三分钟上线”陷阱你是不是也试过在 CentOS 7.x 上跑docker run -d --name redis-node1 redis:7-alpine然后兴冲冲地redis-cli -h 192.168.56.101 -p 7001 cluster info结果只看到CLUSTERDOWN Hash slot not served别急——这不是你手残而是 Redis 集群压根没“活”起来。Docker 官方镜像不带集群初始化逻辑redis-server --cluster create又得手动凑 6 个节点 IP端口--cluster-replicas 1稍一漏写或网络模式选错bridge vs host整个集群就卡在connecting状态日志里全是Node is not ready。这套脚本专治这种“看似一键、实则玄学”的部署场景它不是简单拉镜像起容器而是完整覆盖网络桥接配置、节点发现机制、集群握手流程、主从关系固化、健康状态自检六大环节适用于所有标准 CentOS 7.4–7.9内核 ≥3.10.0-957环境。如果你正被运维同事催着“今晚必须把缓存集群跑通”或者刚在测试机上删了三次docker network prune那这篇就是你的后悔药。2. 环境准备与依赖校验CentOS 7.x 的 Docker 版本玄学Redis 集群对 Docker 网络栈和内核参数极其敏感。CentOS 7 自带的docker-1.13.1RHEL 仓库版存在--networkhost下容器间 UDP 广播失效、docker exec时redis-cli无法解析redis-node1域名等黑匣子问题。必须升级到 Docker CE 20.10.x 或更高版本且需确认内核模块加载状态。2.1 卸载旧版 Docker 并安装 CE 20.10.24推荐稳定版提示不要用yum install dockerCentOS 7 默认源的 docker 是阉割版不支持--cgroup-parent和--init会导致 Redis 进程在 OOM 时无法优雅退出。# 彻底清除旧版含残留配置 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker # 安装必要依赖 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加 Docker CE 官方源使用阿里云镜像加速下载 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 安装指定版本避免自动升级到 24.x 引发 cgroup v2 兼容问题 sudo yum install -y docker-ce-20.10.24 docker-ce-cli-20.10.24 containerd.io # 启动并设为开机自启 sudo systemctl start docker sudo systemctl enable docker执行后验证版本与运行状态docker --version # 必须输出 Docker version 20.10.24, build ... systemctl is-active docker # 应返回 active若docker --version报错command not found检查/usr/bin/docker是否存在若存在但不可执行执行sudo chmod x /usr/bin/docker。2.2 内核参数加固绕过 CentOS 7 默认限制Redis 集群节点间通过 TCP UDP 通信且大量使用epoll和mmap。CentOS 7 默认vm.overcommit_memory0会导致 Redis fork 子进程失败Cant save in background: fork: Cannot allocate memorynet.core.somaxconn128则引发连接队列溢出Connection refused。需永久生效# 写入 sysctl 配置 echo vm.overcommit_memory 1 | sudo tee -a /etc/sysctl.conf echo net.core.somaxconn 65535 | sudo tee -a /etc/sysctl.conf echo net.ipv4.tcp_max_syn_backlog 65535 | sudo tee -a /etc/sysctl.conf echo net.ipv4.ip_local_port_range 1024 65535 | sudo tee -a /etc/sysctl.conf # 立即生效 sudo sysctl -p # 验证是否生效 sysctl vm.overcommit_memory # 输出应为 1 sysctl net.core.somaxconn # 输出应为 65535注意vm.overcommit_memory1表示“允许分配超过物理内存的虚拟内存”这是 Redisfork()的刚需非安全风险——Redis 本身有maxmemory限流不会真爆内存。2.3 创建专用 Docker 网络解决跨容器 DNS 解析失效CentOS 7 的docker0网桥默认使用172.17.0.0/16但 Redis 集群要求所有节点能通过容器名互相访问如redis-node1:7001。必须创建自定义桥接网络并显式指定子网避免与宿主机网段冲突# 创建名为 redis-cluster-net 的桥接网络子网 172.20.0.0/16避开常见局域网 192.168.x.x 和 10.x.x.x sudo docker network create --driver bridge \ --subnet172.20.0.0/16 \ --gateway172.20.0.1 \ redis-cluster-net # 验证网络创建成功 docker network inspect redis-cluster-net | grep -E (Subnet|Gateway) # 输出应包含 Subnet: 172.20.0.0/16 和 Gateway: 172.20.0.1若报错Error response from daemon: network with name redis-cluster-net already exists说明已存在可跳过若提示no such network检查 Docker daemon 是否运行中systemctl status docker。3. 脚本结构解析与核心参数说明为什么是 6 节点而非 3 节点该 Shell 脚本并非简单循环docker run其设计遵循 Redis 官方集群最小拓扑规范3 主 3 从每个主节点配 1 个从节点。少于 3 主节点无法容忍单点故障cluster-require-full-coverage no也无法挽救而 6 节点能保证任意 1 主 1 从宕机后集群仍可写入。脚本将节点分为两类master端口 7001–7003和slave端口 7004–7006并通过--cluster-replicas 1参数强制绑定主从关系。3.1 脚本主体结构精简版含关键注释#!/bin/bash # redis-cluster-deploy.sh —— CentOS 7.x 专用版 # 作者某运维工程师血泪经验整理 # 可配置参数区务必按需修改 REDIS_VERSION7.2.4 # 必须与 Docker Hub 官方镜像 tag 一致 CLUSTER_NETWORKredis-cluster-net # 必须与 2.3 节创建的网络名完全相同 NODES(7001 7002 7003 7004 7005 7006) # 6 个端口前3主后3从 MASTER_NODES(7001 7002 7003) # 主节点端口列表 SLAVE_NODES(7004 7005 7006) # 从节点端口列表 # 不建议修改的常量 REDIS_IMAGEredis:${REDIS_VERSION}-alpine # 使用 alpine 减小镜像体积 CONFIG_DIR/opt/redis-cluster # 宿主机配置文件存放路径 # 步骤1创建宿主机目录结构 mkdir -p $CONFIG_DIR/{7001,7002,7003,7004,7005,7006} for port in ${NODES[]}; do cat $CONFIG_DIR/$port/redis.conf EOF port $port cluster-enabled yes cluster-config-file nodes-$port.conf cluster-node-timeout 5000 appendonly yes protected-mode no bind 0.0.0.0 daemonize no pidfile /var/run/redis-$port.pid dir /data logfile /var/log/redis-$port.log EOF done # 步骤2启动全部6个容器关键--network 指向自定义网络 for port in ${NODES[]}; do docker run -d \ --name redis-node$port \ --network $CLUSTER_NETWORK \ --ip 172.20.0.$((10#$port 10)) \ # 为每个节点分配固定 IP7001→172.20.0.20, 7002→172.20.0.21... -v $CONFIG_DIR/$port:/usr/local/etc/redis \ -v $CONFIG_DIR/$port:/data \ -p $port:$port \ -p $((10#$port 10000)):$((10#$port 10000)) \ # 预留集群总线端口如 7001→17001 --restartalways \ --ulimit nofile10032:10032 \ $REDIS_IMAGE \ redis-server /usr/local/etc/redis/redis.conf done参数说明--ip 172.20.0.$((10#$port 10))为每个容器分配固定 IP避免 DNS 解析不稳定。10#$port是 Bash 数值计算语法防止八进制误解析7001 → 172.20.0.20。-p $port:$port映射客户端端口如 7001。-p $((10#$port 10000)):$((10#$port 10000))映射集群总线端口如 7001 的总线端口是 17001Redis 集群节点间通过此端口交换心跳和槽位信息。--ulimit nofile10032:10032提升文件描述符上限防止高并发下Too many open files错误。3.2 集群初始化命令为什么必须用redis-cli --cluster create而非redis-trib.rbRedis 5.0 已废弃redis-trib.rb官方推荐redis-cli --cluster。脚本中初始化部分如下接上文# 步骤3等待所有容器就绪每秒检查一次最多 60 秒 for i in $(seq 1 60); do if [ $(docker ps --filter nameredis-node --format {{.Status}} | grep -c Up) -eq 6 ]; then echo ✅ 所有6个 Redis 容器已启动 break fi sleep 1 done # 步骤4执行集群创建关键必须用 --cluster-replicas 1 且按主-从顺序排列 # 格式redis-cli --cluster create ip1:port1 ip2:port2 ... ip6:port6 --cluster-replicas 1 IP_LIST() for port in ${NODES[]}; do # 获取容器在 redis-cluster-net 中的 IP ip$(docker inspect -f {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} redis-node$port) IP_LIST($ip:$port) done # 拼接 IP:PORT 字符串注意前3个必须是主节点后3个是从节点 MASTER_IP_PORT(${IP_LIST[]:0:3}) # 取前3个 SLAVE_IP_PORT(${IP_LIST[]:3:3}) # 取后3个 ALL_IP_PORT(${MASTER_IP_PORT[]} ${SLAVE_IP_PORT[]}) # 执行创建--cluster-yes 跳过交互确认 docker run --rm -it \ --network $CLUSTER_NETWORK \ $REDIS_IMAGE \ redis-cli --cluster create ${ALL_IP_PORT[]} --cluster-replicas 1 --cluster-yes # 步骤5验证集群状态 echo 正在检查集群健康状态... docker exec redis-node7001 redis-cli cluster info | grep cluster_state: # 应输出 cluster_state:ok关键逻辑--cluster-replicas 1表示“每 1 个主节点配 1 个从节点”redis-cli会自动将后 3 个节点7004–7006设为前 3 个7001–7003的从节点。若顺序错乱如把 7004 放在 7001 前集群会创建失败并报Invalid configuration for cluster creation。4. 常见问题排查CentOS 7.x 上最痛的 5 个翻车现场部署失败往往不是脚本问题而是 CentOS 7.x 独有的环境陷阱。以下是真实踩坑记录按发生频率排序4.1 现象redis-cli --cluster create报错No route to host或Connection refused原因Docker 容器间网络不通。CentOS 7 默认firewalld开启且docker0网桥未被加入trusted区域导致172.20.0.0/16流量被拦截。解决# 将自定义网络子网加入 firewalld trusted 区域 sudo firewall-cmd --permanent --zonetrusted --add-source172.20.0.0/16 sudo firewall-cmd --reload # 验证firewall-cmd --zonetrusted --list-sources 应包含 172.20.0.0/164.2 现象docker exec redis-node7001 redis-cli cluster nodes显示所有节点fail状态ping容器 IP 通但telnet 172.20.0.20 7001拒绝连接原因Redis 配置中bind 0.0.0.0被注释或写成bind 127.0.0.1导致仅监听本地回环。解决检查$CONFIG_DIR/7001/redis.conf确保bind行为bind 0.0.0.0无注释且protected-mode no已启用。修改后重启容器docker restart redis-node70014.3 现象集群创建成功但redis-cli -h 172.20.0.20 -p 7001 cluster info返回cluster_known_nodes:6但cluster_size:0原因cluster-config-file路径在容器内为/data/nodes-7001.conf但redis.conf中dir /data未生效导致节点元数据未持久化重启后丢失。解决确认docker run命令中-v $CONFIG_DIR/$port:/data已正确挂载且$CONFIG_DIR/7001/目录权限为755属主为rootRedis 容器以 root 运行。执行ls -l $CONFIG_DIR/7001/ # 应看到 nodes-7001.conf 文件4.4 现象docker logs redis-node7001持续输出Unable to accept client connection: Connection reset by peer原因宿主机 SELinux 启用阻止容器写入挂载卷。CentOS 7 默认enforcing模式。解决临时关闭验证用sudo setenforce 0 # 若恢复正常则永久关闭 SELinux生产环境需评估 sudo sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config sudo reboot4.5 现象集群运行 2 小时后redis-cli cluster nodes中某个节点状态变为fail但docker ps显示容器仍在运行原因Redis 进程因内存不足被 OOM Killer 杀死但容器未退出--init缺失导致僵尸进程。解决在docker run命令中添加--init参数需 Docker 1.13并在redis.conf中设置oom-score-adj -500# 修改脚本中的 docker run 命令增加 --init docker run -d --init ... $REDIS_IMAGE redis-server ... # 并在 redis.conf 中追加 echo oom-score-adj -500 $CONFIG_DIR/$port/redis.conf5. 部署后验证与日常巡检用 3 条命令守住集群生命线装完不是终点而是运维的起点。我见过太多集群“部署成功”后因未做基础验证在业务高峰时突然cluster_state:fail最后发现是某个从节点的replication-offset停滞了 2 小时。以下是我每次部署后必跑的三板斧100% 覆盖 Redis 集群健康核心指标。5.1 第一关集群拓扑与槽位分配cluster nodescluster slots进入任一节点容器执行docker exec -it redis-node7001 redis-cli 127.0.0.1:7001 cluster nodes预期输出特征共 6 行每行以id开头后跟ip:port、master或slave标识、connected状态主节点行末尾有master -从节点行末尾有slave master-id如slave f5e...所有节点状态均为connected非disconnected或fail。再执行127.0.0.1:7001 cluster slots预期输出返回一个数组共 16384 个槽位0–16383被均匀分配给 3 个主节点。例如1) 1) (integer) 0 # 槽位起始 2) (integer) 5460 # 槽位结束 3) 1) 172.20.0.20 # 主节点 IP 2) (integer) 7001 # 主节点端口 3) f5e... # 主节点 ID 4) 1) 172.20.0.23 # 对应从节点 IP 2) (integer) 7004 # 从节点端口 3) a1b... # 从节点 ID提示若cluster slots返回空数组或报错CLUSTERDOWN Hash slot not served说明槽位未分配需重新执行redis-cli --cluster create。5.2 第二关主从同步状态info replication对每个主节点执行info replication重点检查三项字段正常值异常表现含义rolemasterslave确认是主节点connected_slaves10必须有且仅有 1 个从节点连接slave0行的stateonlineconnecting,offline,delayxxx从节点同步状态# 批量检查所有主节点 for port in 7001 7002 7003; do echo redis-node$port (master) replication status docker exec redis-node$port redis-cli info replication | grep -E role|connected_slaves|state done典型异常slave0:ip172.20.0.23,port7004,stateconnecting,offset0,lag0→ 原因从节点网络不通或主节点未开启replica-announce-ip脚本已默认配置无需额外操作。5.3 第三关读写连通性与故障转移模拟set/getkill -SIGTERM这是最硬核的验证——不光看状态还要动手“捅”它# 步骤1写入测试 key自动路由到对应槽位 docker exec redis-node7001 redis-cli -c set test:key:$(date %s) value-$(hostname) # 步骤2从任意节点读取-c 参数启用集群模式自动重定向 docker exec redis-node7004 redis-cli -c get test:key:$(date %s) # 步骤3模拟主节点宕机杀掉 redis-node7001 进程 docker kill -s SIGTERM redis-node7001 # 步骤4等待 30 秒检查集群是否自动选举新主 sleep 30 docker exec redis-node7004 redis-cli cluster nodes | grep 7001\|7002\|7003 | grep master # 应看到原 7002 或 7003 节点变成两个 master因 7001 宕机其从节点 7004 升主从那以后我每次部署完 Redis 集群都强制走一遍这三步先看cluster nodes确认拓扑再查info replication确保主从握手成功最后kill -SIGTERM一个主节点看故障转移是否秒级完成。这三步下来心里才真正踏实——毕竟线上系统不接受“理论上应该可以”。希望帮到你。本文还有配套的精品资源点击获取