#keepalived
Keepalived提供了兼具负载均衡和高可用性的框架
这里以mysql的主从切换为例,实现了从节点自动切换为主库(从节点检测主节点keepalived心跳)
#主节点
/etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id MYSQL_MASTER # 标识主节点,唯一即可
}
# 定义 MySQL 检测脚本
vrrp_script check_mysql {
script "/data/app/mysql/keepalived_check_mysql.sh" # 检测脚本路径
interval 5 # 检测间隔(秒)
fall 5 # 连续5次失败,判定为故障
rise 1 # 连续1次成功,恢复正常
}
# VRRP 实例(核心:关闭 IP 漂移)
vrrp_instance VI_1 {
state MASTER # 主节点标识
interface eth0 # 网卡名称(根据实际修改,如 ens33)
virtual_router_id 51 # VRRP 组 ID(主从必须一致,0-255)
priority 100 # 主节点优先级(高于从节点)
advert_int 1 # 心跳发送间隔(秒)
nopreempt # 关闭抢占(避免主恢复后抢回主身份,可选)
# 单播模式
# 自己 IP
unicast_src_ip 10.33.9.38
# 从节点 IP
unicast_peer {
10.33.9.39
}
# 关联检测脚本
track_script {
check_mysql
}
# 当进入故障状态(即连续失败 2 次后)执行此脚本
notify_fault "/data/app/mysql/stop_keepalived.sh"
}/data/app/mysql/keepalived_check_mysql.sh
#!/bin/bash
# 配置项
MYSQL_USER="root"
MYSQL_PWD="password"
MYSQL_PORT="3306"
MYSQL_FOLDER="/data/app/mysql"
LOG_FILE="${MYSQL_FOLDER}/log-${MYSQL_PORT}/keepalived_mysql.log"
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> ${LOG_FILE}
}
# 检测 MySQL 存活
docker run -i -v ${MYSQL_FOLDER}/data-${MYSQL_PORT}/mysql/mysql.sock:/tmp/mysql.sock --rm mysql:8.0 mysqladmin -u${MYSQL_USER} -p${MYSQL_PWD} -S /tmp/mysql.sock ping > /dev/null 2>&1
if [ $? -ne 0 ]; then
log "MySQL 主库故障(ping 失败)"
exit 1
else
log "MySQL 主库运行正常"
exit 0
fi
/data/app/mysql/stop_keepalived.sh
#!/bin/bash
LOG_FILE="/data/logs/keepalived.log"
mkdir -p /data/logs/
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> ${LOG_FILE}
}
# 停止 Keepalived,停止发送 VRRP 心跳
systemctl stop keepalived
log "Keepalived 已停止,主节点心跳终止"
exit 1
#从节点
/etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id MYSQL_SLAVE
}
vrrp_instance VI_1 {
state BACKUP # 固定为备节点
interface eth0 # 与主节点一致的网卡
virtual_router_id 51 # 与主节点一致
priority 90 # 优先级低于主节点
advert_int 1 # 心跳间隔1秒
# 单播模式
# 自己 IP
unicast_src_ip 10.33.9.39
# 主节点 IP
unicast_peer {
10.33.9.38
}
# 核心:成为主节点时执行升主脚本
notify_master "/data/app/mysql/promote_to_master.sh"
}/data/app/mysql/promote_to_master.sh
#!/bin/bash
# 配置项
MYSQL_USER="root"
MYSQL_PWD="password"
MYSQL_PORT="3306"
MYSQL_FOLDER="/data/app/mysql"
LOG_FILE="${MYSQL_FOLDER}/log-${MYSQL_PORT}/keepalived_mysql.log"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> ${LOG_FILE}
}
# 防止重复执行(加锁)
LOCK_FILE="/tmp/mysql_promote.lock"
if [ -f ${LOCK_FILE} ]; then
log "升主脚本已在执行,跳过"
exit 0
fi
touch ${LOCK_FILE}
# 检测 MySQL 存活
docker run -i -v ${MYSQL_FOLDER}/data-${MYSQL_PORT}/mysql/mysql.sock:/tmp/mysql.sock --rm mysql:8.0 mysqladmin -u${MYSQL_USER} -p${MYSQL_PWD} -S /tmp/mysql.sock ping > /dev/null 2>&1
if [ $? -ne 0 ]; then
log "MySQL 从库故障(ping 失败),不切换成主库"
exit 1
else
# 核心:MySQL 升主 SQL
log "开始执行升主操作..."
docker run -i -v ${MYSQL_FOLDER}/data-${MYSQL_PORT}/mysql/mysql.sock:/tmp/mysql.sock --rm mysql:8.0 \
mysql -u${MYSQL_USER} -p${MYSQL_PWD} -S /tmp/mysql.sock -e "
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;
" >> ${LOG_FILE} 2>&1
log "升主完成"
rm -f ${LOCK_FILE}
exit 0
fi
