背景

我需要在三台服务器(一主二从)上搭建一个redis的哨兵模式。

如果你是在同一台服务器上部署,执行以下命令,然后忽略创建overlay网络这一步。

docker network create --driver bridge redis-net-overlay

我的是三台服务器,为了docker内部网络能相互通信,所以采用overlay网络。

一、创建overlay网络

1.初始化Swarm集群(主节点执行)
docker swarm init

这个命令会输出一个带有 token 的 docker swarm join 命令,用于让其他机器加入集群。

2.节点服务器加入Swarm集群

在从节点服务器上执行上一步在主节点得到的命令,形如:

docker swarm join --token <TOKEN> <IP-OF-MANAGER>:2377
3.在 Swarm 管理节点(主节点服务器)上创建 Overlay 网络:
docker network create -d overlay --attachable redis-net-overlay

--attachable 参数允许非 Swarm 服务(即直接用 docker run 启动的容器)也能连接到此网络。

二、部署并运行redis容器

1.传输redis的docker镜像包到每个节点的/data目录下

我这块用的是镜像版本是7.2.6

2.在主节点编写脚本并运行
cd /data
vim redis-master.sh
#!/bin/bash

# 创建主数据目录
sudo mkdir -p /data/redis/data

# 设置所有权和权限
sudo chown -R 1000:1000 /data/redis
sudo chmod -R 775 /data/redis


# 设置节点ID(根据IP最后一位)
#IP_LAST_OCTET=$(hostname -I | awk '{print $1}' | cut -d. -f4)
#NODE_ID=$((IP_LAST_OCTET - 0))

# 停止并删除现有容器
docker stop reids-matser >/dev/null 2>&1 || true
docker rm reids-matser >/dev/null 2>&1 || true


# 镜像处理逻辑 - 使用您指定的路径 /data/minio-2024-10.tar
if [ -f "/data/redis-7.2.6.tar" ]; then
    echo "从本地文件加载Redis镜像..."
    docker load -i /data/redis-7.2.6.tar
    # 确保加载后镜像名称正确
    if ! docker image inspect redis:7.2.6 &> /dev/null; then
        echo "重新标记镜像为 redis:7.2.6..."
        IMAGE_ID=$(docker images -q --filter "dangling=true" | head -1)
        docker tag ${IMAGE_ID} redis:7.2.6
    fi
fi

# 启动Redis容器
echo "启动Redis容器节点..."
docker run -d --name redis-master --net redis-net-overlay \
-p 16379:6379 \
-v /data/redis/data:/data \
redis:7.2.6 \
redis-server --appendonly yes --requirepass AAbbb_123
  
# 等待容器启动
sleep 5

echo "Reids节点启动成功!"
echo "容器状态:"
docker ps -a | grep redis-master

echo "数据路径: /data/redis"
echo "镜像文件路径: /data/redis-7.2.6.tar"

运行主节点redis容器

chmod +x redis-master.sh
./redis-master.sh
3.从节点编写脚本并运行
cd /data
vim redis-slave.sh

这个脚本内容redis-slave可以替换为redis-slave1啥的,各个容器名称尽量不一样

#!/bin/bash

# 创建主数据目录
sudo mkdir -p /data/redis/data

# 设置所有权和权限
sudo chown -R 1000:1000 /data/redis
sudo chmod -R 775 /data/redis


# 设置节点ID(根据IP最后一位)
#IP_LAST_OCTET=$(hostname -I | awk '{print $1}' | cut -d. -f4)
#NODE_ID=$((IP_LAST_OCTET - 0))

# 停止并删除现有容器
docker stop reids-slave >/dev/null 2>&1 || true
docker rm reids-slave >/dev/null 2>&1 || true


# 镜像处理逻辑 - 使用您指定的路径 
if [ -f "/data/redis-7.2.6.tar" ]; then
    echo "从本地文件加载Redis镜像..."
    docker load -i /data/redis-7.2.6.tar
    # 确保加载后镜像名称正确
    if ! docker image inspect redis:7.2.6 &> /dev/null; then
        echo "重新标记镜像为 redis:7.2.6..."
        IMAGE_ID=$(docker images -q --filter "dangling=true" | head -1)
        docker tag ${IMAGE_ID} redis:7.2.6
    fi
