简介:面向需要在 CentOS 7.x 环境下快速搭建 Redis 集群的运维与开发人员,这份资源提供了一套基于 Docker 的一键部署方案,通过 shell 脚本把镜像导入、容器编排与配置生成等环节串联起来,减少手工逐台配置的重复劳动,适合具备一定 Linux 基础、希望快速验证集群可用性的读者。压缩包共 6 个文件,约 22.46MB,以 sh 脚本为主体,配合 tar 镜像包、conf 配置文件和 md 说明文档,分别承担自动化部署、离线镜像分发、参数配置与使用指引等职责,按说明传入参数即可自动执行部署流程。目前已有 1055 人学习下载,脚本经过实际环境验证,可帮助读者省去镜像拉取与节点编排的摸索成本,并借助卸载脚本与说明文档完成环境清理和参数调整,适合作为学习 Docker 化 Redis 集群部署的参考实践。
1. 一条脚本起六节点:CentOS 7.x 上用 Docker 部署 Redis 集群的安装现场
上周帮同事恢复一套测试环境,机器是 CentOS 7.9,磁盘上还留着上次装到一半的 Redis 集群残骸:六个容器起了三个,redis-cli --cluster create卡在Waiting for the cluster to join,日志里全是Cluster config file exists。这种半死不活的状态比全新安装更难受,因为端口占用、配置文件、数据目录三样东西互相纠缠,清理比重装还费时间。Redis 集群本身不算复杂,难的是在 CentOS 7.x 这种老底子上把 Docker、网络、端口、集群总线一次配对,任何一环没对齐,cluster_state就永远是fail。这篇记录的是我用 shell 脚本一键拉起三主三从 Redis 集群的完整过程,适合手上只有一台 CentOS 7.x 测试机、想快速得到一套可验证集群的开发者,也适合已经装过单机 Redis、第一次碰集群模式、被CLUSTERDOWN折腾过的人。脚本不是黑匣子,下面会把每个参数为什么这么写讲清楚,装坏了也有回退路径。
2. 装前把环境钉死:CentOS 7.x 与 Docker 的版本取舍
2.1 系统底子与 Docker 版本怎么选
CentOS 7.x 的生命周期已经走到尾声,但大量内网测试机还在跑,所以第一件事不是敲安装命令,而是确认内核和 Docker 版本能对上。Redis 集群依赖容器间的 TCP 通信和固定的集群总线端口,Docker 版本太老会出现端口映射不稳定的情况。我一般要求内核不低于 3.10.0-1127,Docker 用 20.10 系列,这个组合在 CentOS 7.9 上验证过多次,docker network和--net host的行为都可预期。
# 确认系统版本与内核,低于 3.10.0-1127 建议先 yum update cat /etc/centos-release uname -r # 查看是否已有 docker,避免和旧版本冲突 docker version 2>/dev/null || echo "docker not installed" rpm -qa | grep -i docker第一段命令看的是系统身份,/etc/centos-release输出CentOS Linux release 7.9.2009 (Core)这类信息才算对路。第二段是排雷,很多机器上残留着docker-ce旧包或者podman的兼容层,直接装新版本会出现二进制路径打架。如果rpm -qa里有docker-common、docker-client这类老包,先卸干净再往下走,这一步省不得。
版本选择上有个取舍:Docker 20.10 之后的版本对iptables后端有调整,CentOS 7.x 默认的firewalld和它配合时偶尔会吞掉容器端口。我的做法是安装时明确指定--setopt=obsoletes=0,并且装完立刻把firewalld停掉换成iptables管理,测试环境这样最省心。生产环境要保留防火墙的话,得手动放行 6379 和 16379 两个端口段,后面避坑章节会细说。
2.2 安装 Docker 与基础依赖
CentOS 7.x 的默认源里没有docker-ce,需要先加官方仓库。这一步网络不通是常态,所以脚本里我会把仓库地址写成可替换变量,方便换成内网镜像源。
# 安装基础工具,yum-utils 提供 yum-config-manager yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加 docker-ce 仓库,地址可按内网情况替换 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装指定版本,20.10.24 在 7.x 上比较稳 yum install -y docker-ce-20.10.24 docker-ce-cli-20.10.24 containerd.io # 启动并设开机自启 systemctl enable docker && systemctl start dockerdevice-mapper-persistent-data和lvm2是存储驱动的前置依赖,缺了它们 Docker 启动时会报devicemapper相关错误。yum-config-manager --add-repo写入的是仓库描述文件,如果公司内网有镜像站,把 URL 换掉即可,后面的包名不变。指定20.10.24而不是latest,是为了让脚本在别的机器上复现时行为一致,latest哪天跳到 24.x,iptables规则和 cgroup 驱动都可能变,集群端口映射就容易出玄学问题。
装完用docker info看两处:Cgroup Driver应该是systemd,Storage Driver在 CentOS 7.x 上通常是overlay2。如果显示devicemapper,说明内核或存储配置没跟上,得在/etc/docker/daemon.json里显式指定,否则后面容器写数据会慢得离谱。
2.3 目录规划与脚本参数约定
一键脚本要能重复执行,前提是目录和端口有固定约定。我习惯把集群根目录放在/opt/redis-cluster,下面按节点编号分7001到7006六个子目录,每个目录里放redis.conf和data。端口规划是三主三从交叉分布:7001、7002、7003 为主,7004、7005、7006 为从,集群总线端口统一用「服务端口 + 10000」,也就是 17001 到 17006。
# 脚本头部变量,改这里就能适配不同机器 CLUSTER_DIR=/opt/redis-cluster BASE_PORT=7001 NODE_COUNT=6 REDIS_IMAGE=redis:6.2.14 NETWORK_NAME=redis-cluster-netREDIS_IMAGE选6.2.14是权衡后的结果:Redis 7.x 的集群命令有变化,--cluster create的部分输出格式和老脚本对不上;6.2 系列在 CentOS 7.x 的 Docker 上跑得最稳,镜像体积也适中。NETWORK_NAME用自定义 bridge 网络而不是host模式,是为了让六个容器通过容器名互相解析,脚本里就不用写死宿主机 IP,换机器时只改变量不改逻辑。这些约定写进脚本开头,后面所有循环都引用它们,改端口只改一个地方。
3. 写一键脚本:从生成配置到拉起六个容器
3.1 用循环生成六份 redis.conf
集群模式下的redis.conf和单机版差别不小,cluster-enabled yes、cluster-config-file、cluster-node-timeout三个是必填项,少一个容器起来就退。脚本里用循环按节点编号生成配置,端口和目录都从变量推导,避免手写六遍出错。
for i in $(seq 0 $((NODE_COUNT-1))); do PORT=$((BASE_PORT+i)) NODE_DIR="${CLUSTER_DIR}/${PORT}" mkdir -p "${NODE_DIR}/data" cat > "${NODE_DIR}/redis.conf" <<EOF port ${PORT} bind 0.0.0.0 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes dir /data EOF doneport和目录由BASE_PORT加偏移算出,六个节点一次成型。bind 0.0.0.0配合protected-mode no是容器内访问的必要条件,否则集群总线握手会被拒。cluster-config-file nodes.conf是每个节点自己的集群状态文件,必须落在持久化目录里,容器重启后才能恢复节点身份。cluster-node-timeout 5000表示 5 秒内主节点失联就触发故障转移,测试环境这个值够用,调太小会误判,调太大故障转移慢。appendonly yes打开 AOF,集群模式下数据安全性比纯 RDB 好一些,代价是磁盘写入多一点。
配置生成后建议抽查一份,确认端口和目录对得上。脚本里可以加一句grep -H "^port" ${CLUSTER_DIR}/*/redis.conf,输出六行端口号,肉眼扫一遍比事后排查省事。
3.2 创建网络并启动容器
六个容器要能互相通信,先建一个自定义 bridge 网络。启动时把配置目录和数据目录都挂进去,容器内路径固定为/usr/local/etc/redis/redis.conf和/data,这样镜像不用改,配置全在宿主机上。
# 创建专用网络,已存在则忽略报错 docker network create ${NETWORK_NAME} 2>/dev/null || true for i in $(seq 0 $((NODE_COUNT-1))); do PORT=$((BASE_PORT+i)) NODE_DIR="${CLUSTER_DIR}/${PORT}" docker run -d \ --name "redis-${PORT}" \ --network ${NETWORK_NAME} \ -p ${PORT}:${PORT} \ -p $((PORT+10000)):$((PORT+10000)) \ -v "${NODE_DIR}/redis.conf:/usr/local/etc/redis/redis.conf" \ -v "${NODE_DIR}/data:/data" \ ${REDIS_IMAGE} \ redis-server /usr/local/etc/redis/redis.conf done--network让六个容器处于同一网段,容器名即主机名,后面组集群时可以直接用redis-7001:7001这种地址。两个-p分别映射服务端口和集群总线端口,后者是集群节点交换 gossip 消息用的,漏掉它cluster meet会一直超时。两个-v把配置和数据都落到宿主机,容器删了数据还在,这是能反复折腾的前提。启动命令末尾显式指定配置文件路径,覆盖镜像默认的启动参数。
启动后别急着组集群,先确认六个容器都处于Up状态,并且日志里没有FATAL。docker ps --filter "name=redis-"看状态,docker logs redis-7001看启动日志,正常会输出Ready to accept connections。有一个容器反复重启,多半是配置文件路径或权限问题,先解决再往下。
3.3 用 redis-cli 组集群并分配槽位
六个节点都活着之后,进任意一个容器执行--cluster create,Redis 会自动把 16384 个槽位平均分给三个主节点,并把另外三个设为从。这一步的关键是--cluster-replicas 1,它告诉工具每个主节点配一个从。
docker exec -it redis-7001 redis-cli --cluster create \ redis-7001:7001 redis-7002:7002 redis-7003:7003 \ redis-7004:7004 redis-7005:7005 redis-7006:7006 \ --cluster-replicas 1 --cluster-yes地址列表前三个会被优先选为主节点,后三个作为从节点候选,--cluster-replicas 1保证一主一从的配比。--cluster-yes跳过交互确认,适合脚本化执行,手工执行时去掉它可以看到槽位分配预览。命令输出里会打印>>> Performing hash slots allocation on 6 nodes...,接着是每个节点的槽位区间,最后出现[OK] All 16384 slots covered才算成功。
如果卡在Waiting for the cluster to join,先别重复执行,去看容器日志里的总线端口有没有报连接拒绝。常见原因是宿主机防火墙拦了 17001 到 17006,或者容器网络里节点名解析不到。组集群失败后残留的nodes.conf会让下次执行报Node ... is not empty,清理方法是停容器、删各节点data目录下的nodes.conf、再重启,这个顺序不能反。
4. 避坑与排查:五个让集群起不来的真实原因
4.1 现象:容器全 Up,cluster_state 却是 fail
原因通常是集群总线端口没通。docker ps里只看到 7001 到 7006 的映射,17001 到 17006 被漏掉,节点之间 gossip 握手失败,槽位分配完了但状态同步不上。解决是把总线端口补进docker run的-p参数,重建容器后重新组集群。验证方法是docker exec redis-7001 redis-cli -p 7001 cluster info,看cluster_state:ok和cluster_known_nodes:6两个值。
4.2 现象:组集群时报 Node is not empty
这是重复执行留下的后遗症。上一次--cluster create中途失败,各节点的nodes.conf里已经写了半套集群视图,再次执行时工具发现节点非空就拒绝。解决分三步:docker stop六个容器,删除每个节点data目录下的nodes.conf和appendonly.aof,再docker start重启,最后重新执行组集群命令。顺序反了会读到旧状态,等于白删。
4.3 现象:宿主机能连,别的机器连不上
CentOS 7.x 上firewalld默认开着,Docker 的端口映射规则和它冲突时,外部访问会被静默丢弃。解决是测试环境直接systemctl stop firewalld && systemctl disable firewalld,生产环境则用firewall-cmd --add-port=7001-7006/tcp --permanent和--add-port=17001-17006/tcp --permanent显式放行,再firewall-cmd --reload。放行后从另一台机器用redis-cli -h <宿主机IP> -p 7001 cluster info验证,能返回cluster_state:ok才算通。
4.4 现象:容器启动即退出,日志报 Can't open the cluster config file
配置文件里cluster-config-file写的是相对路径,而dir指向的/data挂载目录权限不对,Redis 进程写不进去。解决是确认宿主机上${NODE_DIR}/data对容器内用户可写,简单做法是chmod 777测试目录,或者chown 999:999对齐 Redis 镜像里的用户 ID。另外cluster-config-file保持nodes.conf这种相对名即可,它会落在dir指定的目录下,不要写成绝对路径。
4.5 现象:主节点挂了,从节点没顶上
先看cluster-node-timeout是不是设得太大,5000 毫秒在测试环境合适,设成 60000 就要等一分钟才触发转移。再看从节点是否真的挂到了主节点上,redis-cli -p 7001 cluster nodes输出里每行末尾的connected状态和master指向要对应。如果从节点显示disconnected,多半是总线端口或网络问题,回到 4.1 排查。故障转移验证可以手动docker stop redis-7001,等几秒再看cluster nodes,原从节点会变成master并接管槽位。
5. 装完怎么验证:三组命令确认集群真的能读写
集群组起来不等于能用,我习惯用三组命令做验收,顺序是从状态到路由再到实际读写。第一组看整体状态,进任意节点执行cluster info,重点盯三个字段:cluster_state必须是ok,cluster_slots_assigned必须是16384,cluster_known_nodes必须是6。任何一个不对,说明槽位或节点注册有问题,别急着写数据。
# 状态验收:三个关键字段 docker exec redis-7001 redis-cli -p 7001 cluster info | grep -E "cluster_state|cluster_slots_assigned|cluster_known_nodes" # 节点拓扑:确认三主三从和槽位区间 docker exec redis-7001 redis-cli -p 7001 cluster nodes第二组看拓扑,cluster nodes每行是一个节点,第一列是节点 ID,第二列是地址,第三列带master或slave,末尾的槽位区间应该覆盖 0 到 16383 且不重叠。三主三从的典型输出里,三个master各带一段槽位,三个slave的地址列后面跟着connected。如果某个从节点的master指向空或者状态不是connected,说明复制链路没建好。
第三组做真实读写,用-c参数让客户端跟随重定向。集群模式下不带-c写一个落在别的槽位的 key 会报MOVED,这是正常行为,不是故障。
# 写入并读取,-c 表示跟随 MOVED 重定向 docker exec redis-7001 redis-cli -c -p 7001 set cluster:test "ok" docker exec redis-7001 redis-cli -c -p 7001 get cluster:test # 查看 key 落在哪个槽位和节点 docker exec redis-7001 redis-cli -c -p 7001 cluster keyslot cluster:testset返回OK、get返回ok,说明路由和读写都通。cluster keyslot会给出一个 0 到 16383 的数字,对照cluster nodes的槽位区间就能知道这个 key 归哪个主节点管。想再稳一点,可以连续写十个不同前缀的 key,再逐个读回,确认跨节点重定向没有丢数据。
验收通过后,把这套脚本和目录结构留一份在/opt/redis-cluster旁边,下次换机器直接改BASE_PORT和REDIS_IMAGE两个变量就能复用。我踩过最冤的一次是组集群前没清nodes.conf,反复执行了四遍,每遍都以为网络有问题,最后发现是旧状态在作祟。从那以后我每次重装集群都强制先跑一遍清理:停容器、删nodes.conf、再启动,三步走完才碰--cluster create。希望帮到你。
本文还有配套的精品资源,点击获取