使用docker搭建伪集群

#!/bin/bash
# /usr/local/redis-cluster/deploy-cluster.sh

set -e

REDIS_CLUSTER_DIR="/usr/local/redis-cluster"
PORTS=(5001 5002 5003)

# 获取当前服务器的 IP 地址
SERVER_IP=$(hostname -I | awk '{print $1}')

REDIS_PASSWORD="Redis@12345"

echo "=== Redis集群部署开始 ==="
echo "部署配置:"
echo "   - 节点数量: ${#PORTS[@]}个主节点"
echo "   - 服务器IP: ${SERVER_IP}"
echo "   - 端口范围: ${PORTS[*]}"
echo "   - 数据目录: ${REDIS_CLUSTER_DIR}"
echo "----------------------------------------"

# 1. 停止并清理现有容器
echo "1. 清理现有容器..."
for port in "${PORTS[@]}"; do
	if docker stop "redis-cluster-${port}" 2>/dev/null; then
		echo "   已停止容器: redis-cluster-${port}"
	fi
	if docker rm "redis-cluster-${port}" 2>/dev/null; then
		echo "   已删除容器: redis-cluster-${port}"
	fi
done
echo "   容器清理完成"

# 2. 清理数据文件
echo "2. 清理旧数据文件..."
for port in "${PORTS[@]}"; do
	rm -rf "${REDIS_CLUSTER_DIR}/${port}/data/*" 2>/dev/null || true
	rm -f "${REDIS_CLUSTER_DIR}/${port}/data/nodes.conf" 2>/dev/null || true
	rm -f "${REDIS_CLUSTER_DIR}/${port}/data/appendonly.aof" 2>/dev/null || true
	rm -f "${REDIS_CLUSTER_DIR}/${port}/data/dump.rdb" 2>/dev/null || true
	echo "   已清理节点 ${port} 数据"
done

# 创建目录结构
echo "3. 创建目录结构..."
for port in "${PORTS[@]}"; do
	mkdir -p "${REDIS_CLUSTER_DIR}/${port}/conf"
	mkdir -p "${REDIS_CLUSTER_DIR}/${port}/data"
	chmod -R 644 "${REDIS_CLUSTER_DIR}/${port}/data"
	chmod -R 744 "${REDIS_CLUSTER_DIR}/${port}/data"
	chown -R 1001:1001 "${REDIS_CLUSTER_DIR}/${port}/data" 2>/dev/null || true
	echo "   已创建目录: ${REDIS_CLUSTER_DIR}/${port}/{conf,data}"
done

# 4. 创建配置文件
echo "4. 生成配置文件..."
for port in "${PORTS[@]}"; do
	cat >"${REDIS_CLUSTER_DIR}/${port}/conf/redis.conf" <<EOF
# Redis集群配置
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip ${SERVER_IP}
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}

# 密码认证
requirepass ${REDIS_PASSWORD}
masterauth ${REDIS_PASSWORD}

# 持久化配置
appendonly yes
appendfsync everysec
dir /data
save 900 1
save 300 10
save 60 10000

# 网络配置
bind 0.0.0.0
protected-mode no
timeout 0
tcp-keepalive 300

# 内存管理
maxmemory 4gb
maxmemory-policy allkeys-lru

# 日志配置
daemonize no
loglevel verbose
logfile ""

# 客户端配置
maxclients 10000

# 性能配置
activerehashing yes
EOF
	echo "   已生成节点 ${port} 配置文件"
done

# 5. 启动Redis容器
echo "5. 启动Docker容器..."
for port in "${PORTS[@]}"; do
	echo "   启动节点 ${port} ..."

	if docker run -d \
		--name "redis-cluster-${port}" \
		--net host \
		-v "${REDIS_CLUSTER_DIR}/${port}/data:/data" \
		-v "${REDIS_CLUSTER_DIR}/${port}/conf/redis.conf:/etc/redis/redis.conf" \
		-v "/etc/localtime:/etc/localtime:ro" \
		--restart unless-stopped \
		docker.1ms.run/library/redis:7.4.5 \
		redis-server /etc/redis/redis.conf; then
		echo "   节点 ${port} 容器启动成功"
	else
		echo "   节点 ${port} 容器启动失败"
		exit 1
	fi
done

# 6. 等待节点启动
echo "6. 等待节点启动..."
TIMEOUT=300
INTERVAL=5
ELAPSED_TIME=0
ALL_NODES_READY=false

while [ $ELAPSED_TIME -lt $TIMEOUT ]; do
	ALL_NODES_READY=true
	for port in "${PORTS[@]}"; do
		if ! docker exec "redis-cluster-${port}" redis-cli --no-auth-warning -p ${port} -a ${REDIS_PASSWORD} ping 2>/dev/null | grep -q "PONG"; then
			ALL_NODES_READY=false
			break
		fi
	done

	if [ "$ALL_NODES_READY" = true ]; then
		echo "   所有节点已准备好"
		break
	fi

	sleep $INTERVAL
	ELAPSED_TIME=$((ELAPSED_TIME + INTERVAL))
	echo "   等待节点启动... (已等待 ${ELAPSED_TIME} 秒)"
