Docker环境下安装redis哨兵模式
# 环境
docker
docker-compse
# 目录结构
.
├── docker-compose.yaml
├── redis01
│ └── conf
│ └── redis.conf
├── redis02
│ └── conf
│ └── redis.conf
├── redis03
│ └── conf
│ └── redis.conf
├── sentinel01
│ └── conf
│ └── redis.conf
├── sentinel02
│ └── conf
│ └── redis.conf
└── sentinel03
└── conf
└── redis.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置文件
docker-compose.yaml
version: '3'
services:
redis01:
image: redis
container_name: redis01
restart: always
ports:
- 6379:6379
volumes:
- ./redis01/data:/data
- ./redis01/conf/:/usr/local/etc/redis/conf/
command: ["redis-server","/usr/local/etc/redis/conf/redis.conf"]
networks:
redis-cluster-net:
ipv4_address: 172.18.0.21
redis02:
image: redis
container_name: redis02
restart: always
ports:
- 6380:6379
volumes:
- ./redis02/data:/data
- ./redis02/conf/:/usr/local/etc/redis/conf/
command: ["redis-server","/usr/local/etc/redis/conf/redis.conf"]
networks:
redis-cluster-net:
ipv4_address: 172.18.0.22
depends_on:
- 'redis01'
redis03:
image: redis
container_name: redis03
restart: always
ports:
- 6381:6379
volumes:
- ./redis03/data:/data
- ./redis03/conf/:/usr/local/etc/redis/conf/
command: ["redis-server","/usr/local/etc/redis/conf/redis.conf"]
networks:
redis-cluster-net:
ipv4_address: 172.18.0.23
depends_on:
- 'redis01'
redis-sentinel-01:
image: redis
container_name: redis-sentinel-01
volumes:
- ./sentinel01/data:/data
- ./sentinel01/conf/:/etc/redis/conf/
command: redis-sentinel /etc/redis/conf/redis.conf
restart: always
depends_on:
- 'redis01'
- 'redis02'
- 'redis03'
networks:
redis-cluster-net:
ipv4_address: 172.18.0.24
redis-sentinel-02:
image: redis
container_name: redis-sentinel-02
volumes:
- ./sentinel02/data:/data
- ./sentinel02/conf/:/etc/redis/conf/
command: redis-sentinel /etc/redis/conf/redis.conf
restart: always
depends_on:
- 'redis01'
- 'redis02'
- 'redis03'
networks:
redis-cluster-net:
ipv4_address: 172.18.0.25
redis-sentinel-03:
image: redis
container_name: redis-sentinel-03
volumes:
- ./sentinel03/data:/data
- ./sentinel03/conf/:/etc/redis/conf/
command: redis-sentinel /etc/redis/conf/redis.conf
restart: always
depends_on:
- 'redis01'
- 'redis02'
- 'redis03'
networks:
redis-cluster-net:
ipv4_address: 172.18.0.26
networks:
redis-cluster-net:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
redis01的配置文件conf/redis.conf
port 6379
bind 0.0.0.0
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /data
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-min-size 10M
auto-aof-rewrite-percentage 100
# 使用docker的方式时不设置这个不能同步数据
repl-diskless-load on-empty-db
logfile "redis.log"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
redis02、redis03的配置文件conf/redis.conf
port 6379
bind 0.0.0.0
save ""
dbfilename "dump.rdb"
dir "/data"
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-min-size 10000000
auto-aof-rewrite-percentage 100
# 使用docker的方式时不设置这个不能同步数据
repl-diskless-load on-empty-db
replica-read-only yes
replicaof redis01 6379
logfile "redis.log"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sentinel01的配置文件conf/redis.conf
port 6379
bind 0.0.0.0
logfile "sentinel.log"
sentinel monitor mymaster 172.18.0.21 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel resolve-hostnames yes
sentinel announce-ip "redis-sentinel-01"
sentinel announce-port 6379
sentinel deny-scripts-reconfig yes
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
sentinel02的配置文件conf/redis.conf
port 6379
bind 0.0.0.0
logfile "sentinel.log"
sentinel monitor mymaster 172.18.0.21 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel resolve-hostnames yes
sentinel announce-ip "redis-sentinel-02"
sentinel announce-port 6379
sentinel deny-scripts-reconfig yes
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
sentinel03的配置文件conf/redis.conf
port 6379
bind 0.0.0.0
logfile "sentinel.log"
sentinel monitor mymaster 172.18.0.21 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel resolve-hostnames yes
sentinel announce-ip "redis-sentinel-03"
sentinel announce-port 6379
sentinel deny-scripts-reconfig yes
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 启动redis
~/docker/redis$ docker-compose up -d
Creating network "redis_redis-cluster-net" with driver "bridge"
Creating redis01 ... done
Creating redis02 ... done
Creating redis03 ... done
Creating redis-sentinel-02 ... done
Creating redis-sentinel-03 ... done
Creating redis-sentinel-01 ... done
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
~/docker/redis$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e4024697bd4f redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 6379/tcp redis-sentinel-01
c8640976e687 redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 6379/tcp redis-sentinel-03
aaa145ee38af redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 6379/tcp redis-sentinel-02
7cd618c968a8 redis "docker-entrypoint.s…" 4 seconds ago Up 4 seconds 0.0.0.0:6381->6379/tcp, :::6381->6379/tcp redis03
f97cb04149d0 redis "docker-entrypoint.s…" 4 seconds ago Up 4 seconds 0.0.0.0:6380->6379/tcp, :::6380->6379/tcp redis02
782250c395ce redis "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis01
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 查看集群信息
~/docker/redis$ docker exec -it 782250c395ce bash
root@782250c395ce:/data# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.18.0.23,port=6379,state=online,offset=59780,lag=0
slave1:ip=172.18.0.22,port=6379,state=online,offset=59638,lag=1
master_failover_state:no-failover
master_replid:d295101efb7dc5bac96f98e8d0b40cc209271f29
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:59780
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:59780
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
以上在master节点上的操作证明redis的主从服务已经可用。
~/docker/redis$ docker exec -it f97cb04149d0 bash
root@f97cb04149d0:/data# redis-cli
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379>
1
2
3
4
5
2
3
4
5
redis02,从库的服务也可以正确获取数据。
# 触发选举
我们模拟master宕机
~/docker/redis$ docker stop 2cd84318537b
2cd84318537b
yds@yds:~/docker/redis$ sudo tail -f sentinel01/data/sentinel.log
1:X 11 Mar 2024 10:15:52.794 # +try-failover master mymaster 172.18.0.21 6379
1:X 11 Mar 2024 10:15:52.825 * Sentinel new configuration saved on disk
1:X 11 Mar 2024 10:15:52.825 # +vote-for-leader 4ad9233dcaafe88d16dd011eb2cd2a55dea48f5d 1
1:X 11 Mar 2024 10:15:52.831 * 9caa482bc52fdb5d8253fab554c1195d22413e35 voted for 9caa482bc52fdb5d8253fab554c1195d22413e35 1
1:X 11 Mar 2024 10:15:52.841 * 89e3f7246033a1a4cb7c9415ec2af98d8e15cf2d voted for 9caa482bc52fdb5d8253fab554c1195d22413e35 1
1:X 11 Mar 2024 10:15:53.744 # +config-update-from sentinel 9caa482bc52fdb5d8253fab554c1195d22413e35 172.18.0.25 6379 @ mymaster 172.18.0.21 6379
1:X 11 Mar 2024 10:15:53.744 # +switch-master mymaster 172.18.0.21 6379 172.18.0.23 6379
1:X 11 Mar 2024 10:15:53.744 * +slave slave 172.18.0.22:6379 172.18.0.22 6379 @ mymaster 172.18.0.23 6379
1:X 11 Mar 2024 10:15:53.744 * +slave slave 172.18.0.21:6379 172.18.0.21 6379 @ mymaster 172.18.0.23 6379
1:X 11 Mar 2024 10:15:53.754 * Sentinel new configuration saved on disk
1:X 11 Mar 2024 10:16:03.775 # +sdown slave 172.18.0.21:6379 172.18.0.21 6379 @ mymaster 172.18.0.23 6379
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
可以看到日志中已经重新选举出了master节点
# 选举后的服务状态
sentinel的配置文件
~/docker/redis$ sudo cat sentinel01/conf/redis.conf
port 6379
bind 0.0.0.0
logfile "sentinel.log"
sentinel monitor mymaster 172.18.0.23 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel resolve-hostnames yes
sentinel announce-ip "redis-sentinel-01"
sentinel announce-port 6379
sentinel deny-scripts-reconfig yes
# Generated by CONFIG REWRITE
dir "/data"
latency-tracking-info-percentiles 50 99 99.9
user default on nopass sanitize-payload ~* &* +@all
sentinel myid 4ad9233dcaafe88d16dd011eb2cd2a55dea48f5d
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel current-epoch 1
sentinel known-sentinel mymaster 172.18.0.25 6379 9caa482bc52fdb5d8253fab554c1195d22413e35
sentinel known-sentinel mymaster 172.18.0.26 6379 89e3f7246033a1a4cb7c9415ec2af98d8e15cf2d
sentinel known-replica mymaster 172.18.0.22 6379
sentinel known-replica mymaster 172.18.0.21 6379
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
可以看到sentinel的配置文件自动被修改了。
~/docker/redis$ docker exec -it c20b1fd56403 bash
root@c20b1fd56403:/data# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.18.0.22,port=6379,state=online,offset=68805,lag=1
master_failover_state:no-failover
master_replid:4cbae7f9ac3fd43866f51443946889d385000768
master_replid2:1c32eda737790ea747eeb517b274478b53a0696e
master_repl_offset:68947
second_repl_offset:6905
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:876
repl_backlog_histlen:68072
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
redis03已经被选举成了master,数据也没有问题。
# 网络恢复
~/docker/redis$ docker start 2cd84318537b
2cd84318537b
yds@yds:~/docker/redis$ docker exec -it c20b1fd56403 bash
root@c20b1fd56403:/data# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.18.0.22,port=6379,state=online,offset=114278,lag=0
slave1:ip=172.18.0.21,port=6379,state=online,offset=114278,lag=0
master_failover_state:no-failover
master_replid:4cbae7f9ac3fd43866f51443946889d385000768
master_replid2:1c32eda737790ea747eeb517b274478b53a0696e
master_repl_offset:114278
second_repl_offset:6905
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:876
repl_backlog_histlen:113403
127.0.0.1:6379>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可以看到原来宕机的redis01恢复过来以后,是以slave的身份加入了集群。
# 过程中可能遇到的问题
could not rename tmp config file (device or resource busy)
1
这个问题是因为配置文件挂载的时候,可能在docker-compose.yaml
是文件和文件之间的直接映射,修改成文件夹和文件夹的映射就好了。
❌./sentinel03/conf/redis.conf:/etc/redis/conf/redis.conf
✅./sentinel03/conf/:/etc/redis/conf/
关于docker内部容器之间的网络访问
docker容器在同一个网络下是可以通过服务名来访问的,
如从机的配置“replicaof redis01 6379”,这里的“redis01”就是master节点的服务名。
但是在文章中可以看到在docker-compose中使用了静态ip的方式,这是因为在配置sentinel时,
“sentinel monitor mymaster 172.18.0.21 6379 2”该项配置中的master主机ip“172.18.0.21”
我尝试过使用“redis01”来代替,如果发生了选举的行为,日志中会显示不能解析到它,
尽管我设置了“sentinel resolve-hostnames yes”,
但是“sentinel announce-ip "redis-sentinel-01"”该项配置倒是没有出现问题。
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
上次更新: 2024/09/30, 01:34:11