notify脚本中exit 0/1/2仅影响日志记录,不控制vip切换;真正决定vip行为的是vrrp_script的退出码:exit 0权重不变,exit 1触发降权切换,exit 2以上标记失败但不额外处理。

Keepalived notify 脚本里怎么用 exit 0/1/2 控制 VIP 行为
Keepalived 的 notify 脚本本身不决定 VIP 切换,它只是通知钩子;真正控制 VIP 让出的关键,在于脚本退出状态码是否被 Keepalived 主进程识别并触发状态回退。只有当脚本在 notify_stop 或 notify_fault 阶段返回非 0 状态时,Keepalived 才可能提前终止当前状态(比如从 MASTER 强制降级),但更可靠的方式是让脚本主动调用 killall -TERM keepalived 或修改配置后 reload——不过这不是靠 exit 码,而是靠副作用。
真正能被 exit 码直接影响的,是 Keepalived 启动阶段的健康检查脚本(vrrp_script 中的 script):它的退出码直接映射为权重增减依据。而 notify 脚本的 exit 码仅用于日志记录,Keepalived 不据此改变状态机。
-
exit 0:表示 notify 执行成功,Keepalived 继续当前角色(MASTER/BACKUP) -
exit 1或任意非 0:Keepalived 会记一条 warning 日志(如"notify script returned error"),但不会自动切换或释放 VIP - 想让 VIP 主动让出,必须在 notify 脚本里显式执行
ip addr del或触发 reload,例如:ip addr del 192.168.1.100/24 dev eth0 && systemctl reload keepalived
vrrp_script 的 exit 码才是 VIP 切换的实际开关
如果你的目标是“服务异常时让出 VIP”,正确做法不是依赖 notify,而是写一个 vrrp_script,用它的退出码驱动权重变化,再配合 track_script 触发状态重算。
- 脚本返回
exit 0→ 检查通过,权重不变或按配置增加 - 脚本返回
exit 1→ 检查失败,权重减少(weight -2),若导致总权重 ≤ 对端,则触发 BACKUP 切换 - 脚本返回
exit 2及以上 → Keepalived 会标记该 script 为 “failed” 并计入日志,但不会额外处理 - 注意:
fall 2和rise 1表示连续失败 2 次才触发降权,避免瞬时抖动误判
示例脚本(检测 Nginx 是否响应):
#!/bin/bash if curl -f http://127.0.0.1/health > /dev/null 2>&1; then exit 0 else exit 1 fi
为什么 notify_fault 里 exit 1 不会让 VIP 离开
因为 notify_fault 是在 Keepalived 已经判定自己进入 FAULT 状态后才执行的,此时 VIP 通常已被移除(取决于 preempt_delay 和 nofailback 设置)。你在里面 exit 1,只是让 Keepalived 多记一行错误日志,并不能加速或干预这个过程。
- FAULT 状态下 VIP 是否还保留,由
interface、virtual_ipaddress的nopreempt和preempt_delay共同决定,和 notify 返回值无关 - 常见误解:以为在
notify_master里exit 1就能强制切走 VIP —— 实际上 Keepalived 不会因此回滚状态机 - 真要“紧急让出”,唯一稳妥方式是在脚本中直接执行:
ip addr flush dev eth0 && pkill -USR2 keepalived(触发重载并清空地址)
reload vs killall:哪个更适合主动让出 VIP
用 systemctl reload keepalived 是推荐方式,它会触发 VRRP 实例重新协商,当前 MASTER 会发送 priority 0 的通告,让对端快速接管;而 killall -TERM keepalived 会导致 VIP 瞬间消失,中间有几秒不可用窗口,且对端需等待 advert_int × 3 才判定超时。
- reload 前确保配置已更新(例如把本机
priority改成比对端低),否则 reload 后仍可能抢回 VIP - 如果只是临时让出,可在 reload 前加一句:
echo "stopping VIP on $(hostname)" > /tmp/keepalived.manual.stop,然后在 vrrp_script 中检查该文件是否存在并返回exit 1 - 不要在 notify 脚本里 sleep 或阻塞太久(默认超时 5 秒),否则 Keepalived 会杀掉子进程并标记为 failed











