
简介面向运维工程师、网络管理员与高可用技术学习者这份 Keepalived 1.2.13 源码及配套资料围绕 VRRP、服务健康检查和 LVS 负载均衡展开适合研究主备切换、虚拟 IP 接管、故障排查与高可用集群搭建的读者也可作为课程实验、源码阅读与二次开发的基础素材。压缩包共 188 个文件约 334KB以 62 个 C 头文件和 61 个 C 源文件为核心并包含配置样例、手册页、构建脚本与说明文档较完整地呈现了该版本的代码组织、编译方式及典型配置结构。已有 369 人学习下载。读者能从中获得 VRRP 实例配置参考、TCP/HTTP/ICMP 等健康检查思路、LVS 虚拟服务器配置样例以及日志观察和排错所需的基础材料便于在实验环境复现主备高可用方案并进一步理解 Keepalived 的运行机制与部署要点。对学习 C 语言网络编程及守护进程实现亦有参考意义。1. 解包 keepalived-1.2.13.tar.gz 之前先确认你要的是 VIP 漂移还是四层转发两台机器跑同一套服务一台对外、一台待命主的那台挂了之后虚拟 IP 能在几秒内挪过去——这套需求二十年没变过最常见的实现仍然是 keepalived。keepalived-1.2.13.tar.gz 就是这条路上被反复下载的一个源码包体积不大解开之后就是一个标准 autotools 工程。它只做两件事用 VRRP 协议抢虚拟 IP用 IPVS 内核模块做四层转发和健康检查。判断标准很简单你只是想让 IP 飘走编译时关掉 IPVS 就行你要做四层负载才需要内核头文件和 ip_vs 模块。2. VRRP 与 IPVS 两条腿先弄清楚这份源码的职责边界很多人把 keepalived 当成一个“双机软件”整体去理解配置写错一半也不知道错在哪。实际上它内部是两套完全独立的东西只是共用一个进程和一个配置文件。搞清楚这两条腿分别依赖什么后面编译参数怎么选、报错往哪查才有方向。2.1 VRRP 通告、优先级与抢占虚拟 IP 是怎么“飘”过去的VRRP 的本质是几台机器共用一份对外身份。一个vrrp_instance对应一个virtual_router_id同一广播域里这一组设备每隔advert_int秒往组播地址 224.0.0.18 发一个 IP 协议号 112 的通告包包里带着自己的 priority。优先级最高的那台持有 VIP 并持续应答 ARP其余进入 BACKUP 状态只听不说。Master 挂掉后Backup 在一个 Master_Down_Interval 内收不到通告就顶上去这个间隔老公式是3 × advert_int skew_time其中skew_time (256 - priority) / 256秒。由此可以推出几个实操结论。第一state MASTER/state BACKUP只是进程启动时的初始状态不决定最终身份真正的选举看 priority 和抢占开关所以两端都写 BACKUP 反而更稳能避免同时启动时短暂双主。第二priority 取值范围 0 到 255255 保留给“这个 IP 本来就配在我网卡上”的地址拥有者业务配置里别用。第三优先级相同时比 IP 大小这是个很多人不知道的兜底规则也是“为什么每次都是那台当主”的答案。第四认证段的 PASS 密码只取前 8 位写 12 位和写 8 位是一个效果这点在 1.2.x 上尤其要注意。2.2 keepalived.conf 的三段结构哪一段出问题日志会告诉你在哪里1.2.13 的配置文件是纯文本用{ }分层!开头是注释。整份文件的有效段落就那么几类把它们的作用和这个老版本的脾气对上排查时能省很多时间。配置段管什么1.2.13 里必须注意的点global_defs全局标识、告警邮件、脚本执行用户router_id双机不能相同否则日志里分不清是谁notification_email段留空也要写括号vrrp_instanceVIP、优先级、通告间隔、认证方式interface必须和实际网卡名一字不差auth_pass只取前 8 位vrrp_script自定义健康检查脚本配合track_script改优先级脚本必须返回 0 或非 0路径写绝对路径virtual_serverIPVS 四层转发与真实服务器健康检查只有编译时带上 IPVS 支持才生效不需要就--disable-lvs顺序上也有讲究vrrp_script必须定义在引用它的vrrp_instance之前否则启动时直接报找不到对象。这类语法错误在老版本里的提示并不友好经常只给一行 “Unknown keyword”所以配置写完先用命令行做一次配置检查你的构建里如果有--config-test就用keepalived --help能确认比反复重启进程高效得多。2.3 编译前把内核和依赖对齐IPVS 这条腿最挑环境只有 VRRP 需求的话这份源码几乎不挑环境gcc、make、openssl-devel 装好就能过。一旦要用 IPVS就必须让 configure 找到和当前运行内核版本一致的内核源码或头文件它是靠这个来读ip_vs.h里的结构体定义的。找错版本、或者只装了kernel-headers没装kernel-devel编译过程可能不报错但运行起来 IPVS 初始化失败VIP 一切正常、四层转发就是不通这个坑后面第 5 章还会展开。# 确认运行内核版本后面所有路径都要和它对上 uname -r # 检查内核开发包是否装全版本号必须与 uname -r 完全一致 rpm -q kernel-devel-$(uname -r) || echo 缺 kernel-develIPVS 相关头文件找不到 # IPVS 是内核模块先确认能加载没有就手动加载并观察内核日志 lsmod | grep -E ^ip_vs || modprobe ip_vs dmesg | tail -5 # 编译期依赖缺了 configure 会直接停下来提示 rpm -q openssl-devel || yum install -y openssl-devel这段命令的意图是“先验证再编译”而不是装完环境就闷头 make。uname -r的输出要和/usr/src/kernels/下的目录名一字不差modprobe ip_vs之后lsmod能看到模块说明内核这一侧具备条件openssl-devel是健康检查里 SSL 相关功能需要的虽然纯 VRRP 场景用不到但 configure 的检查逻辑会去探测它。常见做法是把这几步写进一个环境准备脚本新机器上跑一遍再动手编译。3. 从 tar 包到能跑的进程编译参数、目录落点和最小可用配置源码包最大的好处是可以精确控制装到哪、开哪些功能。代价是每一步都得自己决定尤其--prefix和--sysconfdir一旦定错后面写 systemd 单元和运维脚本时到处都要跟着改。这一章按顺序走一遍命令可以直接抄。3.1 configure 参数逐个说清三个选项决定后面所有路径拿到包先别急着./configure用--help看一下这个版本到底支持哪些开关。不同发行版打包时可能打过补丁选项集合会有出入这一点比背参数表更靠谱。tar -xzf keepalived-1.2.13.tar.gz cd keepalived-1.2.13 # 先看一眼这个构建支持哪些开关重点找 prefix / sysconfdir / kernel-dir / disable-lvs ./configure --help | grep -E prefix|sysconfdir|kernel-dir|lvs|vrrp看完再决定怎么配。我一般会把程序装到/usr/local/keepalived配置文件单独放到/etc/keepalived好处是升级时直接换 prefix 下的二进制配置不动坏的是一旦忘了--sysconfdir配置文件会跟着装到/usr/local/keepalived/etc/keepalived/下面后面所有脚本里的路径全得改。./configure \ --prefix/usr/local/keepalived \ --sysconfdir/etc/keepalived \ --with-kernel-dir/usr/src/kernels/$(uname -r)三个参数的含义分别是--prefix决定sbin/、bin/这些目录的根keepalived主程序和genhash工具都装在里面--sysconfdir决定配置文件最终落在哪也就是/etc/keepalived/keepalived.conf--with-kernel-dir指向内核源码树IPVS 支持靠它才能编进去。如果这台机器只做 VIP 漂移、不做四层转发把最后一行换成--disable-lvs --disable-lvs-syncd更省事既不用装内核开发包也不会有运行期 IPVS 初始化失败的告警。configure 结束时留意最后几行汇总它会把是否启用 VRRP、是否启用 IPVS 明确打出来。3.2 make install 之后的目录落点与开机自启编译本身没什么可调的把输出留一份日志出问题时比翻屏找错误快得多。make -j$(nproc) 21 | tee build.log # 编译失败时先看最后 30 行通常是头文件找不到或者内核版本不匹配 [ -s build.log ] tail -30 build.log make install # 确认关键文件都落地了 ls -l /usr/local/keepalived/sbin/keepalived ls -l /etc/keepalived/keepalived.conf ls /usr/local/keepalived/etc/rc.d/init.d/1.2.13 的make install会把示例配置和一份 SysV 风格的启动脚本一起放进去位置在$prefix/etc/rc.d/init.d/keepalived。新系统上没有chkconfig用 systemd 包一层更省心注意Typeforking和 PID 文件路径要和程序实际行为对上。cat /etc/systemd/system/keepalived.service EOF [Unit] DescriptionKeepalived VRRP daemon Afternetwork.target [Service] Typeforking ExecStart/usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf ExecReload/bin/kill -HUP $MAINPID PIDFile/var/run/keepalived.pid Restarton-failure RestartSec5 [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now keepalived systemctl status keepalived --no-pager-D是把日志级别调到详细排查阶段很有用稳定运行后可以去掉-f显式指定配置文件路径避免程序去读编译时写死的默认位置PIDFile必须和程序实际写的一致默认是/var/run/keepalived.pid写错了 systemd 会一直报 “start operation timed out”。Restarton-failure是后悔药进程因为配置错误崩掉时能被拉起来同时也让日志里留下完整的错误堆栈。3.3 一份最小可用的双机配置和它的验证方法下面这份配置两台机器几乎一样只有router_id和priority不同。核心思路是两端都写 BACKUP靠优先级决出主preempt_delay给一段时间缓冲避免刚重启就被抢回去。cat /etc/keepalived/keepalived.conf EOF ! 两节点最小可用配置本机 router_id 与 priority 按节点改 global_defs { router_id HA_NODE_A notification_email { } } vrrp_script chk_svc { script /etc/keepalived/chk_svc.sh interval 2 weight -30 fall 3 rise 2 } vrrp_instance VI_1 { state BACKUP # 两端都写 BACKUP避免同时启动抢主 interface eth0 # 必须是本机真实网卡名 virtual_router_id 51 # 同一广播域内唯一 priority 120 # 另一台写 100差值建议 ≥20 advert_int 1 authentication { auth_type PASS auth_pass Kp2013x # 只取前 8 位两端必须一致 } preempt_delay 30 # 30 秒内不抢占防止抖动 notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault virtual_ipaddress { 192.168.10.100/24 dev eth0 } track_script { chk_svc } } EOF # 启动后第一件事VIP 有没有挂到网卡上 ip -4 addr show eth0 | grep 192.168.10.100 # 再看日志里有没有进入 MASTER 的记录 journalctl -u keepalived -n 30 --no-pager参数上值得多说两句。priority差 20 以上是为了给weight留出下降空间——上面配了weight -30健康检查失败时本机优先级从 120 掉到 90低于对端的 100才可能让位如果差值只有 10 而 weight 是 -30优先级被扣到负数行为会很怪。fall 3表示连续 3 次检查失败才判定异常rise 2表示连续 2 次成功才恢复这类参数默认值偏激进真实业务上给两三次的容错更稳。preempt_delay只在非抢占状态下有意义配合两端 BACKUP 的写法能显著减少“网络抖一下主备来回跳”的情况。4. 切换到底有多快用抓包和脚本把“大概三秒”量化出来配置跑起来只是开始真正要回答的是两个问题现在到底谁在发通告、切换要多久。这两个问题靠猜不行得抓包和打点。三秒钟的切换对无状态服务无所谓对有连接状态的服务就是一批超时值得花半小时测一次。4.1 抓包确认通告两个节点必须都在说话VRRP 用的是 IP 协议号 112老版本 keepalived 走的是组播 224.0.0.18。在任意一台机器上抓十来个包就能看出谁在当主、通告间隔是不是 1 秒。# -nn 不做域名和端口解析proto 112 直接过滤 VRRP tcpdump -i eth0 -nn -c 10 ip proto 112 # 如果看不到包先确认网卡名和多播是否被过滤虚拟化环境常见 ip link show eth0 ip maddr show dev eth0 | grep -i 01:00:5e:00:00:12正常输出里会看到VRRPv2, advert 1, prio 120这样的字段prio就是当前通告方的优先级advert是通告间隔。如果只能看到一台在发说明 Backup 侧根本没起来要么interface写错要么认证不一致导致包被丢弃要么防火墙把 112 协议挡了。判断谁在发有个笨办法也很有效——在 Backup 上抓能抓到 Master 的包就说明链路通、协议通问题一定在本地配置。主动验证切换不要用reboot太慢且干扰因素多。直接停服务更干净还能顺便观察notify脚本有没有被触发。# 在 Master 上停掉进程模拟故障 systemctl stop keepalived # 立刻在 Backup 上连续观察 VIP 是否出现间隔 0.5 秒看变化过程 for i in $(seq 1 20); do date %T.%N; ip -4 addr show eth0 | grep -c 192.168.10.100; sleep 0.5; done这段循环的价值在于给出切换耗时的实际数字而不是“感觉挺快”。按前面advert_int 1的配置理论上的检测时间在 3 秒上下加上脚本检查和 ARP 通告实测往往落在 3 到 5 秒之间。数字明显偏大时先看advert_int是不是被改过再看健康检查的interval × fall是不是拖长了判定时间。4.2 三个和时间有关的参数把切换窗口调到业务能接受参数作用调大调小的代价advert_int通告间隔秒调小检测更快但包更多1 秒是通用取值别低于 1garp_master_delay成为 Master 后延迟发免费 ARP 的秒数调大让交换机有时间收敛代价是流量中断变长preempt_delay启动后多久才允许抢占调大避免抖动但故障恢复后回切变慢garp_master_delay是个容易被忽略的点。VIP 挪过去之后如果上联交换机和网关的 ARP 表还是旧记录流量会继续往老机器打表现为“VIP 已经在新机器上了但外部访问还是断的”。常见做法是保持默认值不要乱改同时在notify_master脚本里补一次免费 ARP主动把新位置广播出去。4.3 notify 脚本接管状态变化先把传参打出来再写逻辑notify_master、notify_backup、notify_fault三个钩子在状态变化时执行是接监控告警、调内核参数、刷 ARP 缓存的入口。这里有个血泪经验不同小版本传给脚本的参数个数和顺序并不完全一致照着网上抄的脚本经常拿错变量导致告警里写的是错的节点名。稳妥做法是先写一个只打日志的脚本跑一次切换看看实际传了什么。cat /etc/keepalived/notify.sh EOF #!/bin/bash # 先把全部参数落盘确认传参格式后再往里加业务逻辑 LOG/var/log/keepalived_notify.log echo $(date %F %T) args:[$*] $LOG case $* in *master*) # 成为主补一次免费 ARP让网关尽快更新表项 arping -U -c 3 -I eth0 192.168.10.100 $LOG 21 ;; *backup*) # 降为备这里适合做一些连接清理或缓存回收 ;; *fault*) # 本机异常走内部告警通道 ;; esac EOF chmod 755 /etc/keepalived/notify.sh脚本必须给执行权限路径必须是绝对路径——keepalived 启动后工作目录不确定相对路径必然翻车。日志里如果一条记录都没有先确认脚本本身能不能在 shell 里跑通再看journalctl里有没有 “Cannot execute” 之类的提示。另外脚本里不要写耗时的操作它是在状态切换路径上同步执行的一个卡住十秒的脚本会把切换窗口整体拉长。5. 避坑1.2.13 在老内核和新环境里最常翻车的五个地方这份源码是十多年前的产物放到今天的环境里出问题的往往不是它的逻辑而是它假设的环境已经变了。下面五条都是现象明确、原因清楚、能当场解决的。5.1 两台机器同时是 MASTER先查防火墙有没有放行 112现象是ip addr在两台上都能看到 VIP抓包能看到两个不同优先级在同时通告业务时通时断。原因是 VRRP 使用 IP 协议号 112很多主机的默认策略是只放行 TCP/UDP其余一律丢弃于是两台互相收不到对方的通告都认为自己是唯一的主。解决是按网段放行协议号 112而不是放行某个端口。放行之后重启两端进程用 4.1 的抓包方法确认两边都能看到对方再观察五分钟确认不再反复。5.2 认证和 VRID 串味双主和串台的两种典型现象之一是两台配置看起来一样但就是互不认主现象之二是隔壁机柜的另一套集群偶尔把 VIP 抢走。前者多半是auth_pass超过 8 位后被截断或者两端本来写的就不一致包被静默丢弃日志里通常只有一行轻描淡写的认证失败。后者是virtual_router_id撞了——这个 ID 在同一广播域里必须唯一跨机柜如果用的是同一个二层网络一样会串。解决办法很土但有效把全网的 VRID 登记在一张表里分配前先查auth_pass统一写成 8 位以内两端用同一份模板生成配置。5.3 IPVS 初始化失败VIP 正常但四层转发完全不生效现象是进程活着、VIP 也挂上了但virtual_server里的后端一个都连不通日志里出现和 IPVS 初始化相关的报错通常是协议不可用一类的提示。原因有两个层面内核里ip_vs模块没加载或者编译时--with-kernel-dir指向的源码版本和运行内核不一致导致编译进去的结构体定义对不上。解决顺序是先modprobe ip_vs并确认lsmod有输出仍然不行就重新编译把内核目录指到uname -r对应的那一份。如果这台机器的定位本来只是 VIP 漂移最干脆的做法是重新 configure 时加--disable-lvs从根上不要这条腿。5.4 网卡名写错进程起来了VIP 就是不出现现象是systemctl status显示 active日志里翻半天只有几行“找不到接口”之类的提示ip addr里始终没有 VIP。原因很直接interface写的是eth0而机器实际网卡叫ens33或者eno1或者做了 bonding 之后应该写bond0。这个错误在新装系统、虚拟机克隆、批量扩容之后特别高频。解决办法是在配置模板里不要硬编码网卡名部署脚本里用ip route get 1.1.1.1或ip -o link取出默认出口网卡名再替换进配置从流程上消灭这个错误。5.5 notify 脚本静默不执行权限、路径和环境变量三连现象是切换本身正常VIP 也确实漂过去了但告警没发、ARP 没刷日志里干干净净什么都没有。原因通常有三种脚本没有执行权限配置里写的是相对路径脚本里调用的命令依赖PATH而 keepalived 拉起子进程时的环境变量很精简。解决办法是chmod 755加绝对路径脚本开头显式export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin所有外部命令也写全路径。脚本第一行先把$*打到日志里出问题时至少能确认它到底有没有被调用。6. 上线前的最后一道工序把 VIP 漂移变成一张能勾选的表配置写完、切换测过剩下的风险基本都来自“当时以为对”。我习惯在交付前跑一遍固定动作把结果记在变更单里出问题时能立刻区分是环境变了还是配置改错了。检查项动作期望结果通告可达两端各抓 10 个ip proto 112的包两边都能看到对方的优先级身份唯一ip -4 addr两端各查一次同一时刻只有一台持有 VIP切换耗时停主进程后 0.5 秒轮询3 到 5 秒内完成漂移钩子生效查看 notify 日志每次状态变化都有一条记录回切行为重启原主节点preempt_delay内不抢回超时后按优先级回切有一次在一套跨机柜的环境里上面五项全过了业务却仍然间歇性超时最后查出来是两台机器的系统时间差了十几分钟日志时间线对不上排查时把因果看反了。从那以后我每次做双机第一件事是先chronyc sources或者ntpq -p确认两端时间同步再动 keepalived 的配置——这个习惯帮我省掉的排查时间比任何调参技巧都多。希望帮到你。本文还有配套的精品资源点击获取