Keepalived 1.2.13 双机热备与 VIP 漂移实战 简介Keepalived 1.2.13源码包面向运维工程师、网络架构学习者及高可用实践者围绕VRRP与LVS实现服务故障切换适合研究主备切换、健康检查与负载均衡配置。压缩包共188个文件、约334KB以62个C头文件和61个C源文件为核心辅以autoconf模板、示例配置、man手册与安装脚本兼顾源码阅读、编译部署和样例参考。已有369人学习下载。包内可见VRRP实例、虚拟服务器组及健康检查等配置线索也能结合日志和抓包思路理解排错1.2.13在VRRP实现、性能与配置选项上的改动可通过源码逐项对照适合搭建实验环境、验证版本特性并梳理高可用部署流程。包体还保留变更日志、版本号文件与许可证信息便于追溯发布背景、核对版本差异与编译参数细节并辅助二次编译与旧项目维护。1. 两台机器一个 VIP为什么还有人翻 keepalived-1.2.13前阵子给一个内部系统做双机热备两台机器、一个虚拟 IP对外只暴露一个地址。真正让人半夜爬起来的问题从来不是 IP 漂不过去而是 IP 漂过去了、进程没起来流量照样打空。keepalived-1.2.13.tar.gz 就是应付这类场景的老家伙用 VRRP 在几台机器之间选主主机出问题时备机接管虚拟 IP还能挂 vrrp_script 把“端口通不通、进程在不在”变成漂移的判据。它适合自建机房、没有独立负载均衡设备、又不想引入太重组件的场景也适合想把 VIP 漂移这件事彻底摸透的人——源码亲手编一遍比看十篇配置教程都扎实。代价是 1.2.13 年头够久依赖、语法、边界条件都得自己捋一遍下面的内容就按这个顺序来。2. 从 tar.gz 到可执行文件1.2.13 的依赖、configure 与产物核对2.1 源码包和仓库包的选择边界多数发行版仓库里能直接装到 keepalived版本往往比 1.2.13 高。这两条路不是谁替代谁而是适用面不同。仓库包的好处是省事包管理器会连带把 init 脚本、sysconfig、日志轮转都装好升级也方便坏处是版本和配置语法绑死在你装的那一版上网上找来的示例配置经常因为多了一行vrrp_strict或者version 2就直接启动失败。源码包的价值在于可控。configure 阶段可以关掉用不上的模块比如纯 VIP 漂移根本不需要 LVS 那套 IPVS 代码--disable-lvs --disable-lvs-syncd一关编译依赖少一大截产出的二进制也不用去碰内核头文件。另外同一份二进制推到十几台机器上行为完全一致不会出现“这台是 2.0、那台是 2.2”的排错地狱。1.2.13 属于 1.2 系列的后期版本配置语法相对宽松vrrp_instance、vrrp_script、notify_master这些关键指令都在做双机主备够用。需要提前知道的是这一版只讲 VRRPv2认证是明文口令别指望它承担安全职责。2.2 依赖清单与 configure 参数先把依赖摆清楚。下表是我在干净机器上编译前会逐个确认的东西缺哪个补哪个依赖用途缺失时的表现gcc、make编译与链接configure 直接报找不到 C 编译器kernel-devel版本必须匹配uname -r提供net/ip_vs.h等头文件供 LVS 部分编译configure 找不到内核目录或 make 阶段编译 IPVS 相关文件报错openssl-develSSL_GET 健康检查、部分摘要工具不做 HTTPS 探测可以不装但要留意 configure 摘要里的 SSL 支持项是否被关掉iproute2运行期用ip addr看 VIP 落点不影响运行排错时抓瞎ipvsadm只有用 virtual_server 做四层转发才需要纯 VRRP 场景无影响装完之后解包、进目录、跑 configure。我一般把配置文件目录单独指到/etc/keepalived这一步不做后面 systemd 和 init 脚本都会找不到配置# 基础编译工具 yum install -y gcc make # 内核头文件版本号必须和 uname -r 一致否则路径对不上 yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) # 只有需要 SSL_GET 检查时才装 yum install -y openssl-devel tar -zxf keepalived-1.2.13.tar.gz cd keepalived-1.2.13 # 只做 VIP 漂移关掉 LVS省掉内核头依赖 ./configure \ --prefix/usr/local/keepalived \ --sysconfdir/etc/keepalived \ --disable-lvs \ --disable-lvs-syncd三个参数逐个说清楚。--prefix决定安装根目录二进制落在sbin/keepalived示例配置和 init 脚本落在etc/下面--sysconfdir决定运行时去哪读keepalived.conf默认值在 prefix 下面改到/etc/keepalived是为了符合大多数人的运维习惯也方便配置管理工具统一推送--disable-lvs和--disable-lvs-syncd是配套的关掉 LVS 之后就不需要--with-kernel-dir指内核源码路径了。如果你确实要用 virtual_server 做转发把这两行换成--with-kernel-dir/usr/src/kernels/$(uname -r)并确认那个目录真实存在。configure 跑完别急着 make先看输出末尾的摘要。里面有几行值得逐个确认Use IPVS framework是 Yes 还是 NoUse VRRP framework必须是 YesUse SSL support决定你能不能写 SSL_GET 检查。摘要和你预期不一致说明依赖没装全或者参数写错了这时候 make 下去大概率是白等一场。2.3 make、install 与产物核对编译本身没什么花活机器核数多就并行跑make -j$(nproc) make install # 核对产物 ls -l /usr/local/keepalived/sbin/keepalived ls -l /etc/keepalived/keepalived.conf # 确认二进制能跑、版本对不对 /usr/local/keepalived/sbin/keepalived -vmake install会把二进制装到 prefix 的sbin/把示例配置装到 sysconfdir通常还带一个bin/genhash那个是给 HTTP 检查生成摘要用的纯 VIP 场景用不上。init 脚本不会自动进/etc/init.d得自己从源码目录keepalived/etc/init.d/keepalived拷过去同时把keepalived/etc/sysconfig/keepalived拷到/etc/sysconfig/启动参数从那里读。现在多数机器用 systemd直接写一个 unit 更省事[Unit] DescriptionKeepalived VRRP Afternetwork.target [Service] Typeforking # -D 输出详细日志-f 显式指定配置文件避免读错路径 ExecStart/usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf ExecReload/bin/kill -HUP $MAINPID PIDFile/var/run/keepalived.pid KillModeprocess [Install] WantedBymulti-user.targetTypeforking是因为 keepalived 自己会 daemon 化KillModeprocess防止停止服务时把子进程漏掉ExecReload用 HUP 信号触发配置重载改完配置不用整机重启切换窗口小很多。启动之后用ps -ef | grep keepalived看正常情况下能看到父进程加一个 VRRP 子进程。日志走 syslog 的 daemon facility一般落在/var/log/messages或/var/log/syslog-D打开后能看到每个实例进 MASTER、BACKUP 的时间点后面排查全靠它。3. VRRP 选主参数state、priority、virtual_router_id 填错的三种后果3.1 VRRP 报文与状态机切换快慢由谁决定VRRP 干的事说白了就一句话一组机器共享一个虚拟 IP同一时刻只有一台对外宣告自己是主人。实现方式是组播通告默认目的地址 224.0.0.18IP 协议号 112。每台机器按advert_int的间隔往外发 VRRP Advertisement报文里带着自己的 priority 和 virtual_router_id。priority 最高的那台进入 MASTER 状态并持有 VIP其余停在 BACKUP 状态听通告。切换时间不是随便定的。BACKUP 上跑着一个 master_down_interval 定时器算法是3 × advert_int skew_time其中 skew_time 约等于(256 - priority) / 256秒。按默认advert_int 1算主挂了之后备机大概 3 秒出头接管priority 越低等得越久这是为了减少多台备机同时抢主的概率。想快就把 advert_int 调小但代价是通告流量上升网络稍有拥塞就容易误判我一般不动这个值1 秒在局域网里够稳。状态机是 INIT → BACKUP → MASTER 这套。刚启动时先进 BACKUP等一个 master_down_interval 收不到通告才升 MASTER所以主机重启后不会立刻把 VIP 抢回去除非配了抢占。抢占是默认行为主机恢复、开始发通告发现自己的 priority 比当前 MASTER 高就直接把 VIP 抢回来。很多业务不喜欢这种“恢复即抖动”后面第 6 章会讲怎么用 nopreempt 和 preempt_delay 把这件事压住。3.2 主备两份配置的差异点下面这份是主机侧的完整可用配置备机只需要改三处global_defs { router_id node_a # 日志标识两台不能重名否则排错时完全分不清谁是谁 vrrp_mcast_group4 224.0.0.18 # 默认组播地址没有特殊需求不要改 } vrrp_instance VI_1 { state MASTER # 初始角色实际选主结果由 priority 决定 interface eth0 # 物理网卡名不能写成 eth0:0 这种子接口 virtual_router_id 51 # 1-255同一广播域内必须唯一 priority 150 # 备机写 100差值决定切换是否干脆 advert_int 1 # 通告间隔单位秒 authentication { auth_type PASS auth_pass Abc12345 # VRRPv2 只取前 8 位写再长也只有前 8 位生效 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } }备机侧把router_id改成 node_bstate改成 BACKUPpriority改成 100其余三项和主机保持完全一致。这里有个容易被忽略的点virtual_router_id和auth_pass必须两边严格一致否则通告会被对方丢弃双方都认为对面死了结果就是双主。interface也要确认是真实承载 VIP 的那张网卡bond 或 VLAN 子接口场景下写错名字VIP 会绑到错误设备上业务侧看到的是“VIP 在但连不通”。参数取值上有几个边界值要记住。priority有效范围是 1 到 2540 保留给“主动放弃 MASTER”的场景255 保留给 IP 地址拥有者普通配置不要碰这两个值。virtual_router_id是 1 到 255同一二层网络里如果有别的团队也在跑 keepalived撞号概率不低上线前先跟网络侧确认一遍。3.3 启动后的三看验证法配置写完不要直接上生产先在三看里过一遍看 VIP 落点、看通告报文、看故障切换耗时。# 第一看VIP 到底绑在哪台机器、哪张网卡上 ip -4 addr show dev eth0 | grep 192.168.10.100 # 第二看抓 10 个 VRRP 通告协议号 112 tcpdump -i eth0 -nn -c 10 proto 112 # 第三看在主上停服务备机上循环观察 VIP 出现的时间 systemctl stop keepalived while true; do date %T; ip -4 addr show dev eth0 | grep -c 192.168.10.100; sleep 0.5; done第一看的输出应该是主机上有192.168.10.100/24备机上没有。第二看如果只在一台机器上抓到包说明组播没通先查交换机或防火墙正常应该看到源地址是各自主机的物理 IP、目的地址 224.0.0.18 的报文间隔稳定在 1 秒左右。第三看是验证切换时间最直接的办法从停服务到备机出现 VIP 的时间应该接近 3 秒明显超出说明通告有丢包或者备机的advert_int和主机不一致。日志里对应的关键行有三条Entering BACKUP STATE、Entering MASTER STATE、VRRP_Instance(VI_1) Received advert with higher priority。前两条告诉你角色变化的时间点第三条说明发生了抢占前面那行会带上对方的 priority对着看就知道是谁抢了谁。4. 健康检查落地用 vrrp_script 把 VIP 漂移绑到进程存活上4.1 VRRP 只保证机器活着不保证服务活着这是新手最容易翻车的地方。VRRP 判断“对方死没死”的唯一依据是收不收得到通告只要机器还在、网卡还在、keepalived 进程还在通告就一直发。至于上面的 nginx 是不是已经挂了、后端数据库连接是不是全断了VRRP 一无所知。结果就是VIP 纹丝不动地待在一台已经不能提供服务的机器上业务全量报错监控告警响了十分钟运维上去手动重启才发现问题。keepalived 提供的解法是vrrp_script。它允许你挂一个任意脚本脚本返回 0 代表健康、非 0 代表异常keepalived 按固定间隔去跑这个脚本并根据结果调整本机的 prioritypriority 掉到比备机低VIP 自然就漂走了。这套机制的好处是判据完全自定义可以是端口探测、可以是进程数、可以是调一次业务健康接口、甚至可以是查一次磁盘水位。1.2.13 还带 virtual_server 那一套 LVS 健康检查但那是给四层转发用的纯 VIP 场景用不上也别把两套混着配排错时会非常痛苦。4.2 写一个能用的 vrrp_script 检查脚本脚本要满足三个条件快、绝对路径、退出码明确。下面这个是最小可用版本#!/bin/bash # 检查本机 web 服务的健康接口2 秒超时 # 退出码 0 健康非 0 异常keepalived 只看退出码 code$(curl -s -o /dev/null -m 2 -w %{http_code} http://127.0.0.1:80/health) if [ $code 200 ]; then exit 0 fi exit 1逻辑很简单但每行都有讲究。用127.0.0.1而不是对外域名是为了避开 DNS 和外部链路带来的抖动健康检查必须只反映本机服务的真实状态。-m 2限制总耗时防止脚本卡死拖垮整个检查周期。-w %{http_code}只取状态码把响应体丢掉减少内存和 IO 开销。判断条件别用curl -f那个在 3xx 重定向时行为不符合直觉显式比对 200 更可控。脚本放好之后必须chmod x路径写绝对路径这一点没有商量余地——keepalived 启动时的环境变量和你登录 shell 的环境变量完全不是一回事PATH里没有/usr/local/bin是家常便饭。4.3 track_script 与 weight 的算术关系脚本本身不会自动生效要挂到实例上vrrp_script chk_web { script /usr/local/bin/chk_web.sh # 绝对路径必须可执行 interval 2 # 每 2 秒跑一次 weight -40 # 失败一次本机 priority 减 40 fall 3 # 连续失败 3 次才判定为故障 rise 2 # 连续成功 2 次才恢复 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass Abc12345 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } track_script { chk_web } }weight是这里唯一需要动脑子的参数。它的含义是“脚本失败时给 priority 加多少分”负值就是扣分。主机的 priority 是 150备机是 100差值是 50weight -40扣完还有 110仍然比备机高VIP 不会漂。这种情况下健康检查形同虚设日志里连个错误都不会有你会以为它工作得很好。正确写法是让weight的绝对值超过主备差值比如-60扣完变成 90低于备机的 100切换才会发生。fall和rise是防抖用的。fall 3表示连续失败 3 次才认定故障配合interval 2就是至少 6 秒才触发一次切换能过滤掉偶发的超时。rise 2表示连续成功 2 次才恢复防止服务刚起来还不稳定就急着抢回来。这两个值调小会让切换更灵敏但也更容易抖调大会让故障发现变慢我的习惯是interval 2、fall 3、rise 2大多数业务能接受。4.4 notify 脚本漂移之后还要做什么VIP 漂过去不代表万事大吉。有些场景需要配合动作清一下 ARP 缓存让网关立刻更新、把本机的应用配置从“备”切到“主”、给监控系统推一条状态变更、或者重启一个依赖 VIP 存在的服务。这些用 notify 系列脚本做vrrp_instance VI_1 { # ... 前面的配置省略 notify_master /usr/local/bin/on_master.sh notify_backup /usr/local/bin/on_backup.sh notify_fault /usr/local/bin/on_fault.sh }#!/bin/bash # on_master.sh本机刚接管 VIP 时执行 # $1 是 keepalived 传进来的状态字符串MASTER / BACKUP / FAULT echo $(date %F %T) become $1 /var/log/keepalived-notify.log # 通知网关刷新 ARP部分老交换机不做 gratuitous ARP 的转发 arping -c 3 -I eth0 -s 192.168.10.100 192.168.10.1脚本有三个硬性约束必须可执行、必须快速返回、不能阻塞。keepalived 是同步调用 notify 脚本的脚本卡住不退出整个状态机就跟着卡住。所以脚本里别写sleep、别做耗时的数据库操作、别调需要交互的命令要做重活就丢到后台或者交给独立的 agent 处理。脚本里的$1是状态名1.2.13 传的是大写字符串别拿它跟小写去比。5. 避坑与排查五类翻车现场的现象、原因与处置5.1 起不来与配置解析类第一条启动即退出日志里只有一行“Unable to open configuration file”。现象是systemctl start之后立刻变成 failedps里什么都没有。原因几乎都是配置文件路径不对编译时--sysconfdir没改默认去 prefix 下面的 etc 找而你按习惯把配置放在了/etc/keepalived/keepalived.conf。处置办法是启动时用-f显式指定路径或者重新 configure 一遍把 sysconfdir 指对。判断配置本身有没有语法问题时先用keepalived -t -f /etc/keepalived/keepalived.conf做一次静态检查这个版本认这个参数就直接给结论如果它不认就前台跑keepalived -n -d -f ...把错误直接打到终端上比翻日志快得多。第二条配置检查通过但启动后报“Unknown keyword”。现象是进程起来又退出日志里明确指到某一行的指令不认识。原因是把高版本的配置抄到了 1.2.13 上vrrp_strict、garp_master_repeat、version 2这类 1.3 之后才出现的东西这一版没有。处置办法是把不认识的指令逐行删掉或者注释掉每次只改一处改完跑一次-t。我见过最离谱的一次是有人把整段virtual_server抄过来但编译时用了--disable-lvs那一段直接变成非法配置报错信息还指在别的行上绕了很久。5.2 漂移与双主类第三条两台机器同时持有 VIP客户端连接时通时不通。这是最典型也最危险的双主。现象是ip addr在两边都能看到/32的 VIPping 时通时断抓包能看到两个源地址都在发通告。原因有三类virtual_router_id撞号同网段里还有别的实例用了同一个 IDauth_pass不一致两边互相把对方的通告当非法包丢掉都以为对面死了网络设备把组播掐了两边谁也收不到谁。处置顺序是先对配置把 VRID、auth_pass 前 8 位、advert_int 三个值逐字比对配置一致还双主就用tcpdump -i eth0 -nn proto 112在两边各抓一次看能不能收到对方的包。收不到就是网络问题要么放行协议号 112要么改单播。第四条主机恢复后不抢回 VIP或者抢回瞬间业务抖一下。现象是主修好上线了VIP 还在备机上待着或者刚抢回来又掉回去。原因是nopreempt被误用了这个参数生效有前提不是写上就管用另一种情况是没配preempt_delay主机一恢复就抢此时业务还没完全就绪VIP 抢回来等于把流量引到一个半死的服务上。处置办法是主机侧加preempt_delay 300让它在恢复后等 5 分钟再抢给业务留出预热时间确实不想让它抢回就用nopreempt同时确认state写的是 BACKUP具体条件在第 6 章展开。5.3 健康检查与脚本类第五条服务明明挂了VIP 却一动不动。现象是 nginx 进程已经没了主机上curl 127.0.0.1直接拒绝连接但 VIP 稳稳待着日志里一条切换记录都没有。原因最常见的是 weight 算术没算对weight -40配上 50 的主备差值扣完还是比备机高脚本跑得再勤也没用。其次是脚本没有执行权限keepalived 调它的时候直接返回 126但这个失败被fall计数吃掉了日志里看不出来再其次是脚本里用了相对路径或依赖PATH手动执行正常被 keepalived 调用就报 command not found。处置办法是三步走先在主机上手动执行脚本echo $?确认返回 0再把weight的绝对值调到大于主备 priority 差值最后把脚本里的所有命令换成绝对路径。验证是否真的生效看日志里有没有VRRP_Script(chk_web) failed这一行有这行说明脚本被调到了没有就是根本没跑起来。6. 单播与 nopreempt两个参数决定漂移听不听话组播在跨网段、云上 VPC、或者交换机开了组播抑制的环境里经常不通表现就是两边互相收不到通告最后变成双主。改单播是最干脆的解法1.2.13 这一版已经支持vrrp_instance VI_1 { # ... 前面的配置省略 unicast_src_ip 192.168.10.11 # 本机物理 IP unicast_peer { 192.168.10.12 # 对端物理 IP多台就写多行 } }改单播之后就不用管 224.0.0.18 了防火墙只需要放行两两之间的协议号 112。注意unicast_src_ip必须写本机真实网卡上的地址写 VIP 会导致通告发不出去。nopreempt的生效条件比很多人以为的严格配置不对就是白写条件说明state必须是 BACKUP写 MASTER 时 nopreempt 不生效这是最常见的失效原因两台 priority 不能相同相同会导致选主结果不确定nopreempt 也救不了只影响“抢回”不影响“接管”主机挂了备机照样接管只是主机恢复后不主动抢与preempt_delay二选一想延迟抢回用 preempt_delay想彻底不抢用 nopreempt我一般的做法是核心业务用preempt_delay 300让主机恢复后等五分钟再接管既保留了主机优先的语义又给了业务预热时间只有主备硬件配置差距很大、备机性能明显更强时才用nopreempt让它一直待在备机上。从那以后我每次配完这两个参数都会在一台机器上手动 stop 再本文还有配套的精品资源点击获取