准备工作 创建 工作空间
mkdir -p /usr/local/redis_cluster
下载相应的软件:
wget http://download.redis.io/releases/redis-4.0.1.tar.gz
yum install -y gcc-c++
解压安装包 并 编译
tar -vxf redis-4.0.1.tar.gz
cd redis-4.0.1
make

修改配置文件
将守护进程yes改成no  daemonize no
ip绑定 bind 0.0.0.0
设置密码  requirepass 123456789
主从复制的验证密码  masterauth 123456789
日志文件  logfile "/usr/local/redis/logs/redis-server.log"
开启集群配置  cluster-enabled yes
集群配置文件  cluster-config-file nodes-6379.conf
集群超时时间  cluster-node-timeout 15000
==========================================================================
redis基础镜像的创建
vi Dockerfile

# Redis
# Version 4.0.1
#指定基础镜像  当前镜像非可执行镜像,所以没有包含ENTRYPOINT和CMD指令
FROM centos:7

#镜像作者
MAINTAINER xcl "lansekaola@163.com"

#定义路径的环境变量
ENV REDIS_HOME /usr/local

#本地的redis源码包复制到镜像的根路径下,ADD命令会在复制过后自动解包。
#被复制的对象必须处于Dockerfile同一路径,且ADD后面必须使用相对路径
#将Dockerfile同级目录下的redis-4.0.1.tar.gz复制到镜像的根目录
ADD redis-4.0.1.tar.gz /

#创建安装目录,根据环境变量信息,实际的创建目录为:/usr/local/redis
RUN mkdir -p $REDIS_HOME/redis

#将一开始编译产生并修改后的配置复制到安装目录
ADD redis-4.0.1/redis.conf $REDIS_HOME/redis/

#更新镜像的yum
RUN yum -y update

#安装编译需要的工具
RUN yum install -y gcc make 

#指定工作目录
WORKDIR /redis-4.0.1

#执行编译
RUN make

#移动编译后的redis-server到容器相关的目录
#编译后,容器中只需要可执行文件redis-server
RUN mv /redis-4.0.1/src/redis-server  $REDIS_HOME/redis/

#移动到上一级
WORKDIR /

#删除解压文件
RUN rm -rf /redis-4.0.1

#安装编译完成之后,可以删除多余的gcc跟make
RUN yum remove -y gcc make

#添加数据卷
#此目录需要和redis.conf中logfile一致
#/usr/local/redis/logs/redis-server.log
VOLUME ["/usr/local/redis/logs"]

#暴露6379的端口
EXPOSE 6379

===============================================================================
构建镜像  注意,后面还有一个. 这个.表示当前目录下的Dockerfile
docker build -t xcl/redis-cluster .

└─[$] <> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
xcl/redis-cluster   latest              4772f4f77453        About a minute ago   647MB
centos              7                   67fa590cfc1c        2 months ago         202MB

创建Redis节点镜像
vi Dockerfile

# Redis Node
# Version 4.0.1
FROM xcl/redis-cluster:latest

MAINTAINER xcl "lansekaola@163.com"

#指定容器启动程序及参数
ENTRYPOINT ["/usr/local/redis/redis-server", "/usr/local/redis/redis.conf"]

构建redis节点镜像
docker build -t xcl/redis-node .
===============================================================================
└─[$] <> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
xcl/redis-node      latest              5e24239cfce9        10 seconds ago      647MB
xcl/redis-cluster   latest              4772f4f77453        6 minutes ago       647MB
centos              7                   67fa590cfc1c        2 months ago        202MB

配置集群

1.运行redis容器
docker run -d --name redis-node-7000 -p 7000:6379 xcl/redis-node
docker run -d --name redis-node-7001 -p 7001:6379 xcl/redis-node
docker run -d --name redis-node-7002 -p 7002:6379 xcl/redis-node
docker run -d --name redis-node-7003 -p 7003:6379 xcl/redis-node
docker run -d --name redis-node-7004 -p 7004:6379 xcl/redis-node
docker run -d --name redis-node-7005 -p 7005:6379 xcl/redis-node

docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
cc29cc160917        xcl/redis-node      "/usr/local/redis/re…"   55 seconds ago       Up 54 seconds       0.0.0.0:7005->6379/tcp   redis-node-7005
5c1200b759a7        xcl/redis-node      "/usr/local/redis/re…"   About a minute ago   Up About a minute   0.0.0.0:7004->6379/tcp   redis-node-7004
b50ccbcaaecc        xcl/redis-node      "/usr/local/redis/re…"   About a minute ago   Up About a minute   0.0.0.0:7003->6379/tcp   redis-node-7003
cb4843b7e73b        xcl/redis-node      "/usr/local/redis/re…"   About a minute ago   Up About a minute   0.0.0.0:7002->6379/tcp   redis-node-7002
df2935e00b99        xcl/redis-node      "/usr/local/redis/re…"   About a minute ago   Up About a minute   0.0.0.0:7001->6379/tcp   redis-node-7001
d6ce5aba983c        xcl/redis-node      "/usr/local/redis/re…"   About a minute ago   Up About a minute   0.0.0.0:7000->6379/tcp   redis-node-7000
===============================================================================
docker inspect cc29cc160917 5c1200b759a7 b50ccbcaaecc cb4843b7e73b df2935e00b99 d6ce5aba983c | grep IPA
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.7",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.7",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.6",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.6",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.5",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.5",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.4",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.4",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.3",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.3",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.2",

解析宿主机与容器的ip映射关系
192.168.1.92:7000    172.17.0.2:6379
192.168.1.92:7001    172.17.0.3:6379
192.168.1.92:7002    172.17.0.4:6379
192.168.1.92:7003    172.17.0.5:6379
192.168.1.92:7004    172.17.0.6:6379
192.168.1.92:7005    172.17.0.7:6379
===============================================================================
CLUSTER  FAILOVER
//集群(cluster) 
CLUSTER INFO 打印集群的信息 
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。  
   
//节点(node) 
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。 
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。 
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。 
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。  
   
//槽(slot) 
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。 
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。 
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。 
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,
那么先让另一个节点删除该槽>,然后再进行指派。 
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。 
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。 
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。  
   
//键 (key) 
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。 
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。 
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。
===============================================================================
节点配置

Redis Cluster 的集群感知操作
redis 集群感知:节点握手——是指一批运行在集群模式的节点通过Gossip协议彼此通信,达到感知对方的过程。

任意进入一个redis
将以下所有的redis服务都添加到redis集群的节点
./redis-cli -p 7000
127.0.0.1:7000> auth 123456789
OK
127.0.0.1:7000> info replication
# Replication
role:master
connected_slaves:0
master_replid:3384d18e4e0b51e211b3b96d08c7ae8003e45046
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
客户连接之后,因为之前设置了密码,所以需要先输入密码认证,否则就无法通过
所有的redis都是master角色 role:master

127.0.0.1:7000> CLUSTER MEET 172.17.0.3 6379
OK
127.0.0.1:7000> CLUSTER MEET 172.17.0.4 6379
OK
127.0.0.1:7000> CLUSTER MEET 172.17.0.5 6379
OK
127.0.0.1:7000> CLUSTER MEET 172.17.0.6 6379
OK
127.0.0.1:7000> CLUSTER MEET 172.17.0.7 6379
OK

127.0.0.1:7000> CLUSTER NODES
268d72f0c226b7223e86c9afbb8cc9c67405a3ed 172.17.0.5:6379@16379 master - 0 1572739906997 3 connected
5e3c52d5a4232b937588d2ee7c6b3d667e9ae60d 172.17.0.6:6379@16379 master - 0 1572739904000 4 connected
aa1f8bcadcc2b571366f7b5a6326659d703cc32a 172.17.0.3:6379@16379 master - 0 1572739905000 1 connected
9f8af65badd4675970a72cccc3f42f4617ee8851 172.17.0.7:6379@16379 master - 0 1572739906000 5 connected
c54902379b775e01b25abc5dc6d446389908f653 172.17.0.2:6379@16379 myself,master - 0 1572739904000 0 connected
6ba512ca78a601d4f38dfe152dbd8646810c0a6d 172.17.0.4:6379@16379 master - 0 1572739905992 2 connected

当前已经使这六个节点组成集群,但是现在还无法工作,因为集群节点还没有分配槽(slot)。
127.0.0.1:7000> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:0  # 被分配槽的个数为0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_ping_sent:179
cluster_stats_messages_pong_sent:198
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:382
cluster_stats_messages_ping_received:198
cluster_stats_messages_pong_received:184
cluster_stats_messages_received:382

