news 2026/10/28 1:15:30

CentOS 7源码编译keepalived-1.2.13双机热备与VIP漂移排障

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CentOS 7源码编译keepalived-1.2.13双机热备与VIP漂移排障

简介:这是 keepalived-1.2.13.tar.gz 开源软件源码包,面向网络运维、系统管理员与高可用架构学习者,聚焦 VRRP 虚拟路由冗余协议、服务健康检查与 LVS 负载均衡支撑,可用于搭建主备故障切换实验环境、研读 1.2.13 版本的实现细节并对照配置样例理解实际部署方式。压缩包共 188 个文件,约 334KB,以 62 个 C 源文件与 61 个头文件为主体,并辅以 configure、install-sh 等构建安装脚本,init、conf、sample 等配置与示例文件,pem 证书和 readme、changelog 等说明文档,目录结构便于按模块查阅源码、编译验证和排查配置问题。已有 369 人学习下载。读者可从中获取 VRRP 状态机与报文处理、TCP/HTTP/ICMP 等健康检查机制、虚拟服务器组配置、日志与监控相关实现等具体内容,也能结合 Nginx、MySQL 高可用场景理解 Keepalived 的配置组织与故障切换逻辑,适合需要从源码和样例入手掌握网络服务连续性的中高级读者。

1. 一套跑在旧内网里的双机热备:为什么还在装 keepalived-1.2.13

去年帮某公司内网做业务迁移,对方甩过来一句「两台机器要做 VIP 漂移,版本必须跟老集群一致,keepalived-1.2.13,源码包我发你」。我第一反应是这版本够老,yum 源里随便装个新版不香吗?结果把新版编译上去之后,健康检查脚本因为权限校验直接不执行,VIP 该切的时候纹丝不动,业务在凌晨断了十几分钟。那次之后我就老实了:老环境里版本锁死不是保守,是拿事故换来的。这篇记录按「装什么、怎么装、怎么配、坏了怎么救」走一遍,适合还在维护 CentOS 7 老集群、需要源码编译 keepalived-1.2.13 的人照着复现。

2. 装前把环境列清:系统版本、编译依赖和源码包校验

动手之前先把环境盘清楚,这一步偷懒,后面编译报错能让你怀疑人生。keepalived 本身是用户态程序,VRRP 协议在应用层跑,不依赖特殊内核模块;但如果你还要用它的 LVS/IPVS 那部分能力,就得有对应的内核头文件。所以环境清单要分两块看:一块是「能编译出来」,一块是「能跑起来」。

2.1 系统与 OpenSSL 版本:决定编译顺不顺的第一道坎

keepalived-1.2.13 是 2015 年前后的代码,它对 OpenSSL 的调用方式是 1.0.x 时代的写法。CentOS 7 自带 openssl-devel 1.0.2 系列,编译基本一路绿灯;换到 OpenSSL 1.1.1 及以上的发行版,make 阶段会抛出一串EVP_MD_CTX相关的结构体不完整错误,因为 1.1 之后这些结构体被改成不透明指针了。这不是你参数写错,是代码和库的代差。

我把常见系统的适配情况列成表,选机器前先对一眼:

操作系统OpenSSL 版本编译 keepalived-1.2.13备注
CentOS 71.0.2顺利推荐,本文以此为例
CentOS 8 / Stream1.1.1大概率失败需自行处理兼容问题
Ubuntu 18.04 及以上1.1.1 / 3.0大概率失败不建议作为编译机
老版 CentOS 61.0.1顺利内核较老,注意 IPVS 头文件

如果生产机必须是新系统,常见做法是找一台 CentOS 7 的构建机编译好,把/usr/local/keepalived整个目录打包分发,再补齐运行时的popt、openssl动态库依赖。注意 glibc 版本差异,跨大版本分发前先在目标机ldd一下二进制,确认没有not found。

2.2 编译依赖:gcc、openssl-devel、popt-devel 一个都不能少

最小依赖集我一般就装这几个,别嫌少,多装的包只会让编译机的状态越来越不可复现:

# CentOS 7 编译 keepalived-1.2.13 的最小依赖集 yum -y install gcc gcc-c++ make openssl-devel popt-devel kernel-devel # 如果后续要用 IPVS/LVS 能力,再补这两个 yum -y install ipvsadm libnl-devel

