
简介面向 CentOS 7.x 环境下需要快速搭建 Redis 集群的运维与开发人员这份资源提供了一套基于 Docker 的一键部署方案通过 shell 脚本把镜像导入、容器编排与集群初始化串联起来省去手工逐节点配置的繁琐过程。压缩包共 6 个文件以 sh 脚本为主体辅以 tar 镜像包、conf 配置文件和 md 说明文档整体约 22.46MB脚本、镜像与配置各司其职便于按说明传参后自动执行部署流程。目前已有 1055 人学习下载说明该方案在实际环境中具备一定参考价值。读者可从中获得可直接复用的自动化部署脚本、预置的 Redis 镜像与配置模板以及卸载脚本和说明文档既能快速拉起集群验证效果也便于在此基础上调整节点数量与参数降低搭建与调试成本。1. 用一份 shell 脚本把 Redis 集群塞进 DockerCentOS 7 上的落地路径在 CentOS 7 上手工搭一套 Redis 集群最耗时间的从来不是redis-cli --cluster create那一行而是前面那堆准备工作六份配置文件、六个数据目录、端口规划、容器网络、节点握手、槽位分配任何一步手抖都要推倒重来。这份资源给的是一个 shell 脚本用 Docker 在单机上把 Redis 集群一键拉起来目标环境明确锁定 CentOS 7.x适合两类人一类是要在测试环境快速验证集群行为、做故障演练的后端同学另一类是想把「集群部署」这件事从手工操作变成可重复执行流程的运维同学。它不解决生产级高可用但能把「从零到能连上集群」的路径压缩到几分钟这个价值在联调和教学场景里很实在。2. 先想清楚为什么用 Docker 跑 Redis 集群而不是直接装六份2.1 单机多实例的隔离账直接在宿主机上装六个 Redis 实例最直接的麻烦是文件系统污染。六个redis.conf、六个dump.rdb、六个nodes.conf散落在不同目录端口从 7000 排到 7005卸载时得一个个找。Docker 把每个实例的配置、数据、日志都收进容器自己的可写层或挂载卷里删容器就是删实例宿主机上不留残渣。更关键的是网络。Redis 集群节点之间要互相通信cluster meet之后每个节点会把自己的 IP 和端口广播给其他节点。宿主机多实例方案里这个 IP 就是宿主机 IP端口各不相同配置里写死bind和cluster-announce-ip容易出错。Docker 方案里常见做法是给所有节点挂同一个自定义 bridge 网络容器之间用容器名解析cluster-announce-ip直接填容器在 bridge 网络里的地址节点握手时不会因为地址不一致而卡在CLUSTERDOWN。代价也要说清楚单机 Docker 跑六节点本质是六个进程抢同一块 CPU 和内存集群的「高可用」只是逻辑上的宿主机一挂全挂。所以这套东西的定位是测试、联调、教学不是生产。想清楚这一点后面所有参数取舍才有依据。2.2 三主三从的最小拓扑Redis 集群要求至少三个主节点才能分配 16384 个槽位从节点数量不强制但为了验证主从切换标准做法是三主三从。脚本里通常用循环生成六个实例端口按 7000 到 7005 递增前三个是主、后三个是从或者由--cluster create时用--cluster-replicas 1让工具自动配对。这里有个容易被忽略的点--cluster-replicas 1的含义是「每个主节点配一个从节点」工具会按你给的节点顺序自动分配主从关系但分配结果不一定是你预期的配对。如果要做定向的主从绑定比如 7003 固定做 7000 的从就不能靠这个参数得先create出三个主再手动cluster meet加从节点并cluster replicate。脚本如果只做一键拉起一般用--cluster-replicas 1图省事但你要知道它背后的配对是工具决定的。2.3 集群模式的配置硬约束Redis 开集群模式不是加一行cluster-enabled yes就完事有几个参数必须同时到位否则集群起不来或者行为诡异配置项必须值作用cluster-enabledyes开启集群模式cluster-config-filenodes.conf节点拓扑持久化文件不能手工改cluster-node-timeout15000 左右节点失联判定阈值太小误判、太大切换慢appendonlyyes 或 no 均可集群模式不强制但建议开protected-modeno容器网络内需要跨容器访问bind0.0.0.0容器内监听所有地址cluster-node-timeout这个值在单机 Docker 场景下值得单独说。默认 15000 毫秒意味着一个节点失联 15 秒后才被标记为疑似下线。测试环境里如果你手动docker stop一个主节点要等十几秒才能看到从节点升主很多人以为脚本坏了其实是这个参数在起作用。想加快演练节奏可以调到 5000但别调太小单机负载抖动时容易误判导致频繁切换。3. 脚本拆开看目录规划、配置生成与容器拉起3.1 目录结构与变量约定一份能复用的脚本开头一定是变量区。常见做法是把端口基址、节点数、镜像版本、网络名、数据根目录都提出来后面所有路径都基于这些变量拼改一处就能整体调整。#!/bin/bash # redis-cluster-deploy.sh # 适用CentOS 7.x Docker 已安装 set -e BASE_PORT7000 # 起始端口 NODE_COUNT6 # 节点总数三主三从 IMAGEredis:6.2 # 镜像版本按需替换 NET_NAMEredis-cluster-net DATA_ROOT/opt/redis-cluster PASSWORDYourStrongPass123 # 集群密码留空则不设set -e是血泪经验脚本里任何一条命令失败就整体退出避免半拉子状态。没有它的话某个容器启动失败后脚本继续往下跑最后cluster create报一堆看不懂的错排查成本翻倍。DATA_ROOT选在/opt下是习惯实际部署时确认这个分区有足够空间。六个节点每个appendonly开着的话写入量大的测试会吃掉不少磁盘别放在根分区快满的机器上。3.2 生成每个节点的 redis.conf配置生成是脚本的核心。六个节点配置大同小异只有端口和节点自身地址不同用循环生成最省事。mkdir -p ${DATA_ROOT} for i in $(seq 0 $((NODE_COUNT-1))); do PORT$((BASE_PORTi)) NODE_DIR${DATA_ROOT}/${PORT} mkdir -p ${NODE_DIR}/data cat ${NODE_DIR}/redis.conf EOF port ${PORT} cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 appendonly yes dir /data protected-mode no bind 0.0.0.0 masterauth ${PASSWORD} requirepass ${PASSWORD} EOF done逐项说明dir /data对应容器内挂载点宿主机目录通过-v映射进去这样配置里写的是容器内路径和宿主机路径解耦。masterauth和requirepass设成同一个值集群内主从复制和客户端访问都用这个密码省得两套密码搞混。如果PASSWORD留空这两行会变成masterauth和requirepassRedis 会报配置错误所以脚本里要么强制要求填密码要么用条件判断跳过这两行——这是很多人抄脚本后第一次翻车的地方。cluster-config-file nodes.conf写的是相对路径实际落在dir指定的目录下也就是/data/nodes.conf。这个文件由 Redis 自己维护记录集群拓扑绝对不能手工编辑删了它等于让节点失忆重新加入集群时会被当成新节点。3.3 创建网络并拉起容器docker network create ${NET_NAME} 2/dev/null || true for i in $(seq 0 $((NODE_COUNT-1))); do PORT$((BASE_PORTi)) NODE_DIR${DATA_ROOT}/${PORT} docker run -d \ --name redis-${PORT} \ --network ${NET_NAME} \ -p ${PORT}:${PORT} \ -p $((PORT10000)):$((PORT10000)) \ -v ${NODE_DIR}/redis.conf:/usr/local/etc/redis/redis.conf \ -v ${NODE_DIR}/data:/data \ redis:6.2 redis-server /usr/local/etc/redis/redis.conf done端口映射这里有个必须讲清楚的点Redis 集群除了服务端口还需要一个「集群总线端口」固定是服务端口加 10000。7000 对应 170007001 对应 17001以此类推。只映射服务端口不映射总线端口节点之间cluster meet会一直卡在握手阶段cluster nodes里看到的全是handshake状态。这是单机 Docker 跑集群最高频的坑没有之一。--network ${NET_NAME}让所有容器在同一个自定义 bridge 网络里容器名可以直接当主机名解析。但注意cluster-announce-ip如果没显式设置Redis 会用容器自己的 IP 广播这个 IP 在 bridge 网络里是通的所以集群内部通信没问题但宿主机上的客户端通过-p映射的端口连进来时集群返回的重定向地址是容器 IP宿主机不一定能路由到。解决办法有两个要么客户端也在同一个 Docker 网络里跑要么在配置里加cluster-announce-ip填宿主机 IP 并配合cluster-announce-port。脚本如果只做「集群能起来」这个目标通常不处理这个但你要连的时候得知道为什么MOVED重定向会失败。3.4 等节点就绪再建集群容器docker run -d返回不代表 Redis 已经能接受连接。直接跑cluster create大概率报Connection refused或者Node is not empty。稳妥做法是轮询PING。for i in $(seq 0 $((NODE_COUNT-1))); do PORT$((BASE_PORTi)) until docker exec redis-${PORT} redis-cli -p ${PORT} -a ${PASSWORD} ping 2/dev/null | grep -q PONG; do sleep 1 done doneuntil循环每秒探一次直到返回PONG。2/dev/null把密码错误警告之类的噪音吞掉grep -q PONG只认成功响应。这一步不加脚本在慢机器上十次有三次失败加了之后基本稳。3.5 执行 cluster createNODES for i in $(seq 0 $((NODE_COUNT-1))); do PORT$((BASE_PORTi)) NODES${NODES} redis-${PORT}:${PORT} done docker exec redis-${BASE_PORT} redis-cli -a ${PASSWORD} --cluster create ${NODES} --cluster-replicas 1 --cluster-yes--cluster-yes跳过交互确认适合脚本自动化。--cluster-replicas 1让工具自动分配三主三从。NODES拼出来是redis-7000:7000 redis-7001:7001 ...用的是容器名因为cluster create是在容器内执行的容器名在 bridge 网络里可解析。执行完输出里会看到槽位分配结果[OK] All 16384 slots covered是成功标志。如果看到Not all 16384 slots are covered说明有主节点没分到槽通常是节点数不够或者某个节点状态异常用cluster nodes逐个查。4. 验证与排错集群起来之后怎么确认它真的能用4.1 三条命令确认集群健康# 看集群拓扑确认三主三从、槽位全覆盖 docker exec redis-7000 redis-cli -a YourStrongPass123 cluster nodes # 看集群整体状态ok 才算健康 docker exec redis-7000 redis-cli -a YourStrongPass123 cluster info # 写入一个 key验证槽位路由正常 docker exec redis-7000 redis-cli -a YourStrongPass123 -c set foo barcluster nodes输出里每个节点一行第一列是节点 ID后面跟地址、角色master/slave、槽位范围。重点看两件事主节点后面有没有fail标记从节点有没有正确slave到对应主节点。cluster info里cluster_state:ok是最终判据如果是fail往下看cluster_slots_assigned是不是 16384。-c参数是客户端跟随重定向不加的话set foo如果落在别的节点上会返回MOVED错误。这个参数在验证阶段必加否则你会误以为集群坏了。4.2 主从切换演练# 停掉一个主节点观察从节点升主 docker stop redis-7000 sleep 20 docker exec redis-7001 redis-cli -a YourStrongPass123 cluster nodes | grep master停掉 7000 后等cluster-node-timeout加一点余量这里给 20 秒再看拓扑原来 7000 的从节点应该已经变成 master。这个演练能验证cluster-node-timeout设置是否合理也能让你对切换耗时有个体感。演练完记得把 7000 拉起来它会以从节点身份重新加入。4.3 常见失败信号对照现象大概率原因排查方向cluster nodes全是 handshake总线端口未映射检查-p PORT10000cluster create报Node is not empty节点里已有旧集群数据清空data目录重来cluster_state:fail槽位未全覆盖cluster info看slots_assigned客户端MOVED重定向失败announce-ip 是容器 IP客户端进同网络或配 announce-ip容器启动即退出配置文件密码行为空检查requirepass行5. 避坑清单这五个地方我踩过你大概率也会踩5.1 总线端口没映射握手永远卡住现象六个容器都起来了PING都通但cluster create之后cluster nodes里节点状态一直是handshake或者只有部分节点互相认识。原因Redis 集群节点间通信走的是服务端口加 10000 的总线端口docker run时只映射了 7000-7005没映射 17000-17005容器之间虽然在同一 bridge 网络里能通但如果脚本用了-p而没配--network的完整互通或者宿主机防火墙拦了高位端口握手就断在这。解决确认docker run里每个节点都有-p $((PORT10000)):$((PORT10000))并且所有节点在同一个自定义网络里。用docker exec redis-7000 redis-cli -p 17000 ping单独测总线端口是否可达。5.2 密码留空导致配置解析失败现象容器docker run后立刻退出docker logs里报Bad directive or wrong number of arguments。原因脚本里requirepass ${PASSWORD}在PASSWORD为空时变成requirepassRedis 解析配置时认为参数缺失直接拒绝启动。解决要么强制要求填密码并在脚本开头做非空校验要么用条件判断密码为空时根本不写这两行。我一般选前者测试环境也设个密码省得后面加密码还要重建集群。5.3 复用旧数据目录节点带着旧拓扑启动现象改了端口规划重新跑脚本cluster create报Node is not empty或者新集群里混进了旧节点 ID。原因DATA_ROOT下旧的nodes.conf和appendonly文件还在新容器挂载进去后 Redis 读到旧拓扑认为自己已经是某个集群的成员。解决脚本开头加清理逻辑或者在重新部署前手动rm -rf ${DATA_ROOT}。生产习惯是每次部署用带时间戳的目录测试环境图省事就直接清空。nodes.conf这东西没有后悔药删了就得重建集群。5.4 cluster-node-timeout 太小单机负载抖动触发误切换现象压测时集群频繁发生主从切换cluster nodes里fail?标记反复出现又消失。原因单机跑六个容器CPU 和内存竞争激烈某个节点偶尔响应慢超过cluster-node-timeout被其他节点判定为疑似下线触发切换。解决测试环境把cluster-node-timeout从默认 15000 适当调大或者给容器加--cpus限制避免互相抢。反过来如果要做快速切换演练调到 5000 但别更低低于 3000 在单机上基本是自找麻烦。5.5 宿主机客户端连不上重定向地址是容器 IP现象宿主机上用redis-cli -h 127.0.0.1 -p 7000 -c能连上但执行set时返回的MOVED地址是172.x.x.x:7001客户端连不过去。原因集群节点广播的是容器在 bridge 网络里的 IP宿主机没有到那个网段的路由。解决三个办法——客户端也跑在同一个 Docker 网络里或者在配置里显式设cluster-announce-ip为宿主机 IP、cluster-announce-port为映射端口或者用--nethost让容器直接用宿主机网络栈CentOS 7 上可行但端口冲突要自己管。脚本默认不处理这个因为处理方式取决于你的使用场景但连不上时先想到这一层。6. 进阶把脚本改成可参数化、可验证的部署工具一键脚本跑通只是起点真正让它变成团队里能反复用的东西得做两件事参数化和自验证。参数化方面把端口基址、节点数、密码、镜像版本都提到脚本开头还不够更好的做法是支持环境变量覆盖这样 CI 里不用改文件就能跑不同配置BASE_PORT${REDIS_BASE_PORT:-7000} NODE_COUNT${REDIS_NODE_COUNT:-6} PASSWORD${REDIS_PASSWORD:?must set REDIS_PASSWORD} IMAGE${REDIS_IMAGE:-redis:6.2}${REDIS_PASSWORD:?must set REDIS_PASSWORD}这个写法在变量为空时直接报错退出比后面配置生成失败再排查省事得多。:-是给默认值:?是强制要求两个配合用关键参数不漏、次要参数有兜底。自验证方面脚本最后加一段健康检查把cluster info的cluster_state和cluster_slots_assigned抓出来判断不 ok 就以非零码退出。这样在自动化流程里部署失败能被上游感知而不是「脚本跑完了但集群是坏的」这种黑匣子状态。STATE$(docker exec redis-${BASE_PORT} redis-cli -a ${PASSWORD} cluster info | grep cluster_state | tr -d \r | cut -d: -f2) SLOTS$(docker exec redis-${BASE_PORT} redis-cli -a ${PASSWORD} cluster info | grep cluster_slots_assigned | tr -d \r | cut -d: -f2) if [ $STATE ! ok ] || [ $SLOTS ! 16384 ]; then echo cluster not healthy: state$STATE slots$SLOTS exit 1 fitr -d \r是处理redis-cli输出里可能带的回车符不加的话字符串比较永远不相等这个细节坑过不少人。cut -d: -f2取冒号后面的值简单粗暴但够用。还有一个值得加的技巧部署完成后自动打印一份连接信息包括每个节点的宿主机映射端口和集群总线端口以及一条带-c的示例连接命令。团队里其他人拿到输出就能直接连不用再问「端口是多少」。这种小细节决定一份脚本是被用一次还是被用一年。从那以后我每次写这类部署脚本都会在最后强制走一遍「停一个节点、看切换、拉起来、再验证」的流程不跑通不算完。集群这东西起来不等于能用能用不等于切换正常三层都过了才敢交给别人。希望这份拆解帮到你少走几个我走过的弯路。本文还有配套的精品资源点击获取