上面看到集群状态是失败的,原因是槽位没有分配,而且需要一次性把16384个槽位完全分配了,集群才可用。
=================================================================================================================

分配槽位: CLUSTER ADDSLOTS  槽位,一个槽位只能分配一个节点,16384个槽位必须分配完,不同节点不能冲突。
所以通过脚本进行分配 addslots.sh:

#!/bin/bash
#将0-5461    的槽点配置在 172.17.0.2:6379 (宿主机7000) 的redis上
n=0
for ((i=n;i<=5461;i++))
do
   /usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7000 -a 123456789 CLUSTER ADDSLOTS $i
done
 
#将5462-10922的槽点配置在 172.17.0.3:6379 (宿主机7001) 的redis上
n=5462
for ((i=n;i<=10922;i++))
do
   /usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7001 -a 123456789 CLUSTER ADDSLOTS $i
done
 
#将10923-16383的槽点配置在 172.17.0.4:6379 (宿主机7002) 的redis上
n=10923
for ((i=n;i<=16383;i++))
do
   /usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7002 -a 123456789 CLUSTER ADDSLOTS $i
done

保存后  改成  可执行文件  
chmod 777 addslots.sh
执行脚本
=================================================================================================================
127.0.0.1:7000> CLUSTER INFO
cluster_state:ok                         # 集群状态为失败
cluster_slots_assigned:16384             # 已经全部分配完成  一定要等到脚本执行 完全
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6                    # 总共6个节点
cluster_size:3                           # 集群为 3 个节点
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_ping_sent:955
cluster_stats_messages_pong_sent:988
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:1948
cluster_stats_messages_ping_received:988
cluster_stats_messages_pong_received:960
cluster_stats_messages_received:1948

以上我们已经搭建了一套完整的可运行的redis cluster,但是每个节点都是单点,
这样子可能出现,一个节点挂掉,整个集群因为槽位分配不完全而崩溃,
因此,我们需要为每个节点配置副本备用节点。
前面我们已经提前创建了6个备用节点,搭建集群花了三个,因此还有剩下三个直接可以用来做备用副本。

查看所有节点的id
127.0.0.1:7000>  CLUSTER NODES
268d72f0c226b7223e86c9afbb8cc9c67405a3ed 172.17.0.5:6379@16379 master - 0 1572740973000 3 connected
5e3c52d5a4232b937588d2ee7c6b3d667e9ae60d 172.17.0.6:6379@16379 master - 0 1572740975861 4 connected
aa1f8bcadcc2b571366f7b5a6326659d703cc32a 172.17.0.3:6379@16379 master - 0 1572740971000 1 connected 5462-10922
9f8af65badd4675970a72cccc3f42f4617ee8851 172.17.0.7:6379@16379 master - 0 1572740974000 5 connected
c54902379b775e01b25abc5dc6d446389908f653 172.17.0.2:6379@16379 myself,master - 0 1572740975000 0 connected 0-5461
6ba512ca78a601d4f38dfe152dbd8646810c0a6d 172.17.0.4:6379@16379 master - 0 1572740974851 2 connected 10923-16383

编写脚本,添加副本节点
vi addSlaveNodes.sh

#!/bin/bash
/usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7003 -a 123456789 CLUSTER REPLICATE c54902379b775e01b25abc5dc6d446389908f653
 
/usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7004 -a 123456789 CLUSTER REPLICATE aa1f8bcadcc2b571366f7b5a6326659d703cc32a
 
/usr/local/redis_cluster/redis-4.0.1/src/redis-cli -p 7005 -a 123456789 CLUSTER REPLICATE 6ba512ca78a601d4f38dfe152dbd8646810c0a6d

注意:1、作为备用的节点,必须是未分配槽位的,否者会操作失败 (error) ERR To set a master the node must be empty and without assigned slots 。
2、需要从 需要添加的节点上面执行操作,CLUSTER REPLICATE [node_id]  ,使当前节点成为 node_id 的副本节点。
3、添加从节点(集群复制): 复制的原理和单机的Redis复制原理一样,区别是:集群下的从节点也需要运行在 cluster 模式下,要先添加到集群里面,再做复制。

保存后  改成  可执行文件  
chmod 777 addSlaveNodes.sh