逐项说清楚:gcc、make是编译底座;openssl-devel提供 VRRP 认证和加密相关头文件,缺了 configure 阶段就过不去;popt-devel提供命令行参数解析库,缺了会在 configure 末尾报Popt libraries not found,这个报错很靠后,第一次见容易懵;kernel-devel是给 IPVS 用的,只做 VIP 漂移可以不装。libnl-devel在 CentOS 7 上装的是 libnl3,而 1.2.13 检测的是 libnl1 那套 pkg-config 名字,两者对不上,所以这个包装了也未必被识别,后面 configure 参数里我会直接用开关绕开。

提示:编译机和生产机的openssl-devel版本尽量一致,否则编译出来的二进制在目标机可能因为符号版本差异起不来。

2.3 源码包落地:路径、校验和解压习惯

源码包统一放/usr/local/src,这个目录就是给编译源码用的,权限和环境都干净。拿到keepalived-1.2.13.tar.gz之后,先校验再解压,别小看这一步,传输不完整导致的解压报错能浪费你半小时:

# 进入源码目录并核对包完整性 cd /usr/local/src ls -lh keepalived-1.2.13.tar.gz sha256sum keepalived-1.2.13.tar.gz # 与提供方给出的校验值比对,一致再解压 tar -zxvf keepalived-1.2.13.tar.gz cd keepalived-1.2.13

解压后先别急着 configure,花十秒看一眼目录结构:configure在根目录,keepalived/etc/init.d/keepalived和keepalived/etc/sysconfig/keepalived是自带的启动脚本模板,这两个文件后面装服务时会用到。版本号也顺手确认一下,grep VERSION configure.in | head能看出是不是你要的 1.2.13,避免拿到改名过的包。

3. 编译安装 keepalived-1.2.13:configure 参数和安装路径怎么定

源码编译最怕的就是「一路回车」,装完发现配置跑到/usr/local/etc去了,服务脚本找不到配置文件。这一章把三个关键参数、安装产物位置和服务托管方式一次定死,后面就不用再回头改。

3.1 configure 的三个参数:--prefix、--sysconfdir、--disable-libnl

我用的 configure 命令是这样,参数不多但每个都有明确目的:

# 在源码根目录执行 ./configure \ --prefix=/usr/local/keepalived \ --sysconfdir=/etc \ --disable-libnl

--prefix=/usr/local/keepalived把二进制、库、文档全部收在一个目录下,卸载时rm -rf就干净了,不会像默认安装那样散落到/usr/local/sbin、/usr/local/lib各处。--sysconfdir=/etc是关键,它决定配置文件默认读哪里,加上这个参数后 keepalived 会去/etc/keepalived/keepalived.conf找配置,和你后面写 systemd 单元、写运维脚本时的路径习惯一致;不加的话默认落在/usr/local/etc,很多「改了配置不生效」的案子都是这个原因。

--disable-libnl是 CentOS 7 上的保命参数。1.2.13 的 configure 脚本检测的是老版 libnl 的 pkg-config 名,CentOS 7 装的是 libnl3,检测逻辑对不上,有的环境会直接报库找不到。VRRP 的 VIP 漂移功能不依赖 libnl,关掉它不影响核心能力,只有你要用某些基于 netlink 的高级特性时才需要处理这个依赖。configure 跑完会打印一张汇总表,逐行看:Use OpenSSL应该是 yes,Use Popt应该是 yes,Use Libnl是 no 属于预期。

3.2 make 与 make install:产物落在哪、PATH 怎么补

configure 通过之后就是常规两步:

# 编译并安装,-j 按 CPU 核数并行加快速度 make -j$(nproc) make install

装完去/usr/local/keepalived下看一眼产物,通常有这几个关键位置:sbin/keepalived是主程序,bin/genhash用来生成 VRRP 认证密码的哈希,etc/keepalived/下可能有示例配置,etc/sysconfig/keepalived是启动参数文件。主程序不在系统 PATH 里,直接敲keepalived会提示 command not found,两种补法:一是在/etc/profile.d/下加一个脚本把/usr/local/keepalived/sbin加进 PATH;二是做个软链ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived。我倾向软链,因为 systemd 单元和 init 脚本里写绝对路径更稳,不依赖登录 shell 的环境变量。

还有个细节:make install不会自动创建/etc/keepalived目录。首次安装时手动建一下,不然后面启动会因为配置文件路径不存在直接退出:

mkdir -p /etc/keepalived chmod 700 /etc/keepalived

