keepalived-1.2.13源码编译与VIP漂移配置排错实战
发布时间:2026/10/27 17:02:30 锦皓数字建站

简介该资源为 keepalived 1.2.13 官方源码压缩包面向运维工程师、系统架构师及高可用方案学习者用于搭建基于 VRRP 与 LVS 的网络服务故障切换实验环境解决主备节点自动接管、健康检查与负载均衡调度等实际问题适合具备一定 Linux 网络基础的中级读者研读。包内共 188 个文件以 62 个 .h 头文件与 61 个 .c 源文件为主体完整呈现 vrrp、check 等核心模块的实现逻辑另有 keepalived.conf 样例、man 手册页、configure 构建脚本及 install-sh 等安装辅助文件并附带 pem 证书、sysconfig 服务脚本与 in/init 模板便于直接编译部署。压缩包仅 334KB轻量易携。目前已有 369 人学习下载。借助这份源码读者可对照真实代码理解 VRRP 通告、优先级选举与 track_script 健康检查的执行流程结合示例配置完成主备切换与 LVS 虚拟服务器组调度验证并参照 changelog、TODO 与 contrib 目录中的脚本积累排错与二次开发思路。1. 一个 2014 年的 keepalived-1.2.13.tar.gz为什么今天还得装上个月接手一台老业务机系统还是 CentOS 6前端跑 LVS-DR两个节点上跑着 keepalived 做 VIP 漂移。运维交接文档里只留了一句话keepalived 版本别动用的就是 keepalived-1.2.13.tar.gz。我一开始不信邪直接 yum 装了源里能拿到的新版本结果老配置里那几段virtual_server语法新版本直接不认启动日志刷Unknown keyword节点起来三秒就退。回滚、重新编译、把 1.2.13 装回去前后折腾了一个下午这就是典型的“版本对不上配置全是白搭”。这篇记的就是这套环境从依赖、编译、配置到验证的完整走法适合还在维护 1.2.x 老集群、或者要给老项目复刻一套 VIP 高可用的人。2. 装前把环境钉死keepalived 1.2.13 的依赖清单与内核开关源码编译最怕的不是编译不过是编到一半才发现少个包然后在一个已经装乱的系统上反复试。我现在的习惯是先把环境三件套核清楚再动手解压。2.1 先对齐三行版本号系统、内核、内核头文件keepalived 1.2.13 这个年代的东西对内核头文件的路径非常敏感。--with-kernel-dir指向的目录如果和当前运行内核不是同一个版本configure 阶段不会直接报错而是悄悄把 IPVS 支持关掉等到你配 LVS 的时候才发现virtual_server段根本不生效。先看三行输出cat /etc/redhat-release # 系统大版本CentOS 6/7 都行 uname -r # 当前运行内核比如 2.6.32-754.el6.x86_64 ls -d /usr/src/kernels/$(uname -r) # 内核头文件目录是否存在第三条命令没输出说明kernel-devel没装或者版本对不上。常见做法是yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r)这里有个坑要说清楚yum install kernel-devel不带版本号装的是仓库里最新的内核头文件而机器当前跑的可能还是老内核两边差一个版本号/usr/src/kernels/下就多出一个不匹配的目录。我现在一律带$(uname -r)锁死版本装完再ls一遍确认目录名和uname -r完全一致。如果这套环境只做纯 VRRP 的 VIP 漂移不接 LVS那内核头文件其实可以不装后面 configure 时跳过--with-kernel-dir就行这一点在第 3 章会展开说。2.2 编译依赖一次装齐别装一个试一个keepalived 1.2.13 的依赖不多但每个都卡在关键节点上。下面这张表是我在不同机器上反复踩出来的清单按这张表一次装完基本不会在 configure 阶段来回折腾。组件包名是否必须作用编译器gcc、make必须源码编译SSL 库openssl-devel建议装健康检查走 HTTPS 时用得上参数解析库popt-devel视情况部分环境 configure 会报 popt 缺失内核头文件kernel-devel-$(uname -r)接 LVS 时必装提供 IPVS 头文件netlink 库libnl-devel可选启用 libnl 版本的 IPVS 同步对应的安装命令yum install -y gcc make openssl-devel popt-devel # 接 LVS 的机器再多装一个版本号必须和 uname -r 一致 yum install -y kernel-devel-$(uname -r)openssl-devel我建议无脑装上。keepalived 1.2.13 的健康检查支持 SSL如果编译时没带 OpenSSL后面配SSL_GET之类的检查会直接不可用而你当时并不会察觉只觉得“怎么检查永远是成功的”。popt-devel属于“装了不亏”的类型某些精简系统上 keepalived 的 configure 会因为找不到 popt 直接退出。装完可以顺手验证一下rpm -q gcc make openssl-devel gcc --version | head -1gcc 版本不需要追求新旧1.2.13 的源码在 gcc 4.x 到 7.x 上都能过。如果你在更新的发行版上编译可能会遇到编译告警被当成错误处理的情况后面第 3 章有对应的绕法。2.3 内核参数与防火墙放行 VRRP而不是关掉防火墙keepalived 的 VRRP 通告走的是组播目的地址224.0.0.18IP 协议号 112。很多环境里 iptables 默认策略是 DROP结果是两边 keepalived 都在跑日志也都正常但谁也收不到谁的通告双双进入 MASTER 状态VIP 同时挂在两台机器上这就是最典型的脑裂。所以宁可放行一条规则也不要把防火墙整个关掉。CentOS 6 的 iptables 写法# 协议名 vrrp 在某些系统的 /etc/protocols 里没有直接用协议号更稳 iptables -I INPUT -p 112 -j ACCEPT iptables -I OUTPUT -p 112 -j ACCEPT service iptables saveCentOS 7 上用 firewalld 的话对应的是firewall-cmd --permanent --add-protocolvrrp firewall-cmd --reload除了防火墙还有两个内核参数建议在装之前就打开写进/etc/sysctl.conf里# 允许服务监听非本机 IP后端要绑 VIP 时必需 net.ipv4.ip_nonlocal_bind 1 # LVS-NAT 模式需要转发纯 VRRP 或 DR 模式可以不开 net.ipv4.ip_forward 1ip_nonlocal_bind这一条是血泪经验。VIP 漂移到备机之后如果后端 Nginx 绑的是0.0.0.0没问题但如果绑的是具体的 VIP 地址没有这个参数就会启动失败报Cannot assign requested address而 keepalived 自身的日志一切正常排查方向很容易跑偏到 VIP 上。最后看一眼 SELinuxgetenforce # 如果是 Enforcing临时切成 permissive 观察 setenforce 0SELinux 在 CentOS 6 上对 keepalived 的影响不算大但在某些加固过的系统上会拦住它执行track_script里自定义的检查脚本表现是脚本手动跑没问题、keepalived 调用就失败。装之前先切成宽容模式等整条链路验证通了再回头收紧策略比一上来就跟 SELinux 死磕效率高得多。3. 源码编译 keepalived-1.2.13configure 参数与安装路径的取舍依赖齐了之后编译本身其实很快真正决定后面好不好维护的是 configure 阶段的几个参数。参数选对了配置文件、启动脚本、sysconfig 会自己落到系统标准位置选错了后面每一处都得手工拷贝拷贝还容易漏。3.1 解包与 configure 的三个关键参数包放在哪不重要重要的是别在/root下直接解压然后make install源码目录留一份以后要重编或者对比版本还用得上。tar -zxvf keepalived-1.2.13.tar.gz -C /usr/local/src/ cd /usr/local/src/keepalived-1.2.13configure 我一般这么写./configure \ --prefix/usr/local/keepalived \ --sysconfdir/etc \ --mandir/usr/local/share/man \ --with-kernel-dir/usr/src/kernels/$(uname -r)四个参数逐个说清楚--prefix/usr/local/keepalived决定可执行文件的位置编完之后主程序是/usr/local/keepalived/sbin/keepalived。之所以不直接装到/usr/local是为了让整个 keepalived 的安装物集中在一个目录里将来要卸载或者换版本rm -rf这一个目录就干净了不会和系统里其他/usr/local/sbin下的东西混在一起。--sysconfdir/etc是这套参数里最关键的一个。它会把配置文件装到/etc/keepalived/keepalived.conf把 sysconfig 文件装到/etc/sysconfig/keepalived把启动脚本装到/etc/rc.d/init.d/keepalived。不写这个参数默认会落到/usr/local/etc下面后面 init 脚本、systemd 单元、人肉维护的路径全要跟着改属于给自己找事。--mandir只是 man 页的位置不影响运行写不写都行写上是为了man keepalived.conf能查到语法1.2.13 的官方配置样例就是靠 man 页带出来的排查语法问题时非常好用。--with-kernel-dir只在要接 LVS 时加。如果这套环境只是纯 VRRP 做 VIP 漂移把这一行去掉即可configure 会自动跳过 IPVS 相关模块的编译少一层依赖也少一堆潜在报错。判断标准很简单配置里有没有virtual_server段。有就加没有就不加。3.2 make 报错的三类现场处理configure 跑完之后先别急着 make往上翻一下它打印的摘要这是判断参数有没有生效最直接的方式Keepalived configuration ------------------------ Keepalived version : 1.2.13 Use IPVS Framework : Yes Use VRRP Framework : Yes Use VRRP authentication : Yes Use OpenSSL : YesUse IPVS Framework是 No 而你的配置里又要写virtual_server说明--with-kernel-dir指错了或者头文件版本对不上回头查第 2 章那一节。Use OpenSSL是 No说明openssl-devel没装上回头补装后重新 configure注意要先make clean再跑一遍。make 阶段我遇到过的报错大致三类第一类是找不到 OpenSSL 头文件报Cannot find openssl或者链接阶段一堆undefined reference to SSL_xxx。这种情况九成是openssl-devel没装剩下一成是装了但装在非标准路径需要显式指定--with-openssl/usr再 configure 一次。第二类是Popt libraries is required直接补popt-devel重来即可。第三类是高版本 gcc 下把警告当错误报一堆warning: ... [-Werror...]然后中断。这种不用改源码把编译选项放宽就行make CFLAGS-O2 -g -w-w是关闭所有告警-O2 -g保持正常的优化和调试信息。这只影响编译过程不改任何运行行为属于临时绕过编出来的二进制和正常编译没有区别。3.3 make install 之后文件去哪儿了目录对照与拷贝make make install装完之后别直接启动先核对落点。用--sysconfdir/etc的话正常情况下应该是这样文件安装后路径用途主程序/usr/local/keepalived/sbin/keepalived守护进程本体配置文件/etc/keepalived/keepalived.confVRRP 与 LVS 配置sysconfig/etc/sysconfig/keepalived启动参数启动脚本/etc/rc.d/init.d/keepalivedSysV 服务脚本man 页/usr/local/share/man/man5/keepalived.conf.5语法查询核实命令ls -l /usr/local/keepalived/sbin/keepalived ls -l /etc/keepalived/keepalived.conf ls -l /etc/sysconfig/keepalived ls -l /etc/rc.d/init.d/keepalived四个都在说明--sysconfdir生效了后面不用手工拷贝。如果keepalived.conf落在了/usr/local/keepalived/etc/keepalived/下面说明 configure 时--sysconfdir被漏掉了这种情况要么重新 configure 编译一遍要么老老实实按目录逐个cp过去再改 init 脚本里的KEEPALIVED_CONF变量。还有一步容易被忽略把主程序软链到/usr/sbin下这样service keepalived start之外的场景比如人肉which keepalived、第三方监控脚本能直接找到命令ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived3.4 注册成系统服务init.d 与 systemd 两套写法CentOS 6 用 SysV装完基本就能用但启动参数在/etc/sysconfig/keepalived里默认是KEEPALIVED_OPTIONS-D-D是详细日志把 VRRP 状态切换的细节打到 syslog 里排查阶段非常有用建议保留等到稳定运行几周之后如果嫌日志多再改成不带-D。其他常用参数-f指定配置文件-d让日志走 syslog-l直接写本地文件-n前台运行不 fork。init 脚本内部已经带上了-f /etc/keepalived/keepalived.conf一般不用自己再加。CentOS 7 上没有现成的 unit 文件我自己写一个[Unit] DescriptionKeepalived Afternetwork.target [Service] Typeforking ExecStart/usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf ExecReload/bin/kill -HUP $MAINPID KillModeprocess Restarton-failure [Install] WantedBymulti-user.targetTypeforking是必须的keepalived 起来之后会自己 fork 到后台用simple会让 systemd 误以为主进程退出了反复重启。KillModeprocess保证 stop 的时候只杀主进程不连坐子进程否则 VRRP 子进程可能被强杀状态文件残留下次启动行为异常。ExecReload用 HUP 信号keepalived 收到后会重新读配置这个动作对 VRRP 实例是平滑的不会导致 VIP 短暂消失改优先级之类的参数可以靠它生效。4. keepalived.conf 落地VRRP 实例、权重与健康检查配置文件写不对前面装得再干净也是白费。keepalived 1.2.13 的配置语法和后面的 1.3、2.x 有差异尤其是virtual_server段和track_script的权重处理照抄新版本教程很容易翻车。4.1 global_defsrouter_id 别两台写成一样配置文件的第一段是全局定义global_defs { router_id LVS_NODE_A notification_email { opsexample.com } notification_email_from keepalivedexample.com smtp_server 127.0.0.1 smtp_connect_timeout 30 }router_id是每个节点在日志里的标识两台机器必须不一样。见过不止一次两台都写LVS_DEVEL日志里全是同一个名字切换的时候根本分不清是哪台在说话。命名习惯是业务名_节点序号主机名不方便改的时候这一行就是唯一能帮你定位的东西。邮件通知这一段在 1.2.13 里是可选的而且要求本机有可用的 SMTP大部分内网机器连不上外网邮件服务器配上之后反而会在日志里刷连接超时。我的做法是没有邮件中继就整段删掉靠日志和监控告警别留一段永远失败的通知配置在那制造噪音。4.2 vrrp_instance主备两台怎么对齐这一段是整个配置的核心两台机器要按同一张表对齐vrrp_instance VI_1 { state MASTER # 备机写 BACKUP interface eth0 # 必须写成真实的网卡名 virtual_router_id 51 # 同一组必须一致 priority 100 # 备机写 90 或更低 advert_int 1 # 通告间隔单位秒 nopreempt # 备机也写上 authentication { auth_type PASS auth_pass Kv1p2p13 # 两台必须一致且只取前 8 位 } virtual_ipaddress { 192.168.10.100/24 dev eth0 label eth0:1 } }几个参数单独拎出来讲。interface写错网卡名是新手最常见的翻车点尤其是机器上有 bond、有 docker0 的环境eth0不一定是出口网卡先用ip route get 8.8.8.8确认默认路由走哪个口再回来填。virtual_router_id的取值范围是 1 到 255同一个二层网络里不同组的 keepalived 必须用不同的值。同机房多套集群共用 VLAN 的情况非常常见两个组撞了同一个 ID表现是“A 组的 VIP 跑到 B 组机器上”日志里却看不出任何异常因为对 keepalived 来说它只是收到了一个和自己同 ID 的通告。auth_pass的坑在于 1.2.13 只取前 8 个字符你在配置里写 16 位密码觉得很安全实际参与认证的只有前 8 位两台机器前 8 位不一致就认证失败日志里的报错是Received advertisement with invalid auth之类的不算明显。长度控制在 8 位以内两台严格一致别在这上面炫技。nopreempt的作用是让备机接管之后不再主动把 VIP 还回去。不加它主机恢复后因为优先级高会立刻抢回 VIP对于用连接保持的业务这一抢就是一批长连接断开。注意nopreempt在 1.2.13 里对state MASTER的那一端是无效的两边都写上是常见做法真正起作用的是备机那端。4.3 virtual_ipaddress三种写法与各自的适用场景VIP 这一段有三种常见写法选哪种取决于你的网络环境virtual_ipaddress { 192.168.10.100/24 dev eth0 label eth0:1 192.168.10.101/24 dev eth0 192.168.10.102 }第一种带子网掩码、设备名和 label是最明确的写法。label eth0:1会给网卡加一个别名标签ip addr里能看到eth0:1这个标识人肉排查时一眼就能认出这是漂移过来的地址而不是手工配的。缺点是某些云主机环境的网卡驱动不支持别名标签加了会报错这种情况就去掉 label 只留dev eth0。第二种只带掩码和设备也就是不写 label兼容性最好。第三种只写地址让 keepalived 自己去推断掩码和设备。看着省事实际在有多块网卡的机器上推断结果未必是你想要的我一般不用。一个实例里可以放多个 VIP写在同一对花括号里即可它们会作为一个整体漂移。如果业务需要一部分 VIP 跟着 A 服务走、另一部分跟着 B 服务走那应该拆成两个vrrp_instance用不同的virtual_router_id而不是塞在一个实例里。4.4 vrrp_script 加 track_script让 VIP 跟着进程走默认情况下keepalived 只关心对端还活不活着本机的 Nginx 挂了它照样认为自己是健康的。要让它感知业务进程得配健康检查脚本。先定义脚本vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 2 }再在实例里引用vrrp_instance VI_1 { # ... 前面的参数省略 track_script { chk_nginx } }脚本本身要满足一个硬性约定健康返回 0异常返回非 0。写成这样#!/bin/bash # 检查本机 Nginx 是否存活异常时返回 1 COUNT$(ps -C nginx --no-header | wc -l) if [ $COUNT -eq 0 ]; then exit 1 fi exit 0赋权chmod x /etc/keepalived/check_nginx.sh这点不用多说但每次都能遇到忘了加执行权限、然后盯着日志找半天的人。参数含义interval 2是每 2 秒执行一次fall 2是连续失败 2 次才算真的故障rise 2是连续成功 2 次才算恢复。这两个值不要调得太小脚本本身有启动开销间隔 1 秒、阈值 1 次的环境里一次系统负载抖动就能触发误切换。weight -20表示检测失败时本机优先级减 20配合主 100、备 90 的配置失败后主变 80低于备机VIP 才会漂走。这里有个 1.2.13 上的经典问题值得单独提醒weight的绝对值必须大于主备之间的优先级差值否则减完之后还是比备机高脚本明明检测失败了但 VIP 就是不漂。主 100 备 90 差 10weight至少写 -11写 -20 更保险。反过来weight为正数表示检测成功时加分那种用法适合多个备机之间比较健康度配置起来更绕一般环境用负权重就够了。5. keepalived 1.2.13 装完不生效五类现场排查这套东西最让人抓狂的地方在于它挂掉的时候往往什么错都不报你只能从现象倒推。下面五条是我在不同环境里真实遇到过的按“现象 → 原因 → 解决”整理遇到问题时按顺序对照即可。5.1 两台同时是 MASTERVIP 挂在两个节点上现象两台机器ip addr都能看到 VIP业务时通时不通抓包能看到两个源 IP 都在发 VRRP 通告。原因三种可能。一是防火墙拦了 VRRP 协议号 112双方互相收不到通告各自认为对端已死二是virtual_router_id撞了或者两台priority写成了一样的值三是两台机器不在同一个二层网络里组播根本过不去。解决先tcpdump -i eth0 -nn proto 112看能不能收到对端的包。收不到查 iptables 和交换机是否禁了组播收得到但状态还是不对检查两台的virtual_router_id、auth_pass前 8 位、priority。优先级必须不同这是硬要求。5.2 状态在 MASTER 和 BACKUP 之间反复横跳现象日志里Entering MASTER STATE和Entering BACKUP STATE交替出现间隔几十秒一次VIP 频繁上下。原因通告丢包导致的抖动。常见于advert_int设得太小比如 0.1 秒、网络本身有丢包、或者虚拟机环境里 CPU 抢占严重导致 keepalived 进程被调度延迟。解决把advert_int调回 1 秒如果环境本身抖动大可以调到 2。同时检查track_script的fall和rise是不是都设成了 1改成 2 或 3 能过滤掉大部分瞬时抖动。5.3 VIP 加上去了但业务访问不通现象keepalived 状态正常VIP 在ip addr里能看到但从其他机器 ping 这个 VIP 不通。原因分两种。如果 ping 都不通多半是交换机或路由器的 ARP 表没更新或者 VIP 不在当前网段导致回程路由不对如果 ping 通但服务连不上检查后端进程有没有监听0.0.0.0以及net.ipv4.ip_nonlocal_bind有没有打开。解决在持有 VIP 的节点上执行arping -I eth0 -c 3 -S VIP地址 网关地址主动刷新上游 ARP进程绑定问题按第 2 章的内核参数处理改完sysctl -p生效。5.4 track_script 检测失败但 VIP 不漂移现象手动执行检查脚本返回 1日志里也能看到脚本失败但 VIP 纹丝不动。原因weight的绝对值小于主备优先级差值。主 100 备 90weight -10失败后本机变 90和备机持平keepalived 在这种情况下的行为并不总是按预期切换。解决把weight调到明显大于差值比如 -20 或者 -30。改完用kill -HUP重载配置不需要重启进程。5.5 配置文件报 Unknown keyword进程起不来现象service keepalived start之后秒退日志里写着Unknown keyword xxx指向配置文件的某一行。原因抄了高版本 keepalived 的配置。1.2.13 不认识vrrp_iptables、accept、version 2这些后来才加的关键字也不支持某些健康检查的新写法。解决对照 man 页确认语法man keepalived.conf就是 1.2.13 自己的语法文档比网上任何教程都准。找不到的关键字直接删掉或者查 1.2.13 的官方样例配置改写。删之前先备份cp keepalived.conf keepalived.conf.bak.$(date %F)这个习惯救过我至少三次。6. 验证 VIP 真能漂移三件套看结果6.1 ip addr、抓包、日志三样一起看配置写完之后不要只看进程在不在那没有意义。三样东西一起看才作数# 第一样VIP 在不在以及挂在哪个网卡上 ip addr show eth0 | grep -A2 inet # 第二样VRRP 通告有没有在发正常是每秒一个 tcpdump -i eth0 -nn proto 112 -c 5 # 第三样状态切换的日志CentOS 6 看 messages7 用 journalctl tail -f /var/log/messages | grep -i keepalivedtcpdump那条命令抓到 5 个包就自动退出正常应该看到源地址是本机、目的地址是224.0.0.18、协议号 112 的报文间隔一秒左右。抓不到说明通告没发出去回头查interface和防火墙。日志里Entering MASTER STATE之后应该跟一行Netlink: filter at 224.0.0.18之类的内容说明通告已经开始发送。6.2 手动触发一次切换计时验证不能只看“现在是好的”得真的切一次。在主机上执行service keepalived stop # 或者 systemctl stop keepalived然后在备机上盯着watch -n1 ip addr show eth0 | grep inet 正常情况下 VIP 会在 3 到 4 秒内出现这个时间约等于advert_int × 3加上脚本检测的耗时。超过 10 秒才漂过来说明通告间隔或者fall阈值设得太保守了业务侧会有明显感知。切过去之后再把主机拉起来确认 VIP 不会立刻被抢回去这就是nopreempt的作用然后人工执行一次service keepalived restart让主备归位。6.3 交付前的自检表每次交付前我都过一遍这张表比事后救火便宜得多检查项合格标准两台的 router_id不同两台的 priority主高备低差值小于等于 10auth_pass一致长度不超过 8 位100 秒内 VRRP 抓包每秒至少 1 个通告包停主切备耗时小于 5 秒检查脚本手动执行健康返回 0异常返回 1配置文件备份每次修改前都有带日期的副本从那以后我每次上线 keepalived 环境都会强制走一遍这个手动切换流程哪怕业务方催得再急也不跳过——因为跳过的那次往往就是凌晨两点被电话叫起来的那次。这套 keepalived-1.2.13 的源码包和配置我一般会把整个目录连同编译好的二进制一起打归档下次复刻环境直接解压省掉一整轮依赖排查。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。