一、先理解哨兵模式在容器里的角色
Redis 哨兵模式由两类进程组成:Redis Server 和 Redis Sentinel。Server 负责数据存储,通常是一主多从;Sentinel 负责监控主节点状态,发现主节点不可达后发起选举,把某个从节点提升为新主,并通知其他从节点跟着新主复制。容器化部署时,每个 Redis 和 Sentinel 都跑在独立容器里,网络通过 Docker 自定义 bridge 网络打通,这样容器名称可以直接当作主机名使用。

很多人误以为哨兵模式需要额外的服务发现组件,实际上 Sentinel 自身就承担了配置中心角色,客户端先连接 Sentinel 获取当前主节点地址,再连接主节点读写。容器化以后,客户端只需要知道 Sentinel 暴露的端口即可。另一点容易混淆的是,哨兵不是代理,数据流量不会经过 Sentinel,它只做监控和通知。所以主从切换期间,Sentinel 进程本身不能有单点,生产环境至少三个哨兵。
二、配置文件准备与关键参数说明
容器化部署前先准备 Redis 主从和哨兵的配置。主节点 redis.conf 可以保持默认,但从节点必须配置 replicaof 指向主节点。使用 Docker 自定义网络时,replicaof 最好写容器名而不是 IP,例如 replicaof redis-master 6379,这样即使容器重启 IP 变化也不会影响复制关系。5.0 之前版本使用 slaveof,新版本推荐 replicaof。
从节点配置示例:
# redis-slave.conf bind 0.0.0.0 protected-mode no port 6379 replicaof redis-master 6379 slave-read-only yes
哨兵配置文件 sentinel.conf 的核心是 monitor 指令。格式为 sentinel monitor mymaster redis-master 6379 2。其中 mymaster 是主节点别名,redis-master 是主节点容器名,6379 是端口,2 是法定人数,表示至少两个哨兵同意主节点不可达才发起故障转移。这个值建议设置为哨兵数量的一半加一,三个哨兵时就是 2。
容器场景下还需要关注几个参数。sentinel down-after-milliseconds 控制主观下线判定时间,默认 30000 毫秒,测试环境可以调小到 5000 以便快速看到切换效果。sentinel failover-timeout 控制故障转移总超时,如果网络抖动大可以适当调大,但生产环境不建议低于 10000。sentinel parallel-syncs 决定新主产生后同时有几个从节点同步数据,默认 1 比较稳妥。
# sentinel.conf port 26379 sentinel monitor mymaster redis-master 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 15000 sentinel parallel-syncs mymaster 1
为什么不用 host 网络?如果使用 host 网络,容器共享宿主机端口,虽然性能好,但多个 Redis 实例会端口冲突,而且隔离性差。自定义 bridge 网络可以让所有容器通过名称互访,更适合哨兵场景。创建网络命令是 docker network create redis-ha,后续 Compose 文件里声明同一网络即可。
三、用 Docker Compose 编排一主二从三哨兵
Compose 是最直观的容器化编排方式。以下配置定义 6 个服务:redis-master、redis-slave1、redis-slave2、sentinel1、sentinel2、sentinel3。主节点不依赖其他服务,从节点依赖主节点,哨兵依赖主从节点。依赖关系使用 depends_on 保证启动顺序,但 depends_on 只能保证容器启动顺序,不能保证 Redis 服务就绪,因此哨兵容器启动后最好配合 restart: always 和健康检查。
version: "3.8"
services:
redis-master:
image: redis:7.2
container_name: redis-master
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- ./conf/redis-master.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-ha
ports:
- "6379:6379"
redis-slave1:
image: redis:7.2
container_name: redis-slave1
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- ./conf/redis-slave.conf:/usr/local/etc/redis/redis.conf
depends_on:
- redis-master
networks:
- redis-ha
ports:
- "6380:6379"
redis-slave2:
image: redis:7.2
container_name: redis-slave2
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- ./conf/redis-slave.conf:/usr/local/etc/redis/redis.conf
depends_on:
- redis-master
networks:
- redis-ha
ports:
- "6381:6379"
sentinel1:
image: redis:7.2
container_name: sentinel1
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
- redis-ha
ports:
- "26379:26379"
sentinel2:
image: redis:7.2
container_name: sentinel2
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
- redis-ha
ports:
- "26380:26379"
sentinel3:
image: redis:7.2
container_name: sentinel3
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
- redis-ha
ports:
- "26381:26379"
networks:
redis-ha:
driver: bridge
上面的配置有一个细节:哨兵三个容器挂载同一份 sentinel.conf,在切换完成后 Sentinel 会重写这个配置文件,把新的主节点信息写入。如果希望配置持久化,需要将配置文件放到可写目录,否则下一次重启哨兵可能仍然读取旧主地址。容器内部 Sentinel 重写文件时,对挂载文件可能有权限要求,如果使用 Windows 或某些 NAS 文件系统,建议先确认 Redis 用户有写入权限。
四、启动集群并验证主从复制
执行 docker compose up -d 后,可以用 docker ps 查看 6 个容器状态。进入主节点容器,执行 redis-cli info replication 可以看到 role:master,connected_slaves:2。进入从节点容器同样的命令会看到 role:slave,master_host:redis-master。注意从节点配置里的 replicaof 写的是容器名,所以必须确认这些容器在同一个自定义网络里。
如果从节点无法连接主节点,先检查 redis-slave 日志里是否有 Unable to connect to MASTER 之类的错误。常见原因是主节点默认 protected-mode yes 且 bind 127.0.0.1,容器外部无法访问。本文配置里主节点使用的是 bind 0.0.0.0 和 protected-mode no,如果要求安全,可以改为绑定容器网段,例如 bind redis-master 或者 IP 范围,但在容器环境里一般通过 Docker 网络隔离来保证安全。
验证哨兵状态:docker exec -it sentinel1 redis-cli -p 26379 sentinel master mymaster 会返回当前主节点 IP、端口和 flags。flags 正常值为 master,故障切换后会更新。再用 sentinel sentinels mymaster 查看三个哨兵是否互相发现。
五、模拟主节点故障并观察自动切换
关键测试环节是杀掉主节点容器,观察哨兵是否自动提升新主。执行 docker stop redis-master,等待 down-after-milliseconds 设置的时间后,三个哨兵开始判定主观下线,达到法定人数后触发故障转移。此时可以持续关注 sentinel 日志,看到 +sdown、+odown、+try-failover、+switch-master 等事件。
切换完成后,进入任意从节点容器执行 redis-cli info replication,原来两个从节点之一会变成 role:master,另一个会变成它的从节点。此时可以把原主节点容器重新启动,它会以从节点身份加入集群,不会抢回主节点角色。这个场景需要预先在 redis-master.conf 里配置 replicaof 或由哨兵动态设置,否则原主重启后仍是主节点,可能造成脑裂。更合适的做法是原主容器重新加入时,哨兵会自动用 slaveof 命令将其降级,只要原主节点启动时不是独立主即可。实际测试中 redis:7.2 镜像默认启动后,哨兵会在 replica-priority 配置下自动处理。
这就是容器化哨兵部署和验证的完整流程。想要进一步优化,可以给每个 Redis 节点配置 requirepass 和 masterauth,哨兵侧添加 sentinel auth-pass 参数;还可以加入 supervisord 或 healthcheck,让容器异常退出后自动恢复。