权限给 700 是有意的,配置文件里可能有 VRRP 认证密码,普通用户不该读。

3.3 服务托管:1.2.13 没有 --with-init,systemd 单元得自己写

新版 keepalived 的 configure 带了--with-init=systemd这类开关,1.2.13 没有,所以服务脚本要自己落地。源码包里其实带了 SysV 风格的脚本,可以拷过来用:

# 复用源码包自带的启动脚本和参数文件 cp /usr/local/src/keepalived-1.2.13/keepalived/etc/init.d/keepalived /etc/init.d/keepalived cp /usr/local/src/keepalived-1.2.13/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived chmod +x /etc/init.d/keepalived

如果系统是 CentOS 7 且习惯用 systemctl 管,直接写一个 unit 文件更清爽:

# /etc/systemd/system/keepalived.service [Unit] Description=KEEPALIVED for VRRP After=network.target [Service] Type=forking # -D 表示把日志写到 syslog,-f 指定配置文件路径 ExecStart=/usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf ExecReload=/bin/kill -HUP $MAINPID PIDFile=/var/run/keepalived.pid KillMode=process [Install] WantedBy=multi-user.target

Type=forking是因为 keepalived 启动后会自己 daemon 化;-D参数让日志进 syslog,排查时journalctl -u keepalived和/var/log/messages都能看到状态切换记录;PIDFile的路径 1.2.13 用的就是/var/run/keepalived.pid,写错会导致systemctl stop停不干净。写完执行systemctl daemon-reload && systemctl enable keepalived,先别 start,配置还没写,起了也会因为找不到配置文件退出。

4. 配置双机热备:keepalived.conf 里真正决定漂移的参数

配置文件是这套东西的大脑,1.2.13 的配置语法和老版本一脉相承,但有几个参数的行为和新版不同,照着新文档抄会踩坑。下面按「一份能跑的最小配置」拆开讲。

4.1 global_defs 与 vrrp_instance:最小可用配置长什么样

两台机器的配置只有state、priority、router_id和单播地址不同,其余保持一致。先看节点 A:

# 全局段:router_id 用来标识本机,建议写主机名或业务名 global_defs { router_id LVS_NODE_A } # 健康检查脚本定义,后面在 vrrp_instance 里引用 vrrp_script chk_app { script "/etc/keepalived/check_app.sh" interval 2 weight -20 fall 3 rise 2 } vrrp_instance VI_1 { state MASTER # 初始角色,最终由 priority 决定 interface eth0 # 必须和实际网卡名一致 virtual_router_id 51 # 同网段内必须唯一 priority 100 # 数值大的为主 advert_int 1 # 通告间隔,单位秒 authentication { auth_type PASS auth_pass Kp2015 # 最长 8 位,超出会被截断 } track_script { chk_app } virtual_ipaddress { 192.168.10.100/24 dev eth0 } }

节点 B 把router_id改成LVS_NODE_B、state改成BACKUP、priority降到 90,其余不动。几个参数值得单独说:state只是启动时的初始状态,真正决定谁是主的是priority和抢占逻辑,所以两台都写BACKUP也能选出主来,这种写法在防止双主时反而更稳;virtual_router_id在同一個二层网络里必须唯一,两个不相干的集群用同一个 ID 会互相收到对方通告,日志里能看到莫名的状态切换;auth_pass在 1.2.13 里最长 8 个字符,多写的部分会被静默截断,两端都截断成一样还能通,但一旦一端写 8 位一端写 10 位,认证失败会导致一直处于 BACKUP。

interface这一项特别容易错。CentOS 7 默认启用一致性网络命名,网卡可能叫ens33、ens192,你在配置里还写eth0,keepalived 启动时不会报致命错误,但 VIP 加不上去,日志里是一行不起眼的Cannot find interface eth0。装之前先ip addr看清楚网卡名。

4.2 vrrp_script 健康检查:interval、fall、rise 和 weight 的正负号

健康检查是 VIP 漂移的触发器,脚本返回非 0 就判定节点异常。脚本本身很简单,关键是写全路径、给执行权限:

#!/bin/bash # /etc/keepalived/check_app.sh # 检查本机业务端口是否存活,返回 0 表示正常 /usr/bin/curl -s -o /dev/null -m 2 http://127.0.0.1:8080/health exit $?
chmod 755 /etc/keepalived/check_app.sh

