前言:本文记录了如何使用docker-compose和redis官方镜像和第三方redis-trib镜像组建3主3从的redis集群并设置密码.
[root@localhost redis]# pwd
/apps/usr/redis
[root@localhost redis]# ll
total 72
-rw-r--r--. 1 root root 426 Aug 5 16:28 docker-compose.yml
drwxr-xr-x. 2 root root 42 Aug 5 16:54 node1
drwxr-xr-x. 2 root root 42 Aug 5 16:54 node2
drwxr-xr-x. 2 root root 42 Aug 5 16:55 node3
drwxr-xr-x. 2 root root 42 Aug 5 16:55 node4
drwxr-xr-x. 2 root root 42 Aug 5 16:55 node5
drwxr-xr-x. 2 root root 42 Aug 5 16:55 node6
-rw-r--r--. 1 root root 193 Aug 5 16:57 readfirst.txt
-rw-r--r--. 1 root root 61797 May 16 00:07 redis.conf
[root@localhost redis]#
node1--node6 各redis节点
docker-compose.yml
redis.conf 默认redis配置
# bind 127.0.0.1 //加上注释#
protected-mode no //关闭保护模式
port 6061 //绑定自定义端口
#daemonize yes //禁止redis后台运行
pidfile /var/run/redis_6061.pid
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6061.conf //集群的配置 配置文件首次启动自动生成
配置文件是最容易出问题的,这里面有一些注意事项:
因为使用redis-trib连接集群时是不能指定密码的,如果开启了requirepass或者masterauth会导致集群连接失败,所以应该等集群创建好后再修改密码,这个后文会说
表示设置redis监听哪个ip,设置了监听之后,只有使用这些ip才能访问这个redis服务,不指定则默认所有ip都能访问该redis服务
注意:这里的ip指的是redis的ip而非访问方的ip,bind并不直接限制哪些ip能够访问redis,显示ip访问是限制监听后的效果,如果想限制ip访问应使用Linux防火墙功能.
比方说,在生产条件下的redis服务器有3个ip(外网ip 122.122.122.122,局域网ip192.128.0.1,本地ip127.0.0.1),则为了安全,bind后面只应该写局域网ip和本地ip,这样就只有局域网用户(包括本机)可以通过192.128.0.1访问redis服务,间接起到限制ip访问的作用.
作用:
禁止公网访问redis cache,加强redis安全的
启用条件:
没有bind IP
没有设置requirepass访问密码
解释:
由于前面提及的原因,保护模式会开启导致无法通过公网访问,故这里需要关闭保护模式,但注意集群建好后要及时添加密码,增强安全性
实测开启守护模式(daemonize yes)容器会启动失败,因为是使用docker,所以前台启动也没什么关系,pidfile的文件名和端口号一致是一个良好的习惯
#以node1为例
[root@localhost node1]# pwd
/apps/usr/redis/node1
[root@localhost node1]# more Dockerfile
#基础镜像
FROM redis
#将自定义conf文件拷入
COPY redis.conf /usr/local/etc/redis/redis.conf
#修复时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
#修改文件权限,使之可以通过config rewrite重写
RUN chmod 777 /usr/local/etc/redis/redis.conf
# Redis客户端连接端口
EXPOSE 6061
# 集群总线端口:redis客户端连接的端口 + 10000
EXPOSE 16061
#使用自定义conf启动
CMD [ "/usr/local/bin/redis-server", "/usr/local/etc/redis/redis.conf" ]
注意:
集群总线端口
Redis集群中每个redis实例(可能一台机部署多个实例)会使用两个Tcp端口,一个用于给客户端(redis-cli或应用程序等)使用的端口,另一个是用于集群中实例相互通信的内部总线端口,且第二个端口比第一个端口一定大10000.内部总线端口通信使用特殊协议,以便实现集群内部高带宽低时延的数据交换。所以配置redis实例时只需要指明第一个端口就可以了。
但是由于我们使用的是docker,所以要将这个端口暴露出来,否则集群无法建立(使用redis-trib时会一直显示Waiting for the cluster to join)
修改redis.conf文件权限,否则后面写入访问密码到文件的时候会提示Permission denied
[root@localhost redis]# pwd
/apps/usr/redis
[root@localhost redis]# more docker-compose.yml
version: '3.7'
services:
redis-node1:
build: ./node1
ports:
- 6061:6061
- 16061:16061
container_name: redis-node1
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.11 #指定固定IP
redis-node2:
build: ./node2
ports:
- 6062:6062
- 16062:16062
container_name: redis-node2
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.12
redis-node3:
build: ./node3
ports:
- 6063:6063
- 16063:16063
container_name: redis-node3
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.13
redis-node4:
build: ./node4
ports:
- 6064:6064
- 16064:16064
container_name: redis-node4
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.14
redis-node5:
build: ./node5
ports:
- 6065:6065
- 16065:16065
container_name: redis-node5
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.15
redis-node6:
build: ./node6
ports:
- 6066:6066
- 16066:16066
container_name: redis-node6
restart: always
tty: true
networks:
extnetwork:
ipv4_address: 172.19.0.16
networks:
extnetwork: #自定义网络环境
ipam:
config:
- subnet: 172.19.0.0/16
[root@localhost redis]#
在redis目录下(即docker-compose.yml同级目录),运行
[root@localhost redis]# pwd
/apps/usr/redis
[root@localhost redis]# docker-compose up -d
[root@localhost redis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22fe97cac263 redis_redis-node4 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6064->6064/tcp, 0.0.0.0:16064->16064/tcp, 6379/tcp redis_redis-node4_1
dc32229f2ac8 redis_redis-node2 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6062->6062/tcp, 0.0.0.0:16062->16062/tcp, 6379/tcp redis_redis-node2_1
3eb4661da9ed redis_redis-node1 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6061->6061/tcp, 0.0.0.0:16061->16061/tcp, 6379/tcp redis_redis-node1_1
e09f67c90dbf redis_redis-node5 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6065->6065/tcp, 0.0.0.0:16065->16065/tcp, 6379/tcp redis_redis-node5_1
671a4a880aa4 redis_redis-node6 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6066->6066/tcp, 0.0.0.0:16066->16066/tcp, 6379/tcp redis_redis-node6_1
995b9e97fa44 redis_redis-node3 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6063->6063/tcp, 0.0.0.0:16063->16063/tcp, 6379/tcp redis_redis-node3_1
cc244c275c49 zookeeper:3.5.3-beta "/docker-entrypoint.…" 5 weeks ago Up 2 hours 2888/tcp, 3888/tcp, 0.0.0.0:2183->2181/tcp zookeeper_3
a3ffc8080f04 zookeeper:3.5.3-beta "/docker-entrypoint.…" 5 weeks ago Up 2 hours 2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp zookeeper_1
03f34a88a2fb zookeeper:3.5.3-beta "/docker-entrypoint.…" 5 weeks ago Up 2 hours 2888/tcp, 3888/tcp, 0.0.0.0:2182->2181/tcp zookeeper_2
[root@localhost redis]#
可以看到此时请求访问密码和访问master密码是空白的,另外集群状态是失败
这个时候使用redis会报"CLUSTERDOWN Hash slot not served"
错误
在此首先需要查看redis各节点IP
[root@localhost redis]# docker ps
[root@localhost redis]# docker inspect 01527dfc2f31 9e5eb69610e8 975babd130bc e2b9d2b28470 aa00057c3319 9c2a1d4a40bd | grep -e "IPAddress" -e "Image"
"Image": "sha256:fac3b8c3d00f2e2d5477b30730b13253680d6349717142e1b460f834198f3cac",
"Image": "redis_redis-node6",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.16",
"Image": "sha256:f8f51e618508faa320a5826c95818a175b55805190439b4aa8548d6d9ca6c327",
"Image": "redis_redis-node1",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.11",
"Image": "sha256:a5b073f201f599c7752a8336474bfc4d71b60dac4a21bdeb818f2fca045084b2",
"Image": "redis_redis-node2",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.12",
"Image": "sha256:1ad0b65f20b1f0a3bcb5302fd741dffcb993c1eca36f59b0ba8dd28a7f0dc0b1",
"Image": "redis_redis-node4",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.14",
"Image": "sha256:17e8e50419bddda5a93c492f34888ef90d63139624422bc7a28c1b88f062951d",
"Image": "redis_redis-node3",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.13",
"Image": "sha256:5e7631cb5ebb869f26dba50dd781d05360139965a7d5ff7a6ff39cdafcc0fef3",
"Image": "redis_redis-node5",
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.15",
[root@localhost redis]#
创建集群
[root@localhost redis]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2514144f2710 bridge bridge local
8f18d5d4a41c host host local
f6adefbb5345 none null local
ab68814edfb8 redis_extnetwork bridge local
9273f18b5674 zookeeper_default bridge local
#ip 根据实际情况修改 --net 指定网络,注意网络名称
[root@localhost redis]# docker run -it --rm --net redis_extnetwork zvelo/redis-trib create --replicas 1 172.19.0.11:6061 172.19.0.12:6062 172.19.0.13:6063 172.19.0.14:6064 172.19.0.15:6065 172.19.0.16:6066
[root@localhost redis]# docker exec -it 9e5eb69610e8 /bin/bash
root@9e5eb69610e8:/data# n/
root@9e5eb69610e8:/usr/local/bin# ls
docker-entrypoint.sh gosu redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server
root@22fe97cac263:/usr/local/bin# ./redis-cli -c -p 6064
127.0.0.1:6064> 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
cluster_my_epoch:1
cluster_stats_messages_ping_sent:2463
cluster_stats_messages_pong_sent:2465
cluster_stats_messages_meet_sent:3
cluster_stats_messages_sent:4931
cluster_stats_messages_ping_received:2463
cluster_stats_messages_pong_received:2466
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:4931
127.0.0.1:6064>
使用redis-trib.rb工具构建集群,集群构建完成前不要配置密码,集群构建完毕再通过config set + config rewrite命令逐个机器设置密码
如果对集群设置密码,那么requirepass和masterauth都需要设置,否则发生主从切换时,就会遇到授权问题
各个节点的密码都必须一致,否则Redirected就会失败
#以一个节点为例
# -c 集群模式
./redis-cli -c -p 6061 -h 172.17.0.5
#
config set masterauth ****
config set requirepass ****
# 验证
auth ****
# 回写到配置文件
config rewrite
注:连通性,本地使用redis集群的连通性问题,参考windows连通CentOS虚拟机中的docker容器 开通172.17.0.0 网段