简介这是一套面向 CentOS 7.x 环境的 Docker Redis 集群一键部署脚本包适合需要快速搭建与验证集群的 Linux 运维、开发人员及中级学习者使用可省去手工拉取镜像、编写节点配置、逐台启动与初始化集群等重复操作。压缩包共 6 个文件主要由 shell 脚本、Docker 镜像 tar 包、conf 配置文件和 Markdown 说明文档组成完整包约 22.46MB既包含自动部署入口也保留配置参考与卸载清理材料。按说明将参数传入安装脚本后部署程序会自动执行读者可据此复现 Redis 集群环境理解容器编排、节点配置、脚本参数传递和资源清理流程也方便在测试场景中做二次调整与排错验证。脚本化流程有助于统一部署步骤降低手工操作带来的配置偏差。已有 1055 人学习下载适合作为单机实验、部署参考和 shell 自动化学习素材。1. 容器全 Up、集群全挂docker redis 集群在 CentOS 7.9 上最先崩的是网络参数一台 CentOS 7.9 的测试机docker ps里 6 个 redis 容器齐刷刷 Upredis-cli -c -p 7000敲进去回一个 CLUSTERDOWN。这是 docker redis 集群最常见的翻车姿势容器活着集群死了。用 linux shell 脚本一键起 6 个节点确实快快到你来不及看清cluster-announce-ip里写的是不是容器内网地址。这套环境在中小项目的测试环境里极其常见——单机 3 主 3 从、6 个端口、一份脚本。装不好不会报错只会在业务连上来那天集体失联。下面按我实际装机的顺序走一遍。2. 装 Docker 之前的环境核对CentOS 7.x 的内核、yum 源与 podman 冲突CentOS 7 已经停止维护但存量的机器还大量跑着 7.6、7.9。在这类系统上装 Docker 和在新系统上装完全是两码事内核老、yum 源里有旧包、extras 源里还躺着 podman 和 buildah 会跟 docker-ce 抢 runc。这一步做不干净后面脚本写得再漂亮也起不来。2.1 内核版本与 overlay2 的 ftype 检查CentOS 7.x 的内核是 3.10 系Docker 官方要求 3.10 以上即可但 overlay2 存储驱动有一个硬性前提底层文件系统的d_type必须可用。xfs 在格式化时没开ftype1overlay2 就会悄悄退回 overlay性能和行为都不一样。装之前先确认两件事# 1. 看内核版本3.10.0-957 以上基本没问题 uname -r # 2. 看根分区的文件系统类型和 ftype 标志 df -T / | tail -1 xfs_info / | grep -i ftypexfs_info输出里出现ftype1才算合格。如果显示ftype0overlay2 用不了只能换存储驱动或者重装系统——这个坑没有优雅的绕法。我一般还会顺手确认一下内存6 个 redis 节点加上 Docker 自身2 GB 内存是底线1 GB 的机器跑到第四个容器就开始 OOM。另外 CentOS 7.6 和 7.9 的用户态工具链差异不大装 Docker 的步骤完全一致不用为小版本单独准备脚本。2.2 清掉 extras 源里的旧 docker 与 podmanCentOS 7 的 extras 源自带docker1.13 版本和podman、buildah。直接yum install docker-ce会报一堆 conflict最常见的报错是container-selinux版本不满足或者runc冲突。正确顺序是先卸干净再装# 卸载系统自带的旧 docker 组件和 podman 家族 yum remove -y docker docker-client docker-client-latest \ docker-common docker-latest docker-latest-logrotate \ docker-logrotate docker-engine podman buildah # 安装 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第三步的源地址是关键。默认的download.docker.com在国内机器上经常几十 KB/s装一个 containerd.io 能等半小时。换成镜像站时只替换域名部分路径/linux/centos/docker-ce.repo保持不变。2.3 指定版本安装 docker-ce别用 latest生产环境我从不装 latest。CentOS 7 上我固定用 20.10 系列它对 cgroup v1、iptables 老版本的兼容性最好再往上的版本在 7.x 上偶发failed to start daemon的问题。先列一下可用版本再指定安装# 列出仓库里可用的 docker-ce 版本 yum list docker-ce --showduplicates | sort -r # 安装指定版本containerd.io 让它自动带 yum install -y --setoptobsoletes0 \ docker-ce-20.10.24-3.el7 \ docker-ce-cli-20.10.24-3.el7 \ containerd.io--setoptobsoletes0这个参数容易被忽略。CentOS 7 的 yum 在处理 obsoletes 关系时会把 docker-ce 判定为要替换 extras 里的docker包从而触发一轮没必要的依赖解析加这个参数直接跳过。版本号里的-3.el7是 release 号yum list里看到什么就写什么别照抄我这里的。装完不要急着systemctl start先写/etc/docker/daemon.json{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, registry-mirrors: [https://你的镜像加速地址] }native.cgroupdriversystemd是为了和 CentOS 7 的 systemd 对齐不写的话默认 cgroupfs后面上 Kubernetes 或者用 systemd 管理容器会打架。日志那两行是保命配置redis 容器一旦开始刷日志不限制大小能把/var/lib/docker撑满磁盘满了集群直接雪崩。2.4 启动并验证docker info 里必须看的三行systemctl daemon-reload systemctl enable docker systemctl start docker # 三行关键信息 docker info | grep -E Cgroup Driver|Storage Driver|Docker Root Dir预期输出是Cgroup Driver: systemd、Storage Driver: overlay2、Docker Root Dir: /var/lib/docker。如果 Storage Driver 显示的是overlay或者vfs回去查 2.1 的 ftype如果 Docker Root Dir 指向了/var/lib/docker以外的路径而你并不知情说明有别的配置文件在干扰用systemctl cat docker看启动参数。这三行过了Docker 这一层就算干净了。3. 脚本拆解6 个 Redis 节点的目录、端口与 cluster-announce-ip一键部署脚本看起来是“一把梭”实际上真正决定成败的是脚本里那几个变量。同一份脚本HOST_IP写错一个数字集群能建起来但外部永远连不上端口少映射一个cluster create会卡在 Waiting for the cluster to join 直到超时。这一章把脚本拆开看。3.1 目录规划与挂载点我不喜欢用 Docker 命名卷集群节点的数据必须落到明确的宿主机路径上出问题能直接进去看nodes.conf。目录结构按端口分/opt/redis-cluster/ ├── 7000/ │ ├── conf/redis.conf │ └── data/ # 存 dump.rdb、appendonly.aof、nodes.conf ├── 7001/ ... └── 7005/data目录一定要挂载。nodes.conf是集群的“黑匣子”记录着节点 ID、槽位分配、其他节点的地址。容器重建时如果这个文件丢了节点会以全新身份加入老集群直接认不出它槽位状态全乱。我见过为了图省事不挂载、docker restart之后集群散架的现场恢复成本远高于当初多写一行-v。3.2 端口表客户端端口与总线端口必须成对出现Redis 集群每个节点占两个端口一个对外提供命令服务一个用于节点间 gossip 通信后者默认是前者加 10000。6 个节点就是 12 个端口节点客户端端口总线端口规划角色redis-7000700017000masterredis-7001700117001masterredis-7002700217002masterredis-7003700317003replicaredis-7004700417004replicaredis-7005700517005replica角色不是启动时决定的是cluster create时按参数顺序分配的表里只是预期结果。端口选择上7000 起步是个惯例避开 6379 是为了防止和单机 redis 混淆。真正要记住的是只要用了桥接网络12 个端口一个都不能少。3.3 脚本主体循环生成配置和容器下面这段是我常用的骨架CentOS 7 的 bash 4.2 完全跑得动#!/usr/bin/env bash set -euo pipefail BASE_DIR/opt/redis-cluster HOST_IP$(hostname -I | awk {print $1}) # 宿主机 IP必须是客户端能访问到的那个 PORTS(7000 7001 7002 7003 7004 7005) IMAGEredis:6.2 PASSWORDRedis2024 for port in ${PORTS[]}; do mkdir -p ${BASE_DIR}/${port}/conf ${BASE_DIR}/${port}/data cat ${BASE_DIR}/${port}/conf/redis.conf EOF port ${port} bind 0.0.0.0 protected-mode no daemonize no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 cluster-announce-ip ${HOST_IP} cluster-announce-port ${port} cluster-announce-bus-port $((port 10000)) appendonly yes appendfsync everysec masterauth ${PASSWORD} requirepass ${PASSWORD} EOF docker run -d --name redis-${port} --net host --restart always \ -v ${BASE_DIR}/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \ -v ${BASE_DIR}/${port}/data:/data \ ${IMAGE} redis-server /usr/local/etc/redis/redis.conf done几个点值得逐个说。set -euo pipefail让脚本任何一步失败就停不要让它带着错误往下跑出 6 个半死不活的容器。$((port 10000))用算术展开算总线端口比手写常量安全。cluster-node-timeout 15000是 15 秒单机部署这个值够了调太小会因为一次 GC 就触发误判主从切换。appendonly yes开 AOF集群模式下 RDB 的持久化粒度太粗。protected-mode no和bind 0.0.0.0必须同时出现只写一个另一个不生效redis 会拒绝非本机连接。镜像版本我写的是redis:6.2。选它的理由5.0 之后redis-cli --cluster子命令才完整内置不用额外装 ruby 的 redis-trib6.2 相比 7.x 在 CentOS 7 的老内核上更稳7.x 的部分特性依赖更新的 glibc 行为没必要给自己找事。3.4 网络模式host 还是 bridge这是个取舍脚本里我用了--net host。原因很直接Redis 集群的节点在握手时会拿自己看到的地址去和对方通信桥接模式下容器内网 IP 是 172.17.x.x宿主机外的客户端拿到这个地址根本路由不到。虽然能用cluster-announce-ip补救但总线端口的 NAT 依然是个玄学问题。用 host 模式的代价是端口不能冲突6 个节点的 12 个端口必须在宿主机上独占。如果坚持用 bridgedocker run要写成这样docker run -d --name redis-7000 \ -p 7000:7000 -p 17000:17000 \ -v /opt/redis-cluster/7000/conf/redis.conf:/usr/local/etc/redis/redis.conf \ -v /opt/redis-cluster/7000/data:/data \ redis:6.2 redis-server /usr/local/etc/redis/redis.conf12 个端口一条条映射漏一个就等着cluster create超时。不管用哪种模式CentOS 7 的 firewalld 都要放行firewall-cmd --permanent --add-port7000-7005/tcp firewall-cmd --permanent --add-port17000-17005/tcp firewall-cmd --reloadSELinux 如果是 enforcing挂载宿主机目录会报 permission denied要么setenforce 0并改/etc/selinux/config要么在挂载参数后加:z。测试环境我一般直接设成 permissive生产环境用:z打标签。4. 组集群redis-cli --cluster create 的参数与执行顺序6 个容器起来不等于集群起来了。这一步才是真正把 16384 个槽位分下去的动作顺序和参数错一个前面全白干。4.1 先确认 6 个节点各自活着# 逐个探活返回 PONG 才继续 for p in 7000 7001 7002 7003 7004 7005; do echo -n port $p: docker exec redis-$p redis-cli -a Redis2024 --no-auth-warning ping done # 确认每个节点都是 cluster 模式启动的 docker exec redis-7000 redis-cli -a Redis2024 --no-auth-warning info cluster | grep cluster_enabledcluster_enabled:1是必须的。如果返回 0说明配置文件没被读到八成是挂载路径写错——镜像里 redis.conf 的位置是/usr/local/etc/redis/redis.conf不是/etc/redis/redis.conf这个路径在 Debian 系镜像里是对的在官方 redis 镜像里是错的。4.2 执行 cluster createHOST_IP$(hostname -I | awk {print $1}) docker exec -it redis-7000 redis-cli -a Redis2024 --no-auth-warning \ --cluster create \ ${HOST_IP}:7000 ${HOST_IP}:7001 ${HOST_IP}:7002 \ ${HOST_IP}:7003 ${HOST_IP}:7004 ${HOST_IP}:7005 \ --cluster-replicas 1 --cluster-yes参数含义要讲清楚不然调整的时候容易乱前三个地址会成为 master后三个按顺序一一配对成 replica。想改主从比例就改节点数量和--cluster-replicas的值比如 9 个节点配--cluster-replicas 2就是 3 主 6 从。--cluster-replicas 1表示每个 master 配一个从节点这是最小高可用配置。--cluster-yes跳过交互式确认。脚本化部署必须加否则会卡在Can I set the above configuration? (type yes to accept)。-a后面跟密码配合--no-auth-warning消掉那条命令行密码泄露的提示。生产环境更稳妥的做法是用REDISCLI_AUTH环境变量传密码。执行成功的标志是最后输出[OK] All 16384 slots covered.只要看到这行槽位分配就完成了。4.3 验证集群状态与槽位分布# 集群整体状态 docker exec redis-7000 redis-cli -c -p 7000 -a Redis2024 --no-auth-warning cluster info # 节点列表看清楚谁是 master 谁是 slave docker exec redis-7000 redis-cli -c -p 7000 -a Redis2024 --no-auth-warning cluster nodes # 官方自带的体检命令最省事 docker exec redis-7000 redis-cli -a Redis2024 --no-auth-warning \ --cluster check ${HOST_IP}:7000cluster info里关注三个字段cluster_state:ok、cluster_slots_assigned:16384、cluster_known_nodes:6。三个数字对不上就是没组好。--cluster check会把每个 master 负责的槽位区间、从节点归属、有没有孤立的节点全列出来出问题第一时间跑它比自己猜快得多。4.4 密码、公告地址变更后的正确重启顺序改redis.conf里的cluster-announce-ip或者换密码不能只docker restart了事。nodes.conf里存着旧地址节点重启后按旧地址去握手握手不上就一直是 fail 状态。正确做法# 1. 停掉全部节点 for p in 7000 7001 7002 7003 7004 7005; do docker stop redis-$p; done # 2. 清掉 nodes.conf数据目录里的 aof/rdb 保留 for p in 7000 7001 7002 7003 7004 7005; do rm -f /opt/redis-cluster/$p/data/nodes.conf; done # 3. 用新配置重新起容器再走一遍 cluster create清nodes.conf意味着集群身份重建如果里面已经有业务数据需要先确认数据在 AOF 里能恢复。这个操作是“后悔药”不是常规操作改配置前想清楚。5. 排查避坑连不上、握手超时、重启后集群散架下面这几条都是我在 CentOS 7 上真实撞过的按现象、原因、解决三段写遇到了直接对号入座。5.1 现象容器全部 Upcluster info 返回 cluster_state:fail原因通常有两个叠加一是nodes.conf残留了上一次集群的身份信息节点以为自己还在老集群里二是cluster-announce-ip填的是127.0.0.1或者容器内网地址节点之间互相通告的地址不可达。解决先docker logs redis-7000看启动日志里 announce 的地址是什么。确认地址错误就按 4.4 的流程清nodes.conf重建。如果地址是对的但还是 fail进容器redis-cli cluster nodes看有没有节点处于handshake状态有的话说明总线端口不通回到 3.4 检查 firewalld 和端口映射。5.2 现象cluster create 卡在 Waiting for the cluster to join 直到超时原因总线端口 17000-17005 没有放行或者没有映射。cluster create阶段节点之间要通过总线端口交换 gossip 消息客户端端口通但总线端口不通表现就是这个卡死。解决宿主机上ss -lntp | grep 170确认端口在监听然后从另一台机器telnet 目标IP 17000验证连通性。firewalld 没放行的补firewall-cmd --add-port17000-17005/tcpbridge 模式漏映射的删容器加-p重建。5.3 现象宿主机上 redis-cli 能连业务方从别的机器连不上原因cluster-announce-ip是容器 IP 或者内网另一块网卡的地址。客户端连上 7000 之后服务端返回 MOVED 重定向重定向里带的是 announce 的地址那个地址客户端根本路由不到。解决把HOST_IP改成客户端视角能访问的地址。多网卡的机器上hostname -I会返回多个 IP取第一个未必对脚本里最好显式指定。改完按 4.4 的流程重建。5.4 现象机器重启后集群整体不可用节点互相不认原因容器设了--restart always开机自动起来但data目录没挂载或者挂载路径写错容器内的nodes.conf在容器重建时丢了每个节点都以新身份启动6 个陌生节点凑在一起当然组不成集群。解决docker inspect redis-7000 | grep -A5 Mounts确认挂载生效。没生效的把数据先备份出来重建容器挂好目录再重新cluster create。这就是为什么 3.1 那节我强调-v不能省。5.5 现象yum install docker-ce 报 container-selinux 版本冲突原因CentOS 7 自带的container-selinux版本太老docker-ce 20.10 要求 2.9 以上而 extras 源里的版本可能只有 2.119 之前的旧包。解决先yum install -y container-selinux从 extras 更新到最新如果还不行就装 centos-release-extras 之外的源提供的版本或者直接yum install -y http://.../container-selinux-2.119.2-1.el7.x86_64.rpm手动指定。装之前务必确认 podman/buildah 已经卸干净它们会锁住 runc 的版本。6. 装完怎么验证从写一个 key 到手动杀掉主节点集群显示 ok 只是第一步能读能写能故障转移才算真的跑通。我习惯按下面这个顺序走一遍五分钟内能确认这套 docker redis 集群是否可用。第一步写读验证。随便挑一个从节点连进去写 key看重定向是否正确# -c 参数让 redis-cli 自动跟随 MOVED 重定向 docker exec -it redis-7003 redis-cli -c -p 7003 -a Redis2024 --no-auth-warning \ set verify:key cluster-ok docker exec -it redis-7003 redis-cli -c -p 7003 -a Redis2024 --no-auth-warning \ get verify:key能拿到cluster-ok说明槽位路由和重定向都正常。如果返回 MOVED 但客户端没跟过去检查有没有加-c。第二步看 key 落在哪个槽、哪个节点docker exec redis-7000 redis-cli -c -p 7000 -a Redis2024 --no-auth-warning \ cluster keyslot verify:key返回一个 0 到 16383 的数字再对照cluster nodes里的槽位区间就能确认这个 key 归属哪个 master。这一步在排查“某些 key 特别慢”的时候很有用。第三步故障转移演练。找出当前的主节点直接docker stop掉一个# 先记下 7000 的节点 ID docker exec redis-7000 redis-cli -p 7000 -a Redis2024 --no-auth-warning cluster myid # 停掉这个 master观察 15 秒 docker stop redis-7000 sleep 20 # 从任意存活节点看集群状态 docker exec redis-7001 redis-cli -p 7001 -a Redis2024 --no-auth-warning cluster nodes预期结果是原来 7000 的从节点应该是 7003 或按配对顺序的那个被提升为 mastercluster_state依然是 ok。如果没有提升看cluster-node-timeout是不是设得太大或者从节点数量不够。验证项可以整理成一张表每次部署完对一遍验证项命令预期结果节点存活逐端口 pingPONG集群模式info clustercluster_enabled:1槽位完整cluster infocluster_slots_assigned:16384节点数量cluster nodes6 个节点3 主 3 从读写路由-c模式 set/get返回写入值故障转移停一个 master从节点提升state 仍为 ok数据持久化重启后 get 老 key值仍在那次因为漏挂data目录导致机器重启后集群散架之后我每次部署完都强制走一遍“停主节点、看提升、再拉起来”的流程哪怕只是测试环境。集群这东西不实际杀一次你永远不知道它能不能扛住。这套脚本和验证步骤希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?