参数的含义要掰开:interval 2是每 2 秒执行一次;fall 3表示连续失败 3 次才判定节点故障,也就是最快 6 秒触发切换;rise 2表示连续成功 2 次才恢复;weight -20表示脚本失败时优先级减 20。这里有个反直觉的点:权重为负值时,减完的优先级如果低于对端,就触发切换;如果两台优先级差距大于权重绝对值,减完还是比对方高,VIP 就不会漂。比如主 100、备 90,权重 -20,主挂掉脚本后变成 80,低于 90,正常切换;如果权重只写 -5,减完是 95,仍然高于备机,VIP 就赖着不走。所以权重绝对值要大于两机优先级差值,这是最常见的配置失误。

还有一点,1.2.13 没有新版那套script_user和enable_script_security机制,脚本默认以启动 keepalived 的用户(通常是 root)执行,不需要额外配用户。好处是省事,坏处是脚本里如果用到了非 root 才能访问的资源,排查时容易想不到这一层。

4.3 组播还是单播:unicast_peer 的写法与适用场景

默认情况下 VRRP 走组播,目的地址 224.0.0.18,协议号 112。很多内网环境的安全策略会拦组播,或者两台机器跨了网段、中间有设备不做组播转发,这时候就得改成单播。1.2.13 支持单播,写法是在vrrp_instance里加两块:

