Appearance
Docker Compose 部署 Redis 集群
1. bridge 网络版
1.1. .env
Properties
REDIS_VERSION=7.4.2
CONTAINER_CONF_PATH=/usr/local/etc/redis
HOST_IP=192.168.163.129
DOCKER_NETWORK_SUBNET=172.118.0.0/16
DOCKER_NETWORK_GATEWAY=172.118.0.254
DOCKER_NETWORK_IP_PREFIX=172.118.0.1
2
3
4
5
6
2
3
4
5
6
1.2. compose.yaml
YAML
name: redis-cluster
services:
redis1:
image: redis:${REDIS_VERSION}
container_name: redis1
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}1
ports:
- "6371:6379"
- "16371:16379"
volumes:
- "./redis1/data:/data"
- "./redis1/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
redis2:
image: redis:${REDIS_VERSION}
container_name: redis2
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}2
ports:
- "6372:6379"
- "16372:16379"
volumes:
- "./redis2/data:/data"
- "./redis2/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
redis3:
image: redis:${REDIS_VERSION}
container_name: redis3
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}3
ports:
- "6373:6379"
- "16373:16379"
volumes:
- "./redis3/data:/data"
- "./redis3/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
redis4:
image: redis:${REDIS_VERSION}
container_name: redis4
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}4
ports:
- "6374:6379"
- "16374:16379"
volumes:
- "./redis4/data:/data"
- "./redis4/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
redis5:
image: redis:${REDIS_VERSION}
container_name: redis5
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}5
ports:
- "6375:6379"
- "16375:16379"
volumes:
- "./redis5/data:/data"
- "./redis5/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
redis6:
image: redis:${REDIS_VERSION}
container_name: redis6
networks:
redis-cluster:
ipv4_address: ${DOCKER_NETWORK_IP_PREFIX}6
ports:
- "6376:6379"
- "16376:16379"
volumes:
- "./redis6/data:/data"
- "./redis6/conf:${CONTAINER_CONF_PATH}"
command: sh -c "chown -R redis:redis ${CONTAINER_CONF_PATH} && redis-server ${CONTAINER_CONF_PATH}/redis.conf"
restart: on-failure:3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
start_period: 10s
networks:
redis-cluster:
external: true1.3. config-network.sh
Bash
#!/bin/bash
set -eo pipefail
# 导入环境变量
echo "Sourcing environments ..."
set -a
source .env
set +a
# 创建 Docker 网络
if [ -z $(docker network ls --filter name=^redis-cluster$ --format '{{.Name}}') ]; then
echo "Creating docker network: redis-cluster"
docker network create -d bridge --subnet ${DOCKER_NETWORK_SUBNET} --gateway ${DOCKER_NETWORK_GATEWAY} redis-cluster
else
echo "Docker network 'redis-cluster' is already existed"
fi
# 配置 iptables
echo "Configuring iptables"
# 先删除
set +e
iptables -t nat -D PREROUTING -m addrtype --dst-type LOCAL -j REDIS-CLUSTER-PREROUTING 2>/dev/null
iptables -t nat -D POSTROUTING -j REDIS-CLUSTER-POSTROUTING 2>/dev/null
iptables -t nat -F REDIS-CLUSTER-PREROUTING 2>/dev/null
iptables -t nat -F REDIS-CLUSTER-POSTROUTING 2>/dev/null
iptables -t nat -X REDIS-CLUSTER-PREROUTING 2>/dev/null
iptables -t nat -X REDIS-CLUSTER-POSTROUTING 2>/dev/null
set -e
# 再重建
iptables -t nat -N REDIS-CLUSTER-PREROUTING
iptables -t nat -N REDIS-CLUSTER-POSTROUTING
for idx in $(seq 1 6); do
iptables -t nat -A REDIS-CLUSTER-PREROUTING -s ${DOCKER_NETWORK_SUBNET} -d ${HOST_IP} -p tcp --dport 637${idx} -j DNAT --to-destination ${DOCKER_NETWORK_IP_PREFIX}${idx}:6379
iptables -t nat -A REDIS-CLUSTER-PREROUTING -s ${DOCKER_NETWORK_SUBNET} -d ${HOST_IP} -p tcp --dport 1637${idx} -j DNAT --to-destination ${DOCKER_NETWORK_IP_PREFIX}${idx}:16379
iptables -t nat -A REDIS-CLUSTER-POSTROUTING -s ${DOCKER_NETWORK_SUBNET} -d ${DOCKER_NETWORK_IP_PREFIX}${idx} -p tcp --dport 6379 -j MASQUERADE
iptables -t nat -A REDIS-CLUSTER-POSTROUTING -s ${DOCKER_NETWORK_SUBNET} -d ${DOCKER_NETWORK_IP_PREFIX}${idx} -p tcp --dport 16379 -j MASQUERADE
done
iptables -t nat -A POSTROUTING -j REDIS-CLUSTER-POSTROUTING
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j REDIS-CLUSTER-PREROUTING
echo "Network configuration successful."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
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
1.4. build.sh
Bash
#!/bin/bash
set -eo pipefail
PARSED=$(getopt -o '' -l admin-password:,replicator-password: -n "${0##*/}" -- "$@") || {
echo "Failed to parse options." >&2
exit 1
}
eval set -- "$PARSED"
admin_password=""
replicator_password=""
while [ "$1" != "--" ]; do
case "$1" in
--admin-password) admin_password="$2"; shift 2 ;;
--replicator-password) replicator_password="$2"; shift 2 ;;
*) echo "Invalid option: $1" >&2; exit 1 ;;
esac
done
shift # 跳过 --
[ -z "$admin_password" ] && { echo "'--admin-password' option is required" >&2; exit 1; }
[ -z "$replicator_password" ] && { echo "'--replicator-password' option is required" >&2; exit 1; }
# 导入环境变量
echo "Sourcing environments ..."
set -a
source .env
set +a
# 批量创建各节点文件夹及 redis.conf、users.acl 文件
for idx in $(seq 1 6); do
echo "Creating redis ${idx} configuration files"
mkdir -p redis${idx}/conf
touch redis${idx}/conf/redis.conf
touch redis${idx}/conf/users.acl
cat << EOF > redis${idx}/conf/redis.conf
bind 0.0.0.0
port 6379
requirepass ""
aclfile ${CONTAINER_CONF_PATH}/users.acl
cluster-enabled yes
cluster-config-file ${CONTAINER_CONF_PATH}/nodes.conf
cluster-announce-ip ${HOST_IP}
cluster-announce-port 637${idx}
cluster-announce-bus-port 1637${idx}
masteruser replicator
masterauth ${replicator_password}
EOF
cat << EOF > redis${idx}/conf/users.acl
user default off
user admin on >${admin_password} ~* +@all
user replicator on >${replicator_password} ~* +@all
EOF
done
# 配置网络
./config-network.sh
wait_for_healthy() {
for container in ${@:-$(docker compose ps --format '{{.Name}}' 2>/dev/null)}; do
until [ "$(docker inspect -f '{{.State.Health.Status}}' "$container")" == "healthy" ]; do
echo "Waiting for $container container to be healthy ..."
sleep 1
done
done
}
# 启动所有实例
echo "Staring services ..."
docker compose up -d
wait_for_healthy
# 搭建集群
echo "Building cluster ..."
docker compose exec \
redis1 \
redis-cli \
--user admin \
--pass ${admin_password} \
--cluster create \
${HOST_IP}:6371 \
${HOST_IP}:6372 \
${HOST_IP}:6373 \
${HOST_IP}:6374 \
${HOST_IP}:6375 \
${HOST_IP}:6376 \
--cluster-replicas 1
echo "Built successful."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
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
1.5. 搭建集群
Bash
$ sudo ./build.sh \
--admin-password q33ENfarK4f2nhkNu53T \
--replicator-password 5NkLQ0Y4ZAX2ZPJXZM871.6. 运行
Bash
$ sudo ./config-network.sh && sudo docker compose up -d