执行脚本
./addSlaveNodes.sh 
OK
OK
OK

127.0.0.1:7000> CLUSTER NODES
268d72f0c226b7223e86c9afbb8cc9c67405a3ed 172.17.0.5:6379@16379 slave c54902379b775e01b25abc5dc6d446389908f653 0 1572741580507 3 connected
5e3c52d5a4232b937588d2ee7c6b3d667e9ae60d 172.17.0.6:6379@16379 slave aa1f8bcadcc2b571366f7b5a6326659d703cc32a 0 1572741582533 4 connected
aa1f8bcadcc2b571366f7b5a6326659d703cc32a 172.17.0.3:6379@16379 master - 0 1572741581526 1 connected 5462-10922
9f8af65badd4675970a72cccc3f42f4617ee8851 172.17.0.7:6379@16379 slave 6ba512ca78a601d4f38dfe152dbd8646810c0a6d 0 1572741583000 5 connected
c54902379b775e01b25abc5dc6d446389908f653 172.17.0.2:6379@16379 myself,master - 0 1572741581000 0 connected 0-5461
6ba512ca78a601d4f38dfe152dbd8646810c0a6d 172.17.0.4:6379@16379 master - 0 1572741583541 2 connected 10923-16383

可以看到我们现在实现了三主三从的一个高可用集群。

集群测试:
docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
cc29cc160917        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7005->6379/tcp   redis-node-7005
5c1200b759a7        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7004->6379/tcp   redis-node-7004
b50ccbcaaecc        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7003->6379/tcp   redis-node-7003
cb4843b7e73b        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7002->6379/tcp   redis-node-7002
df2935e00b99        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7001->6379/tcp   redis-node-7001
d6ce5aba983c        xcl/redis-node      "/usr/local/redis/re…"   46 minutes ago      Up 46 minutes       0.0.0.0:7000->6379/tcp   redis-node-7000

docker stop cb4843b7e73b
尝试关闭一个master,选择端口为 7002 的容器,停掉之后:
自动故障转移正常

127.0.0.1:7000> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5  #当前节点数为5了
cluster_my_epoch:0
cluster_stats_messages_ping_sent:1900
cluster_stats_messages_pong_sent:1937
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:3842
cluster_stats_messages_ping_received:1937
cluster_stats_messages_pong_received:1902
cluster_stats_messages_received:3839

127.0.0.1:7000> CLUSTER NODES
268d72f0c226b7223e86c9afbb8cc9c67405a3ed 172.17.0.5:6379@16379 slave c54902379b775e01b25abc5dc6d446389908f653 0 1572742433000 3 connected
5e3c52d5a4232b937588d2ee7c6b3d667e9ae60d 172.17.0.6:6379@16379 slave aa1f8bcadcc2b571366f7b5a6326659d703cc32a 0 1572742432091 4 connected
aa1f8bcadcc2b571366f7b5a6326659d703cc32a 172.17.0.3:6379@16379 master - 0 1572742434136 1 connected 5462-10922
9f8af65badd4675970a72cccc3f42f4617ee8851 172.17.0.7:6379@16379 master - 0 1572742433115 6 connected 10923-16383
c54902379b775e01b25abc5dc6d446389908f653 172.17.0.2:6379@16379 myself,master - 0 1572742431000 0 connected 0-5461
6ba512ca78a601d4f38dfe152dbd8646810c0a6d 172.17.0.4:6379@16379 slave,fail 9f8af65badd4675970a72cccc3f42f4617ee8851 1572742307745 1572742305617 6 connected
4主节点 失败后  它对应的 从节点 7 自动升级为主节点

再次启动容器后  ====127.0.0.1:7000> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6   #当前节点数为6了
cluster_my_epoch:0
cluster_stats_messages_ping_sent:2245
cluster_stats_messages_pong_sent:2186
cluster_stats_messages_meet_sent:5
cluster_stats_messages_fail_sent:5
cluster_stats_messages_auth-ack_sent:1
cluster_stats_messages_update_sent:1
cluster_stats_messages_sent:4443
cluster_stats_messages_ping_received:2186
cluster_stats_messages_pong_received:2175
cluster_stats_messages_fail_received:1
cluster_stats_messages_auth-req_received:1
cluster_stats_messages_received:4363

参照学习