vrrp_instance VI_1 { # 其余配置省略 unicast_src_ip 192.168.10.11 # 本机用于发送通告的地址 unicast_peer { 192.168.10.12 # 对端地址,可写多个 } }

单播的好处是流量可控、能过大多数安全策略,缺点是配置里写死了 IP,机器换网段要同步改。用单播时注意unicast_src_ip必须是本机真实存在的地址,写错了 keepalived 起不来或者通告发不出去;两台机器要互相把对方写进unicast_peer,只写一边等于单相思,对端收不到通告,状态永远起不来。另外 1.2.13 的单播不支持指定端口,源码里 VRRP 端口是写死的,别想着改端口绕过安全策略。

5. 避坑与排查:VIP 不漂移、双主、脚本不生效的五条血泪记录

这一章是我这些年攒下来的排错笔记,每条都按「看到什么现象、根子在哪、怎么修」写,遇到问题直接对号入座。

5.1 现象:两台都显示 BACKUP,VIP 谁都不加

原因通常是 VRRP 通告根本没通。先在主备两台同时抓包确认:

# 抓 VRRP 协议(IP 协议号 112),看有没有收到对端通告 tcpdump -i eth0 -nn proto 112 -c 10

如果本机只看到自己发出的包、看不到对方的,基本就是链路或策略拦了。CentOS 7 的 firewalld 默认不放行 VRRP,组播地址 224.0.0.18 也常被安全组忽略。解决方式是放行协议:

# firewalld 放行 VRRP 协议 firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept' firewall-cmd --reload

如果中间有安全设备或者跨网段,直接切单播更省事,按 4.3 的写法加unicast_peer即可。

5.2 现象:两台机器同时持有 VIP,业务时通时断

这是双主,最危险的一种。常见根因有三个:一是virtual_router_id和同网段另一套集群撞了,双方互相收通告,状态来回跳;二是两台机器之间网络时断时续,各自以为对方挂了,同时抢主;三是用了state MASTER且没配nopreempt,加上防火墙只放行单向流量。排查时先tcpdump看有没有收到非预期来源的 VRRP 包,确认 ID 冲突就换一个;网络抖动导致的,把advert_int适当调大、配合fall参数增加容错;实在不行两台都写state BACKUP加nopreempt,让先起来的那台一直占着主位,减少来回切。

5.3 现象:脚本明明返回失败,VIP 还是不切

先看脚本是不是真的被执行了。在脚本里加一行写文件的操作,观察有没有输出;再看 keepalived 日志里有没有VRRP_Script(chk_app) failed这类记录。常见的坑:脚本没有执行权限,keepalived 静默跳过;脚本里用了相对路径或者没写全/usr/bin/curl,在非交互环境 PATH 不全导致命令找不到,返回值恰好是 0;weight设成正值,1.2.13 里正权重只在 BACKUP 状态生效,主节点上脚本失败反而加了优先级,逻辑正好反了。解决办法就是把脚本写成绝对路径、chmod 755、权重用负值并且绝对值大于优先级差。

5.4 现象:编译到一半报 OpenSSL 结构体错误

前面提过,这是 OpenSSL 1.1 及以上版本和 1.2.13 老代码的代差,报错关键词是EVP_MD_CTX、dereferencing pointer to incomplete type。别去改源码打补丁,除非你有长期维护的打算。最省事的做法是换一台 CentOS 7 编译,或者用系统自带的 openssl 1.0.2 环境重新构建。如果生产环境必须是新系统,就在 CentOS 7 上编好之后连同依赖库一起打包,目标机用ldd /usr/local/keepalived/sbin/keepalived检查动态库是否齐全。

5.5 现象:改完配置 reload 不生效,甚至进程直接退出

systemctl reload keepalived发的是 HUP 信号,1.2.13 对配置文件的语法检查不算严格,有些错误 reload 时才暴露,进程直接挂掉,VIP 随之丢失。所以改配置前先做语法自检:用keepalived -t -f /etc/keepalived/keepalived.conf做测试模式,输出Configuration file ... validation successful再 reload。另外改virtual_router_id、interface这类底层参数,reload 不一定能完全生效,稳妥做法是systemctl restart,但重启会短暂丢 VIP,安排在维护窗口做。

6. 验证跑通:从抓包到手动切一次主的验收清单

装完不验证等于没装。我的验收顺序是固定的一套:先看进程和日志,再看 VIP,再抓包,最后手动切一次主,四步都过才算交付。

第一步,确认进程和配置加载正常:

systemctl status keepalived # 日志里应该能看到 Entering MASTER STATE 或 BACKUP STATE journalctl -u keepalived -n 50 --no-pager

主节点日志里出现Entering MASTER STATE,备节点出现Entering BACKUP STATE,说明 VRRP 协商通了。如果两边都是 BACKUP,回第 5 章第一条排查。

第二步,确认 VIP 落在正确的位置:

ip addr show eth0 | grep 192.168.10.100

只在主节点上有输出,备节点上查不到,这是正确状态。

第三步,抓包确认通告是双向的。在主备两台各执行十秒,看能不能同时看到来源为对方 IP 的 VRRP 包:

timeout 10 tcpdump -i eth0 -nn proto 112

第四步,手动制造一次故障,验证漂移和回切。最直接的方式是在主节点停服务:

systemctl stop keepalived # 到备节点上确认 VIP 是否漂过来 ip addr show eth0 | grep 192.168.10.100

VIP 应该在几秒内出现在备节点上,业务侧用curl访问 VIP 能通。然后再把主节点起回来,观察是否按预期回切。如果配了nopreempt,主节点恢复后不会抢回 VIP,这是正常的,别当成故障。验证健康检查脚本时,我一般直接改脚本让它返回 1,观察fall次数到达后是否触发切换,比停服务更贴近真实故障场景。

验收项通过标准不通过先看哪
进程状态主备均 active (running)journalctl 日志
角色状态一主一备,无来回跳VRRP 通告是否互通
VIP 位置仅主节点持有interface 网卡名
故障切换停主后 VIP 数秒内漂移weight 与优先级差
业务连通访问 VIP 返回正常本机服务与回环地址

从那以后我每次交付这类环境,都会在最后强制走一遍「停主、看漂、起主、看回切」,不靠日志里那句 MASTER 就下结论。这套 keepalived-1.2.13 的源码包我一直留在内部制品库里,版本固定、校验值固定,省得每次换机器又去满世界找同版本的 tar.gz,需要复现这套环境的话,直接拿这份包按上面的顺序走一遍就行。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:14:48

【傻呱呱】云服务器开启ssh的root权限登录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:13:02

STM32C5嵌入式开发实战:从固件到上位机的完整软件链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:12:56

ESP8266 DIY智能WIFI时钟:NTP自动校时+天气显示,成本仅23元

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:12:21

宽禁带半导体从顶流到主流:SiC与GaN的产业化之路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:11:26

营销技能修炼:从用户洞察到数据驱动的完整闭环

1. 营销技能到底包含什么——先别急着学工具每次有人问我“怎么提升营销技能”,我第一反应都是反问一句:你说的营销技能,是指写文案、投广告、做活动,还是指那种能把东西卖出去的能力?这两者差别非常大。前者是“术”&…

作者头像 李华
网站建设 2026/10/28 1:10:09

个人Agent硬件化实战:ESP32-S3与Linux设备SDK集成指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华