在使用 Docker 构建高可用的后端基础架构时,Redis 主从复制(Master-Slave)是最基础也是最常用的模式之一。相较于官方原生镜像,bitnami/redis 提供了开箱即用的集群环境变量配置,非常适合快速搭建。
本文记录了在单台 Ubuntu 虚拟机上,通过自定义 Docker 网络实现 Redis 主从集群部署的全过程,并复盘了一个非常经典的挂载目录权限踩坑案例。
一、 🚀 集群部署命令
为了让主从节点能够互相通信,这里使用了自定义网络 mynet。
1. 部署主节点 (Master)
主节点的配置相对简单,主要定义对外端口、持久化挂载目录以及运行模式。
docker run -d --name redis01 \
-p 6379:6379 \
-v /app/rd1:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=master \
-e REDIS_PASSWORD=123456 \
--network mynet \
bitnami/redis
核心参数解析:
REDIS_REPLICATION_MODE=master:明确指定当前容器为主节点。REDIS_PASSWORD:设置 Redis 的访问密码。
2. 部署从节点 (Slave)
从节点需要明确指向主节点的地址和认证信息。
docker run -d --name redis02 \
-p 6380:6379 \
--network mynet \
-v /app/rd2:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=slave \
-e REDIS_MASTER_HOST=redis01 \
-e REDIS_MASTER_PORT_NUMBER=6379 \
-e REDIS_MASTER_PASSWORD=123456 \
-e REDIS_PASSWORD=123456 \
bitnami/redis
核心参数解析:
REDIS_REPLICATION_MODE=slave:指定为从节点模式。REDIS_MASTER_HOST=redis01:利用 Docker 内部的 DNS 解析,直接使用主节点的容器名redis01作为主机地址。REDIS_MASTER_PASSWORD:连接主节点进行数据同步时所需的认证密码。
二、 💥 经典踩坑:目录权限被拒绝 (Permission Denied)
1. 报错现象
在执行完上述 run 命令后,容器可能并没有如期运行。通过 docker logs redis01 查看日志,发现了致命错误:
1:M 10 Jun 2026 08:04:23.053 # Can't open or create append-only dir appendonlydir: Permission denied
2. 原因分析
这是使用 bitnami 镜像时非常容易遇到的问题。出于安全考虑,Bitnami 的容器默认使用非 root 用户(通常是 uid 1001)来运行服务进程。 当我们将宿主机的 /app/rd1 目录通过 -v 挂载到容器内的 /bitnami/redis/data 时,宿主机目录的默认所有者通常是 root,导致容器内的非 root 用户没有写入权限,AOF 持久化文件无法创建,服务随即崩溃重启。
3. 解决方案
最直接的修复方式是在宿主机上放开挂载目录的权限,确保容器内进程可读可写:
# 修改主从节点对应的数据挂载目录权限
chmod -R 777 /app/rd1
chmod -R 777 /app/rd2
💡 进阶建议:在生产环境中,出于严格的安全考量,建议使用 chown -R 1001:1001 /app/rd1 将目录所有者精准转移给容器内的对应用户,而不是简单粗暴地放开 777 权限。
三、 ✅ 验证集群状态
权限修复完毕后,重新启动容器。使用 docker ps 查看当前的运行状态,可以看到两个节点均已稳定运行,端口映射也符合预期:
root@loe-virtual-machine:/app# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be702f9e3f0e bitnami/redis "/opt/bitnami/script…" 8 minutes ago Up 8 minutes 0.0.0.0:6380->6379/tcp, [::]:6380->6379/tcp redis02
cd4fb0f22667 bitnami/redis "/opt/bitnami/script…" 29 minutes ago Up 22 minutes 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp redis01
四、 🔍 深度复盘:Redis 从节点全量同步日志剖析
判断 Redis 主从是否真正连接成功,不能只看 Up 状态,我们需要通过 docker logs redis02 深入观察从节点的底层启动和同步日志。
以下是标准的 Redis 主从全量同步 黄金日志及其四阶段拆解:
🤝 阶段 1:建立网络连接与握手
1:S 10 Jun 2026 08:25:21.897 * Connecting to MASTER redis01:6379
1:S 10 Jun 2026 08:25:21.898 * MASTER <-> REPLICA sync started
1:S 10 Jun 2026 08:25:21.898 * Master replied to PING, replication can continue...
剖析:从节点通过自定义网络
mynet主动拨通主节点redis01的 6379 端口。向主节点发送PING探测,并成功收到主节点的响应,这意味着主从网络畅通、认证凭证正确。
🔄 阶段 2:协商同步策略(触发全量同步)
1:S 10 Jun 2026 08:25:21.898 * Partial resynchronization not possible (no cached master)
1:S 10 Jun 2026 08:25:21.899 * PSYNC is not possible, initialize RDB channel.
剖析:从节点尝试申请“增量同步(Partial resynchronization)”,但由于这是它第一次连接该主节点,本地没有缓存主节点的运行 ID(runid)。Redis 底层随即决定转为全量同步,开始初始化 RDB 数据通道。
📥 阶段 3:接收并加载主节点 RDB 快照
1:S 10 Jun 2026 08:25:26.014 * Starting to receive RDB and replication stream in parallel.
1:S 10 Jun 2026 08:25:26.024 * MASTER <-> REPLICA sync: receiving streamed RDB from master with EOF to disk
1:S 10 Jun 2026 08:25:26.028 * MASTER <-> REPLICA sync: Loading DB in memory
1:S 10 Jun 2026 08:25:26.030 * MASTER <-> REPLICA sync: Flushing old data
剖析:主节点在后台生成了一份最新的 RDB 快照并通过网络流发送给从节点。从节点收到后,首先清空本地老数据(Flushing old data),随后将这份 RDB 加载到内存中(Loading DB in memory)。由于是全新部署,显示
keys loaded: 0。
🎉 阶段 4:同步大获成功
1:S 10 Jun 2026 08:25:26.031 * MASTER <-> REPLICA sync: Finished with success
剖析:当在日志中看到
Finished with success时,说明底层主从数据通道已彻底就绪!后续主节点所有的增量写入修改,都会通过replication stream实时广播并同步给该从节点。
📝 博主总结
安全意识第一步:Bitnami 镜像默认以普通用户运行虽会带来权限摩擦,但更符合企业生产环境的安全规范。挂载宿主机目录时一定要注意 UID 的权限转移。
拒绝盲目猜测:遇到容器莫名重启或数据不一致,永远第一时间执行
docker logs <容器名>。看懂日志的这四个阶段,是后端开发从“命令调用者”蜕变为“架构理解者”的关键。
至此,一个轻量级的 Redis 主从集群就已经成功跑通了。数据的写入操作将由 redis01 承担,并自动同步到 redis02,为后续的读写分离打下了基础。