fi

# 启动Redis容器
echo "启动Redis容器节点..."
docker run -d --name reids-slave --net redis-net-overlay \
-p 16379:6379 \
-v /data/redis/data:/data \
redis:7.2.6 \
redis-server --appendonly yes --requirepass AAbbb_123 \
--slaveof redis-master 6379 --masterauth AAbbb_123
  
# 等待容器启动
sleep 5

echo "Reids节点启动成功!"
echo "容器状态:"
docker ps -a | grep reids-slave

echo "数据路径: /data/redis"
echo "镜像文件路径: /data/redis-7.2.6.tar"

运行从节点容器

chmod +x redis-slave.sh
./redis-slave.sh

三、验证主从状态

docker exec -it redis-master redis-cli -a AAbbb_123 INFO replication

预期输出应显示role:master和两个连接的从节点信息

四、部署并运行sentinel

1.每个服务器编写sentinel配置文件
cd /data/redis
vim sentinel.conf

内容如下:

port 36379
sentinel monitor mymaster redis-master 6379 2
sentinel auth-pass mymaster AAbbb_123
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
sentinel resolve-hostnames yes

关键参数说明:

  • sentinel monitor mymaster redis-master 6379 2:监控名为mymaster的主节点,至少需要2个哨兵同意才能判定主节点失效
  • sentinel down-after-milliseconds:5000毫秒(5秒)无响应认为节点下线
  • sentinel parallel-syncs:故障转移时并行同步的从节点数量
2.编写sentinel启动脚本
cd /data 
vim redis_sentinel.sh

脚本内容(注意:这里面的redis-sentinel1需要替换为redis-sentinel2或redis-sentinel3放到另外两台服务器)

#!/bin/bash

# 停止并删除现有容器

docker stop redis-sentinel1 >/dev/null 2>&1 || true
docker rm redis-sentinel1 >/dev/null 2>&1 || true

# 镜像处理逻辑 - 使用您指定的路径 

if [ -f "/data/redis-7.2.6.tar" ]; then
    echo "从本地文件加载Redis镜像..."
    docker load -i /data/redis-7.2.6.tar

    # 确保加载后镜像名称正确

    if ! docker image inspect redis:7.2.6 &> /dev/null; then
        echo "重新标记镜像为 redis:7.2.6..."
        IMAGE_ID=$(docker images -q --filter "dangling=true" | head -1)
        docker tag ${IMAGE_ID} redis:7.2.6
    fi
fi

# 启动Redis容器

echo "启动Redis容器节点..."
docker run -d --name redis-sentinel1 --net redis-net-overlay \
-p 36379:36379 \
-v /data/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf \
redis:7.2.6 \
redis-sentinel /usr/local/etc/redis/sentinel.conf

# 等待容器启动

sleep 5

echo "Reids-Sentinel节点启动成功!"
echo "容器状态:"
docker ps -a | grep redis-sentinel1

echo "镜像文件路径: /data/redis-7.2.6.tar"

给脚本授权并启动

chmod +x redis_sentinel.sh
./redis_sentinel.sh
3.验证哨兵状态

在任何一台服务器上执行以下命令检查哨兵状态:

docker exec -it redis-sentinel1 redis-cli -p 36379 INFO sentinel

预期输出应显示监控的主节点信息和哨兵节点数量

五、故障转移测试

1.在主节点服务器上停止主节点容器:
docker stop redis-master
2. 观察故障转移

等待约10-15秒后,检查哨兵日志:

docker logs redis-sentinel1

应该能看到哨兵检测到主节点下线并触发故障转移的日志

3.验证新主节点

检查新的主节点信息:

docker exec -it redis-sentinel1 redis-cli -p 36379 sentinel get-master-addr-by-name mymaster

输出应为其中一个从节点(redis-slave1或redis-slave2)的IP和端口,这个IP应该是docker内部的IP,可以使用以下命令查看到底是哪个节点的IP

docker inspect redis-salve1 | grep Networks -A 10
4.恢复原主节点

如果需要恢复原主节点,只需重新启动它:

docker start redis-master
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