done

if [ "$ALL_NODES_READY" = false ]; then
	echo "   超时:节点未能在 ${TIMEOUT} 秒内启动"
	exit 1
fi

# 7. 检查节点状态
echo "7. 检查节点状态:"
ALL_NODES_READY=true
for port in "${PORTS[@]}"; do
	if docker exec "redis-cluster-${port}" redis-cli --no-auth-warning -p ${port} -a ${REDIS_PASSWORD} ping 2>/dev/null | grep -q "PONG"; then
		echo "   节点 ${port} Redis服务正常"
	else
		echo "   节点 ${port} Redis服务异常"
		docker logs "redis-cluster-${port}" | tail -5
		ALL_NODES_READY=false
	fi
done

if [ "$ALL_NODES_READY" = false ]; then
	echo "节点启动检查失败,请查看日志"
	exit 1
fi

# 8. 创建Redis集群
echo "8. 创建Redis集群..."
echo "   正在组建集群,请稍候..."
# 构建 Redis 集群创建命令
CLUSTER_NODES=""
for port in "${PORTS[@]}"; do
	CLUSTER_NODES="${CLUSTER_NODES} ${SERVER_IP}:${port}"
done

# 执行集群创建
docker exec redis-cluster-5001 redis-cli -p 5001 -a ${REDIS_PASSWORD} --no-auth-warning --cluster create \
	$CLUSTER_NODES --cluster-replicas 0 --cluster-yes && echo "集群创建成功" || echo "集群创建失败,请检查"

# 9. 等待集群稳定
echo "9. 等待集群稳定"
sleep 5

# 10. 验证集群状态
echo "10. 验证集群状态:"
echo "----------------------------------------"
CLUSTER_HEALTHY=true
for port in "${PORTS[@]}"; do
	# 获取集群信息,并删除多余的换行符
	cluster_info=$(docker exec "redis-cluster-${port}" redis-cli -p ${port} -a ${REDIS_PASSWORD} --no-auth-warning CLUSTER INFO 2>/dev/null || echo "无法获取集群信息")

	# 提取集群状态和槽位信息
	cluster_state=$(echo "$cluster_info" | grep 'cluster_state:' | cut -d: -f2 | tr -d '[:space:]' || echo "unknown")
	cluster_slots_ok=$(echo "$cluster_info" | grep 'cluster_slots_ok:' | cut -d: -f2 | tr -d '[:space:]' || echo "0")
	cluster_slots_assigned=$(echo "$cluster_info" | grep 'cluster_slots_assigned:' | cut -d: -f2 | tr -d '[:space:]' || echo "0")

	# 清除可能存在的非数字字符(如 k,m)
	cluster_slots_assigned=$(echo $cluster_slots_assigned | sed 's/[^0-9]*//g')
	cluster_slots_ok=$(echo $cluster_slots_ok | sed 's/[^0-9]*//g')

	# 输出调试信息
	echo "   [节点 ${port}] cluster_state=$cluster_state, cluster_slots_ok=$cluster_slots_ok, cluster_slots_assigned=$cluster_slots_assigned"

	# 检查集群状态和槽位是否正常
	if [ "$cluster_state" = "ok" ] && [ "$cluster_slots_ok" = "16384" ] && [ "$cluster_slots_assigned" = "16384" ]; then
		echo "节点 ${port}: 状态正常 | 槽位: ${cluster_slots_ok}/16384"
	else
		echo "节点 ${port}: 状态: ${cluster_state} | 槽位: ${cluster_slots_ok}/16384"
		CLUSTER_HEALTHY=false
	fi
	sleep 1
done
echo "----------------------------------------"
if [ "$CLUSTER_HEALTHY" = true ]; then
	echo "=== Redis集群部署成功! ==="
else
	echo "=== Redis集群部署完成,但有警告 ==="
fi

# 11. 显示连接信息
echo ""
echo "连接信息:"
echo "----------------------------------------"
for port in "${PORTS[@]}"; do
	echo "节点${port}: redis-cli -c -h ${SERVER_IP} -p ${port} -a ${REDIS_PASSWORD}"
done

echo ""
echo "管理命令:"
echo "----------------------------------------"
echo "查看集群节点: redis-cli -c -h ${SERVER_IP} -p 5001 -a ${REDIS_PASSWORD} CLUSTER NODES"
echo "查看集群信息: redis-cli -c -h ${SERVER_IP} -p 5001 -a ${REDIS_PASSWORD} CLUSTER INFO"
echo "测试写入:     redis-cli -c -h ${SERVER_IP} -p 5001 -a ${REDIS_PASSWORD} SET test_key 'hello cluster'"
echo "测试读取:     redis-cli -c -h ${SERVER_IP} -p 5002 -a ${REDIS_PASSWORD} GET test_key"

echo ""
echo "数据目录:"
echo "----------------------------------------"
for port in "${PORTS[@]}"; do
	echo "节点${port}: ${REDIS_CLUSTER_DIR}/${port}/data/"
done

echo ""
echo "部署时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"

posted @ 2025-08-25 21:19  自由散漫  阅读(8)  评论(0)    收藏  举报