Keepalived 主备—双主案例
Keepalived 笔记
适用版本:Keepalived 2.x | 系统:CentOS 8 / Ubuntu 22.04
目录
1. 简介
Keepalived 基于 VRRP 协议(Virtual Router Redundancy Protocol)实现服务器高可用,核心功能是管理一个虚拟 IP(VIP),在多台服务器之间自动漂移,对外始终提供同一个 IP 地址。
典型用途:
- HAProxy / Nginx 双机热备
- LVS 高可用
- 任意服务的 IP 层冗余
工作原理:
正常状态:
VIP 192.168.1.100 → MASTER(优先级高)
BACKUP 静默监听心跳
主节点故障:
BACKUP 超时未收到心跳 → 接管 VIP(约 3~6 秒)
主节点恢复:
MASTER 重新广播 → 抢占 VIP(可配置是否抢占)
2. 安装
# CentOS / RHEL
dnf install keepalived -y
# Ubuntu / Debian
apt install keepalived -y
# 验证版本
keepalived --version
# 启用并启动
systemctl enable --now keepalived
3. 配置文件结构
主配置文件:/etc/keepalived/keepalived.conf
keepalived.conf
├── global_defs # 全局参数
├── vrrp_script # 健康检查脚本(可多个)
└── vrrp_instance # VRRP 实例(可多个,对应多个 VIP)
4. VRRP 核心概念
| 概念 | 说明 |
|---|---|
virtual_router_id |
VRRP 组 ID,同组主备必须一致,取值 1~255 |
priority |
优先级,越高越优先成为 MASTER,取值 1~254 |
state |
初始角色:MASTER 或 BACKUP |
advert_int |
心跳发送间隔(秒),默认 1 秒 |
virtual_ipaddress |
VIP 地址,可配置多个 |
interface |
绑定的网卡名称 |
preempt / nopreempt |
是否抢占,默认抢占 |
authentication |
同组节点认证,防止误加入 |
优先级与选举规则:
- 优先级高的节点成为 MASTER
- 优先级相同时,IP 地址大的优先
weight配合vrrp_script动态调整优先级
5. 基础实战:从零搭建主备高可用
本节以两台 CentOS 8 虚拟机为例,手把手完成一次完整的 Keepalived 主备部署,涵盖环境准备、安装、配置、验证全流程。
5.1 实验环境
| 角色 | IP | 主机名 | 说明 |
|---|---|---|---|
| MASTER | 192.168.1.1 | node1 | 主节点,正常持有 VIP |
| BACKUP | 192.168.1.2 | node2 | 备节点,主节点故障时接管 |
| VIP | 192.168.1.100 | — | 对外服务的虚拟 IP |
| 网卡 | eth0 | — | 两台机器同网段 |
两台机器需在同一局域网/VLAN,能互相 ping 通。
5.2 第一步:环境准备
两台机器都执行:
# 设置主机名(node1 上执行)
hostnamectl set-hostname node1
# 设置主机名(node2 上执行)
hostnamectl set-hostname node2
# 互相添加 hosts 解析(两台都执行)
cat >> /etc/hosts << EOF
192.168.1.1 node1
192.168.1.2 node2
EOF
# 验证互通
ping -c 3 node2 # 在 node1 上执行
ping -c 3 node1 # 在 node2 上执行
查看本机网卡名(后续配置需要):
ip addr
# 找到对应网段的网卡名,如 eth0 / ens33 / enp0s3
放行 VRRP 协议(两台都执行):
# CentOS / firewalld
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
firewall-cmd --list-all | grep vrrp # 确认已生效
# Ubuntu / ufw
iptables -A INPUT -p 112 -j ACCEPT
iptables -A OUTPUT -p 112 -j ACCEPT
5.3 第二步:安装 Keepalived
两台机器都执行:
# CentOS 8
dnf install keepalived -y
# Ubuntu
apt install keepalived -y
# 验证安装
keepalived --version
5.4 第三步:编写健康检查脚本
本实验用 Nginx 作为被守护的服务。
两台机器都执行:
# 安装 Nginx
dnf install nginx -y # CentOS
# apt install nginx -y # Ubuntu
# 启动 Nginx
systemctl enable --now nginx
# 确认 Nginx 正常
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1
# 输出 200 表示正常
创建健康检查脚本(两台都执行):
cat > /etc/keepalived/check_nginx.sh << 'EOF'
#!/bin/bash
# 检查 Nginx 是否存活,失败时尝试重启
if systemctl is-active nginx > /dev/null 2>&1; then
exit 0
else
systemctl restart nginx
sleep 2
if systemctl is-active nginx > /dev/null 2>&1; then
exit 0
else
exit 1 # 重启失败 → 触发 VIP 漂移
fi
fi
EOF
chmod +x /etc/keepalived/check_nginx.sh
# 手动测试脚本
bash /etc/keepalived/check_nginx.sh
echo "exit code: $?" # 0 表示正常
5.5 第四步:配置 Keepalived
node1(主节点):
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id node1
script_user root
enable_script_security
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -20
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0 # 替换为你的网卡名
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass Keepalived123
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
EOF
node2(备节点):
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id node2
script_user root
enable_script_security
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -20
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP # 备节点
interface eth0 # 替换为你的网卡名
virtual_router_id 51 # 与主节点一致
priority 90 # 低于主节点
advert_int 1
authentication {
auth_type PASS
auth_pass Keepalived123 # 与主节点一致
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
EOF
创建通知脚本(两台都执行):
cat > /etc/keepalived/notify.sh << 'EOF'
#!/bin/bash
STATE=$1
HOSTNAME=$(hostname)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] $HOSTNAME → $STATE" >> /var/log/keepalived-state.log
EOF
chmod +x /etc/keepalived/notify.sh
5.6 第五步:启动并验证
两台机器都执行:
# 检查配置语法
keepalived --config-test -f /etc/keepalived/keepalived.conf
# 启动
systemctl enable --now keepalived
# 查看状态
systemctl status keepalived
验证 VIP 在主节点:
# 在 node1 上执行,应能看到 192.168.1.100
ip addr show eth0 | grep 192.168.1.100
# 在 node2 上执行,不应有 VIP
ip addr show eth0 | grep 192.168.1.100
访问 VIP 确认服务正常:
curl http://192.168.1.100
# 应返回 Nginx 欢迎页
5.7 第六步:模拟故障切换
测试一:停止主节点 Keepalived
# node1 上执行
systemctl stop keepalived
# 等待约 6 秒后,node2 上检查 VIP
ip addr show eth0 | grep 192.168.1.100
# → 应出现 192.168.1.100
# 访问 VIP 仍然正常
curl http://192.168.1.100
# 恢复主节点
systemctl start keepalived
# 约 6 秒后 VIP 漂回 node1
ip addr show eth0 | grep 192.168.1.100
测试二:停止 Nginx 触发健康检查
⚠️ 直接
systemctl stop nginx不管用:check_nginx.sh 检测到故障会立刻重启,
Nginx 永远停不下来。需要用以下任一方式绕过。
方法一:屏蔽 Nginx,让脚本重启也失败(推荐)
# node1 上执行
# mask 后 systemctl restart nginx 也会失败,脚本无法拉起
systemctl mask nginx
systemctl stop nginx
# 此时脚本检测到 Nginx 停止 → 尝试 restart → 失败(被 mask)→ exit 1
# 观察 Keepalived 日志
journalctl -u keepalived -f
# 同时另开终端,node2 上等待 VIP 出现(约 6~10 秒)
ip addr show eth0 | grep 192.168.1.100
# 查看状态切换日志
cat /var/log/keepalived-state.log
# 恢复:解除 mask,VIP 会漂回 node1
systemctl unmask nginx
systemctl start nginx
方法二:修改脚本让它直接返回失败(不重启)
# node1 上临时替换脚本内容,让它直接返回失败
cat > /etc/keepalived/check_nginx.sh << 'EOF'
#!/bin/bash
exit 1 # 强制返回失败,模拟服务宕机
EOF
# 等待 fall 3 次触发(约 6 秒),观察 VIP 漂移
journalctl -u keepalived -f
# node2 查看是否接管 VIP
ip addr show eth0 | grep 192.168.1.100
# 恢复:还原脚本,VIP 漂回 node1
cat > /etc/keepalived/check_nginx.sh << 'EOF'
#!/bin/bash
if systemctl is-active nginx > /dev/null 2>&1; then
exit 0
else
systemctl restart nginx
sleep 2
systemctl is-active nginx > /dev/null 2>&1 && exit 0 || exit 1
fi
EOF
方法三:kill 掉 Nginx 主进程,速度比脚本检测快
# 连续执行,让脚本来不及在 fall 计数归零前重拉起来
# 先记录 pid,循环 kill
while true; do
PID=$(pgrep -x nginx | head -1)
[ -n "$PID" ] && kill -9 $PID
sleep 0.5
done
# Ctrl+C 停止循环后 Nginx 才能稳定存活
实际生产中方法一最常用,
systemctl mask也是模拟"服务彻底崩溃无法恢复"场景的标准做法。
预期结果:
node1 check_nginx.sh 返回非0 × 3次(fall 3)
→ node1 优先级 100 - 20 = 80
→ 低于 node2 的 90
→ VIP 漂移到 node2
恢复后:
node1 check_nginx.sh 返回0 × 2次(rise 2)
→ node1 优先级恢复 100
→ VIP 漂回 node1
5.8 实验总结
| 步骤 | 关键点 |
|---|---|
| 环境准备 | 同网段互通,防火墙放行 VRRP(112协议) |
| 健康检查脚本 | 退出码 0=正常,非0=异常,脚本需有执行权限 |
| 主备配置差异 | state、priority、router_id 三处不同,其余完全一致 |
virtual_router_id |
主备必须相同,同网络内不能重复 |
auth_pass |
主备必须相同,防止其他节点误加入 |
| 故障切换时间 | advert_int × fall ≈ 漂移时间,默认约 3 秒 |
6. 主备模式完整配置
环境:
VIP : 192.168.1.100
MASTER : 192.168.1.1(priority 100)
BACKUP : 192.168.1.2(priority 90)
网卡 : eth0
主节点配置
/etc/keepalived/keepalived.conf
global_defs {
router_id MASTER_NODE # 节点标识,每台唯一
script_user root
enable_script_security
}
vrrp_script check_service {
script "/etc/keepalived/check_service.sh"
interval 2 # 每 2 秒执行一次
weight -20 # 脚本失败时优先级 -20
fall 3 # 连续 3 次失败才触发降权
rise 2 # 连续 2 次成功才恢复
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51 # 主备必须一致
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass YourPassword123
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_service
}
}
备节点配置
仅修改两处,其余完全相同:
global_defs {
router_id BACKUP_NODE # 改为不同标识
}
vrrp_instance VI_1 {
state BACKUP # MASTER → BACKUP
priority 90 # 低于主节点
# 其余参数完全相同
}
验证 VIP
# 主节点查看 VIP
ip addr show eth0 | grep 192.168.1.100
# 停止主节点 Keepalived,观察备节点是否接管
systemctl stop keepalived
# 备节点应出现 VIP
ip addr show eth0 | grep 192.168.1.100
7. 双主模式实战
两台服务器各持有一个 VIP,互为对方的备节点,两台机器同时承载流量,充分利用硬件资源。
7.1 实验环境
| 角色 | IP | 持有 VIP | 业务说明 |
|---|---|---|---|
| Node1 | 192.168.1.1 | VIP1: 192.168.1.100 | Web 流量入口 |
| Node2 | 192.168.1.2 | VIP2: 192.168.1.101 | API 流量入口 |
| 网卡 | eth0 | — | 两台同网段 |
正常状态:
Web 流量 → VIP1(192.168.1.100) → Node1
API 流量 → VIP2(192.168.1.101) → Node2
Node1 故障时:
Web 流量 → VIP1(192.168.1.100) → Node2(接管)
API 流量 → VIP2(192.168.1.101) → Node2(不变)
7.2 第一步:安装依赖
两台机器都执行:
# 安装 Keepalived
dnf install keepalived -y # CentOS
# apt install keepalived -y # Ubuntu
# 安装邮件发送工具
dnf install mailx postfix -y # CentOS
# apt install mailutils postfix -y # Ubuntu
#安装Postfix 登录邮箱用的组件
yum install -y cyrus-sasl cyrus-sasl-plain cyrus-sasl-lib
# 放行 VRRP 协议
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
7.3 第二步:配置邮件告警
使用外部 SMTP(以 QQ邮箱为例)发送告警邮件。
两台机器都执行:
# 配置 Postfix 使用外部 SMTP 中继
cat > /etc/postfix/main.cf << 'EOF'
# SMTP 中继配置
relayhost = [smtp.qq.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_use_tls = yes
smtp_tls_wrappermode = yes
smtp_tls_security_level = encrypt
# 强制关闭IPv6!!
inet_protocols = ipv4
EOF
# 配置 SMTP 认证信息
cat > /etc/postfix/sasl_passwd << 'EOF'
[smtp.qq.com]:587 28329954**@qq.com:sfjoh**rgftudcdc
EOF
# 生成哈希文件并设置权限
postmap /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
# 重启 Postfix
systemctl enable --now postfix
systemctl restart postfix
测试邮件是否能发出:
echo "Keepalived 邮件告警测试" | mail -s "测试邮件" -r 28329954**@qq.com 28329954**@qq.com
echo "正文" | mail -s "标题" -r 发件人 收件人
# 查看发送日志
tail -f /var/log/maillog # CentOS
# tail -f /var/log/mail.log # Ubuntu
常见问题:163/QQ 邮箱需要在网页端开启「SMTP 服务」并生成授权码,
sasl_passwd里填授权码而非登录密码。
编写邮件告警脚本(两台机器都执行):
cat > /etc/keepalived/notify_email.sh << 'EOF'
#!/bin/bash
# ====== 配置区 ======
FROM="28329954**@qq.com" # 发件人
TO="28329954**@qq.com" # 收件人,多个用空格分隔
# ====================
INSTANCE=$1 # VRRP 实例名,如 VI_1
STATE=$2 # 状态:MASTER / BACKUP / FAULT
HOSTNAME=$(hostname)
IP=$(hostname -I | awk '{print $1}')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 状态说明
case $STATE in
MASTER) DESC="【接管】本机成为 MASTER,已获取 VIP" ;;
BACKUP) DESC="【释放】本机降为 BACKUP,已释放 VIP" ;;
FAULT) DESC="【故障】健康检查失败,服务异常!" ;;
*) DESC="状态变更:$STATE" ;;
esac
SUBJECT="[Keepalived] $HOSTNAME $INSTANCE → $STATE"
BODY=$(cat << MAIL
Keepalived 状态变更通知
=======================
主机名 : $HOSTNAME
IP 地址 : $IP
实例 : $INSTANCE
新状态 : $STATE
说明 : $DESC
时间 : $TIMESTAMP
=======================
请登录服务器确认当前 VIP 分布:
ip addr show eth0 | grep -E '100|101'
MAIL
)
# 写入本地日志
echo "[$TIMESTAMP] $HOSTNAME $INSTANCE → $STATE" >> /var/log/keepalived-state.log
# 发送邮件
echo "$BODY" | mail -s "$SUBJECT" -r "$FROM" $TO
EOF
chmod +x /etc/keepalived/notify_email.sh
# 手动测试告警脚本
bash /etc/keepalived/notify_email.sh VI_1 MASTER
# 检查收件箱是否收到邮件
7.4 第三步:编写健康检查脚本
两台机器都执行:
cat > /etc/keepalived/check_nginx.sh << 'EOF'
#!/bin/bash
if systemctl is-active nginx > /dev/null 2>&1; then
exit 0
else
systemctl restart nginx
sleep 2
systemctl is-active nginx > /dev/null 2>&1 && exit 0 || exit 1
fi
EOF
chmod +x /etc/keepalived/check_nginx.sh
7.5 第四步:配置 Keepalived
Node1 配置 /etc/keepalived/keepalived.conf:
global_defs {
router_id node1
script_user root
enable_script_security
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -20
fall 3
rise 2
}
# ===== 实例1:Node1 为 MASTER,持有 VIP1 =====
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass VIPass51
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify_email.sh VI_1 MASTER"
notify_backup "/etc/keepalived/notify_email.sh VI_1 BACKUP"
notify_fault "/etc/keepalived/notify_email.sh VI_1 FAULT"
}
# ===== 实例2:Node1 为 BACKUP,备份 VIP2 =====
vrrp_instance VI_2 {
state BACKUP
interface eth0
virtual_router_id 52
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass VIPass52
}
virtual_ipaddress {
192.168.1.101/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify_email.sh VI_2 MASTER"
notify_backup "/etc/keepalived/notify_email.sh VI_2 BACKUP"
notify_fault "/etc/keepalived/notify_email.sh VI_2 FAULT"
}
Node2 配置 /etc/keepalived/keepalived.conf:
global_defs {
router_id node2
script_user root
enable_script_security
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -20
fall 3
rise 2
}
# ===== 实例1:Node2 为 BACKUP,备份 VIP1 =====
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass VIPass51
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify_email.sh VI_1 MASTER"
notify_backup "/etc/keepalived/notify_email.sh VI_1 BACKUP"
notify_fault "/etc/keepalived/notify_email.sh VI_1 FAULT"
}
# ===== 实例2:Node2 为 MASTER,持有 VIP2 =====
vrrp_instance VI_2 {
state MASTER
interface eth0
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass VIPass52
}
virtual_ipaddress {
192.168.1.101/24
}
track_script {
check_nginx
}
notify_master "/etc/keepalived/notify_email.sh VI_2 MASTER"
notify_backup "/etc/keepalived/notify_email.sh VI_2 BACKUP"
notify_fault "/etc/keepalived/notify_email.sh VI_2 FAULT"
}
7.6 第五步:启动并验证初始状态
# 两台都执行:检查语法
keepalived --config-test -f /etc/keepalived/keepalived.conf
# 两台都执行:启动
systemctl enable --now keepalived
# Node1 上应持有 VIP1,不持有 VIP2
ip addr show eth0 | grep -E '100|101'
# 预期:192.168.1.100 ✅ 192.168.1.101 ❌
# Node2 上应持有 VIP2,不持有 VIP1
ip addr show eth0 | grep -E '100|101'
# 预期:192.168.1.100 ❌ 192.168.1.101 ✅
7.7 第六步:故障切换验证
测试一:Node1 整机故障(停止 Keepalived)
# Node1 上执行
systemctl stop keepalived
# Node2 上约 6 秒后应同时持有两个 VIP
ip addr show eth0 | grep -E '100|101'
# 预期:192.168.1.100 ✅ 192.168.1.101 ✅
# 同时检查收件箱,应收到两封告警邮件:
# [Keepalived] node2 VI_1 → MASTER
# [Keepalived] node2 VI_2 → (不变,本来就是 MASTER)
# 恢复 Node1
systemctl start keepalived
# 约 6 秒后 VIP1 漂回 Node1,收到恢复邮件
ip addr show eth0 | grep -E '100|101'
测试二:Node1 Nginx 故障(用 mask 防止脚本重拉)
# Node1 上执行
systemctl mask nginx
创建软链接 /etc/systemd/system/nginx.service → /dev/null
永久锁定禁用服务,禁止任何方式启动(手动 / 开机自启 / 别的程序拉起全都无效)
systemctl stop nginx
# 观察 Keepalived 日志(等待 fall 3 × interval 2 = 6 秒)
journalctl -u keepalived -f
# Node1 优先级:100 - 20 = 80 < Node2 的 90
# VIP1 应漂移到 Node2
ip addr show eth0 | grep 192.168.1.100 # 在 Node2 上执行
# 检查邮件告警
cat /var/log/keepalived-state.log
# 恢复
systemctl unmask nginx
systemctl start nginx
# VIP1 漂回 Node1,再次收到恢复邮件
7.8 VIP 分布速查
# 两台机器同时检查,一目了然
echo "=== Node1 ===" && ssh node1 "ip addr show eth0 | grep -E '100|101'"
echo "=== Node2 ===" && ssh node2 "ip addr show eth0 | grep -E '100|101'"
# 查看状态切换历史
cat /var/log/keepalived-state.log
7.9 双主实验总结
| 配置项 | VI_1 | VI_2 |
|---|---|---|
| Node1 角色 | MASTER(priority 100) | BACKUP(priority 90) |
| Node2 角色 | BACKUP(priority 90) | MASTER(priority 100) |
| virtual_router_id | 51 | 52 |
| auth_pass | VIPass51 | VIPass52 |
| VIP | 192.168.1.100 | 192.168.1.101 |
两个实例的
virtual_router_id和auth_pass必须各自不同,否则两个实例会互相干扰。
8. 健康检查脚本
脚本退出码:0 = 健康,非 0 = 不健康(触发优先级降低)。
检查任意进程
#!/bin/bash
# /etc/keepalived/check_service.sh
SERVICE="haproxy"
if systemctl is-active $SERVICE > /dev/null 2>&1; then
exit 0
else
# 尝试重启
systemctl restart $SERVICE
sleep 2
systemctl is-active $SERVICE > /dev/null 2>&1 && exit 0 || exit 1
fi
检查端口是否监听
#!/bin/bash
# /etc/keepalived/check_port.sh
PORT=80
if ss -tlnp | grep -q ":$PORT "; then
exit 0
else
exit 1
fi
检查 HTTP 接口
#!/bin/bash
# /etc/keepalived/check_http.sh
URL="http://127.0.0.1/health"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 $URL)
if [ "$HTTP_CODE" = "200" ]; then
exit 0
else
exit 1
fi
# 脚本授权
chmod +x /etc/keepalived/check_*.sh
9. 通知脚本
状态切换时自动执行脚本,常用于发送告警通知。
vrrp_instance VI_1 {
...
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
/etc/keepalived/notify.sh
#!/bin/bash
STATE=$1
HOSTNAME=$(hostname)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
log() {
echo "[$TIMESTAMP] [$HOSTNAME] Keepalived state: $1" >> /var/log/keepalived-notify.log
}
case $STATE in
MASTER)
log "Became MASTER - VIP acquired"
# 可在此发送钉钉/企微/邮件告警
;;
BACKUP)
log "Became BACKUP - VIP released"
;;
FAULT)
log "FAULT - health check failed"
;;
esac
chmod +x /etc/keepalived/notify.sh
10. 与 HAProxy 联动
Keepalived 监控 HAProxy 进程,HAProxy 故障时触发 VIP 漂移。
global_defs {
router_id HAPROXY_MASTER
script_user root
enable_script_security
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
weight -20
fall 3
rise 2
}
vrrp_instance VI_HAProxy {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass HAPasswd123
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
#!/bin/bash
# /etc/keepalived/check_haproxy.sh
if systemctl is-active haproxy > /dev/null 2>&1; then
exit 0
else
systemctl restart haproxy
sleep 2
systemctl is-active haproxy > /dev/null 2>&1 && exit 0 || exit 1
fi
11. 常用命令
# 启动 / 停止 / 重启 / 重载
systemctl start keepalived
systemctl stop keepalived
systemctl restart keepalived
systemctl reload keepalived # 重载配置,不中断 VIP
# 查看运行状态
systemctl status keepalived
# 查看日志
journalctl -u keepalived -f
journalctl -u keepalived --since "1 hour ago"
# 查看当前 VIP 是否在本机
ip addr show eth0 | grep <VIP>
# 查看 VRRP 组播(抓包确认心跳正常)
tcpdump -i eth0 -nn vrrp
# 手动触发主备切换(临时降低优先级)
# 主节点执行,让备节点接管
systemctl stop keepalived
12. 故障排查
常见问题
| 现象 | 原因 | 解决方案 |
|---|---|---|
| 两台都成为 MASTER(脑裂) | 网络不通 / 认证不一致 | 检查防火墙放行 VRRP(112协议),核对 auth_pass |
| VIP 不漂移 | virtual_router_id 不一致 |
确保主备该值完全相同 |
| 频繁主备切换 | 健康检查脚本不稳定 | 增大 fall 值,检查脚本执行时间 |
| 主节点恢复后不抢占 | 配置了 nopreempt |
确认是否需要抢占,去掉或保留 nopreempt |
| 脚本无效果 | 脚本无执行权限 | chmod +x 并检查 script_user 配置 |
排查步骤
# 1. 检查配置文件语法
keepalived --config-test -f /etc/keepalived/keepalived.conf
# 2. 查看实时日志
journalctl -u keepalived -f
# 3. 确认防火墙放行 VRRP 协议(必须)
# CentOS
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
# Ubuntu
iptables -A INPUT -p 112 -j ACCEPT
# 4. 抓包验证心跳
tcpdump -i eth0 -nn vrrp
# 5. 手动测试健康检查脚本
bash /etc/keepalived/check_haproxy.sh
echo "exit code: $?"
# 6. 查看当前 VIP 持有情况
ip addr | grep -E 'eth0|VIP地址'
防火墙配置(必做)
Keepalived 使用 VRRP 协议(IP 协议号 112) 和多播地址 224.0.0.18 通信,必须放行:
# CentOS / firewalld
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
# Ubuntu / ufw
ufw allow proto ah
# 或直接用 iptables
iptables -A INPUT -p 112 -j ACCEPT
iptables -A OUTPUT -p 112 -j ACCEPT
Keepalived 官方文档:https://www.keepalived.org/doc/

浙公网安备 33010602011771号