简介:Keepalived 1.2.13 源码压缩包面向具备 Linux 基础的运维工程师、网络架构学习者以及需要构建高可用服务的技术人员,尤其适合初中级读者,围绕 VRRP 虚拟路由冗余与 LVS 负载均衡场景,提供源码研读与配置实践的基础素材。压缩包共 188 个文件,以 62 个 .h 头文件和 61 个 .c 源文件为主体,并包含配置样例、安装与初始化脚本、手册页等辅助内容,整体约 334KB,体量轻便却覆盖核心实现与常用配置入口。已有 369 人学习下载,可见其在 Keepalived 版本研究和实验环境中具有一定参考价值。读者可借助源码理解主备切换、虚拟 IP 接管、健康检查及 track_script 等机制,结合随包示例梳理 global_defs、vrrp_instance、virtual_server_group 等配置结构,并把握优先级、通告间隔、故障检测与 LVS 转发之间的关系,为 Nginx、MySQL 等高可用部署、运行维护和故障排查积累可复用的分析路径。
1. 一台老 CentOS 7 上的 keepalived-1.2.13.tar.gz,折腾掉我半天
给一套双机网关做虚拟 IP 漂移,翻遍内网源只翻到 keepalived-1.2.13.tar.gz 这一个包,yum 里能装到的新版本语法又不兼容。这套 keepalived 场景其实很常见:两台机器共用一个 VIP,主挂了备顶上,中间靠 VRRP 组播互相确认存活。装得不好,后果很直接——要么 VIP 在主备两台机器上同时挂着、流量分成两半,要么切换时业务断几十秒,日志里全是VRRP_Instance的告警。下面这条路径,是我在 CentOS 7.6 和 Ubuntu 16.04 上各跑通一次后记下来的编译安装流程,从依赖包怎么挑、configure 参数怎么取舍,到配置文件怎么写、装完怎么验证真能漂移,新手照着敲能落地,熟手可以直接看版本对照和踩坑那几段。
2. 装前把依赖对齐:keepalived 1.2.13 认哪几套组合
keepalived 1.2.13 在 2012 年发布,源码是纯 C + autotools,没有预编译包可用,必须自己编译。它不像现在的新版本那样一个apt install就完事,configure 阶段要主动检查几个开发库和内核头文件,缺一样就直接退出。所以装之前的第一件事不是解压,而是把编译环境和版本组合确定下来,否则后面 make 报错时,你得从头判断是库的问题还是代码的问题。
2.1 三个必须装对的开发包
keepalived 1.2.13 的 configure 会硬性检查 OpenSSL 和 popt,libnl 则是能装就装。我在两台机器上试过的组合是:
# CentOS 7 系 yum install -y gcc gcc-c++ make \ openssl-devel \ popt-devel \ libnl-devel \ kernel-devel-$(uname -r) \ zlib-devel # Ubuntu / Debian 系 apt-get install -y build-essential \ libssl-dev \ libpopt-dev \ libnl-3-dev libnl-genl-3-dev \ linux-headers-$(uname -r) \ zlib1g-devopenssl-devel是给 VRRP 认证用的,1.2.13 里主备之间的auth_pass走 HMAC/MD5 校验,没有这个库 configure 会直接报OpenSSL is not properly installed。popt-devel容易被漏掉——它是 keepalived 自己解析命令行参数用的,缺了会报Popt library not found,而且这个报错信息不提示你去装哪个包,很多人第一次见会以为是配置问题。libnl-devel负责通过 netlink 拿网卡和地址信息,缺了 configure 通常会退回老的 ioctl 实现,多数单网卡机器能编过,但在网卡多、别名 IP 多的机器上会出现取不到接口状态的玄学现象,能装就顺手装上。kernel-devel只有在你打算同时用 LVS 时才必须,后面一节细说。
提示:
kernel-devel-$(uname -r)里的版本号必须和uname -r完全一致。直接yum install kernel-devel会装上仓库里最新的内核头文件,和当前运行内核不匹配,configure 检查时一样找不到目标头文件。
2.2 内核头文件与 --with-kernel-dir 的取舍
keepalived 1.2.13 的 configure 脚本在没有加--disable-lvs的情况下,会去内核目录里找include/net/ip_vs.h,找不到就报错退出。CentOS 上这个文件在/usr/src/kernels/$(uname -r)/include/net/ip_vs.h,而 configure 默认找的路径是/usr/src/linux——这个目录在 CentOS 发行版上根本不存在,所以必须显式指定:
# 先确认头文件真的在 ls -l /usr/src/kernels/$(uname -r)/include/net/ip_vs.h如果这条命令能列出文件,就可以在 configure 时加--with-kernel-dir=/usr/src/kernels/$(uname -r)。如果装完 kernel-devel 后/usr/src/kernels/下是空的或者版本对不上,说明装的是别的内核的头文件,用rpm -qa | grep kernel-devel看一眼版本再决定是重装还是补装。
如果你这台机器只做 VRRP 漂移,不打算跑 LVS 负载均衡,我的建议是干脆把 IPVS 相关的东西全关掉:--disable-lvs --disable-lvs-syncd。这两个开关能让编译过程彻底不碰内核头文件,省掉 kernel-devel 这一整条依赖链,编译时间也短一截。代价是编出来的二进制没有virtual_server能力,后面配置里也就不能写 LVS 段。对绝大多数只做 VIP 漂移的场景来说,这个取舍是划算的。
2.3 版本组合对照表:哪些系统上能一次编译通过
1.2.13 的代码里有不少依赖 OpenSSL 1.0.x 内部结构的写法,在 1.1 及以上版本上编译会冒出一堆告警,个别发行版上会直接报错。我把实际试过的组合列出来,方便你对号入座:
| 发行版与版本 | OpenSSL | 编译结果 | 建议 |
|---|---|---|---|
| CentOS 6.9 | 1.0.1e | 一次通过 | 最省心,老版本首选 |
| CentOS 7.6 | 1.0.2k | 一次通过,个别告警 | 生产推荐组合 |
| Ubuntu 16.04 | 1.0.2g | 一次通过 | 需要手动装 libpopt-dev |
| Ubuntu 18.04 | 1.1.1 | 告警多,可编过 | 编完跑一遍前台启动确认 |
| Ubuntu 20.04 及以上 | 1.1.1 / 3.0 | 大概率报错 | 建议在容器里用老系统编好再拷二进制 |
最后一行那个做法值得展开:找一个 CentOS 7 的容器或虚拟机,把 1.2.13 编出静态一点的二进制,再拷到目标机上。keepalived 的可执行文件对 glibc 版本的依赖不算强,跨同架构的老系统之间搬运基本没问题,比在 OpenSSL 3.0 上硬改源码省事得多。搬过去之后记得ldd看一眼动态库依赖,把缺的库补齐。
3. 解压、configure 到 make install:一条条命令落地
依赖齐了之后就是标准的三步走,但 keepalived 1.2.13 的每一步都有几个容易写错的点,尤其是 prefix 和后缀参数。下面的命令我按顺序贴,你可以直接抄,但建议每执行一步都看一眼输出末尾有没有error。
3.1 源码放置与解压
mkdir -p /opt/src && cd /opt/src tar -zxvf keepalived-1.2.13.tar.gz cd keepalived-1.2.13 # 顺手记录一下包本身的校验值,方便多台机器比对是不是同一个包 sha256sum /opt/src/keepalived-1.2.13.tar.gz解压后的目录结构里,configure、Makefile.in、keepalived/、lib/是主要部分。养成先ls一眼的习惯,有些二次打包的压缩包里会多套一层目录,直接cd keepalived-1.2.13会找不到 configure。sha256sum这一步在批量部署时很有用——主备两台机器编出来的二进制如果行为不一致,先排除包本身不是同一个的概率。
3.2 configure 参数逐个解释
纯 VRRP 场景用这一套:
cd /opt/src/keepalived-1.2.13 ./configure \ --prefix=/usr/local/keepalived \ --disable-lvs \ --disable-lvs-syncd \ 2>&1 | tee /tmp/keepalived-configure.log要带 LVS 的话换成这一套:
./configure \ --prefix=/usr/local/keepalived \ --with-kernel-dir=/usr/src/kernels/$(uname -r) \ --disable-lvs-syncd \ 2>&1 | tee /tmp/keepalived-configure.log--prefix=/usr/local/keepalived决定了安装目录,1.2.13 的默认值是/usr/local,直接用它会把二进制塞进/usr/local/sbin,和系统里别的东西混在一起,后面做软链和写 systemd 单元时容易搞混,所以我一般显式指定一个独立目录。--disable-lvs关掉整个 LVS 支持,--disable-lvs-syncd只关掉同步守护部分,前者更彻底。--with-kernel-dir前面说过,只在需要 IPVS 时用。
把输出 tee 到日志文件是个小习惯,configure 报错往往夹在几十行检查信息中间,滚屏之后想回看就没了。真出错的时候直接grep -i error /tmp/keepalived-configure.log,再配合源码目录下自动生成的config.log,基本能定位到是哪个库没找到。
还有一个常被忽略的参数是--log-facility,1.2.13 默认把日志打到 syslog 的 daemon 设施,在 CentOS 上就是/var/log/messages。如果你们的日志采集只认 local0 到 local7,configure 时加--log-facility=local5,后面在 rsyslog 里单独配一条规则,排查时不用在几千行 messages 里翻。
3.3 make 与 make install,以及文件落位
make -j$(nproc) 2>&1 | tee /tmp/keepalived-make.log # 编译完先确认二进制生成了再装 ls -l keepalived/keepalived make installmake -j$(nproc)用满 CPU 核数并行编译,1.2.13 代码量不大,单核也就一两分钟,但并行能省点时间。编译失败的日志同样 grep 关键词,OpenSSL 相关的报错通常是undefined reference to加一串函数名,看到这种就回到 2.3 的版本对照表去核对 OpenSSL 版本。
装完之后,/usr/local/keepalived下应该是这样的结构:
/usr/local/keepalived/ ├── sbin/keepalived # 主程序 ├── bin/genhash # 生成 auth_pass 的小工具 ├── etc/keepalived/keepalived.conf # 示例配置 ├── etc/sysconfig/keepalived # 启动参数 └── etc/rc.d/init.d/keepalived # init 脚本注意这里的配置文件是示例,不是给你直接用的。真正要生效的配置在/etc/keepalived/keepalived.conf,这个目录 make install 不会创建,得手动mkdir -p /etc/keepalived。bin/genhash是个挺实用的小工具,早年间有人用它生成密码散列,不过 1.2.13 的auth_pass实际只取明文前 8 位,用它属于多此一举,知道有这个东西就行。
4. 配置 keepalived.conf:VRRP 实例与 VIP 漂移的骨架
1.2.13 的配置语法比 2.x 少一些关键字,从网上抄新版本配置是最常见的翻车方式。这一节给一份能在 1.2.13 上跑起来的最小骨架,再逐段说明每个参数为什么这么写。
4.1 全局块和 vrrp_instance 的最小骨架
主节点/etc/keepalived/keepalived.conf的内容如下,备节点只改state、priority、router_id三处:
global_defs { router_id node_a # 本机标识,主备必须不同 notification_email { ops@example.com # 告警收件地址,不用可以留空 } smtp_server 127.0.0.1 smtp_connect_timeout 30 } vrrp_script chk_gateway { script "/etc/keepalived/chk_gateway.sh" interval 2 # 每 2 秒执行一次 weight -20 # 脚本失败时优先级减 20 fall 2 # 连续失败 2 次才算故障 rise 2 # 连续成功 2 次才算恢复 } vrrp_instance VI_1 { state BACKUP # 两端都写 BACKUP,靠优先级选举 interface eth0 virtual_router_id 51 # 同一组主备必须相同 priority 100 # 备节点写 90 advert_int 1 # 组播通告间隔,单位秒 authentication { auth_type PASS auth_pass Kx7p2mQa # 只取前 8 位,主备必须一致 } virtual_ipaddress { 192.0.2.10/24 dev eth0 } track_script { chk_gateway } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault" }global_defs里router_id是同组机器的唯一标识,主备写成一样会导致日志分不清谁是谁。state这一项我建议两端都写 BACKUP,让优先级来决定谁是主——如果一端写 MASTER 一端写 BACKUP,主节点重启后可能出现短暂的抢占混乱;两端都是 BACKUP 时,优先级高的先抢到,行为更可预期。virtual_router_id是这一组 VRRP 的编号,同一个二层网络里不能和别的组冲突,冲突的表现是两台机器疯狂抢占 VIP。auth_pass在 1.2.13 里只比较前 8 个字符,写长了不报错但只有前 8 位生效,主备两边长度不一致的时候特别容易出错。
virtual_ipaddress里的 VIP 用 192.0.2.x 这种文档保留地址只是示例,实际换成你们规划的空闲 IP,掩码和出口网卡都要写清楚,dev eth0漏掉的话 keepalived 可能把地址加到回环口上。
4.2 健康检查脚本与 notify 脚本落地
vrrp_script指向的脚本必须存在且可执行,否则 keepalived 启动时不会报错,只会在日志里刷Unable to open script,然后一直认为检查失败。脚本本身要写得短、跑得快、返回码明确:
#!/bin/bash # /etc/keepalived/chk_gateway.sh # 返回 0 表示健康,非 0 表示异常,由 keepalived 根据 weight 调整优先级 GW=192.0.2.1 COUNT=2 if ping -c $COUNT -W 1 $GW > /dev/null 2>&1; then exit 0 fi exit 1这个脚本用 ping 探测上游网关,-c 2发两个包,-W 1每个包最多等 1 秒,最坏情况阻塞 2 秒,比interval 2略短,不会造成检查任务堆积。真实场景里把 ping 换成你们自己的探测逻辑,比如curl -s -o /dev/null -w '%{http_code}'判断后端端口,或者读一个本地状态文件。关键是脚本的耗时必须明显小于interval,否则 keepalived 会一直排队。
notify 脚本负责在状态切换时做额外动作,比如发告警、刷 ARP、重启依赖 VIP 的服务:
#!/bin/bash # /etc/keepalived/notify.sh # 参数由 keepalived 传入:master / backup / fault STATE=$1 LOG=/var/log/keepalived-notify.log case "$STATE" in master) # 成为主节点后,主动发一次免费 ARP,让交换机刷新 MAC 表 arping -I eth0 -c 3 -U 192.0.2.10 >> $LOG 2>&1 echo "$(date '+%F %T') become MASTER" >> $LOG ;; backup) echo "$(date '+%F %T') become BACKUP" >> $LOG ;; fault) echo "$(date '+%F %T') enter FAULT" >> $LOG ;; esac这里最值得写的是arping -U那一行。VIP 从备机挪到主机之后,交换机上的 MAC 地址表还指着旧机器,流量会继续往备机飘,现象是 VIP 已经在新机器上了但业务仍然不通,等 ARP 缓存老化(通常几分钟)才恢复。主动发免费 ARP 能把这个窗口压到秒级。两个脚本都要chmod 755,属主 root。
4.3 init.d 与 systemd 两种托管方式
make install 生成的 init 脚本里路径是按/usr/sbin/keepalived写死的,而我们的二进制在/usr/local/keepalived/sbin/下。最省事的做法是做软链,再按老规矩把文件放到位:
mkdir -p /etc/keepalived cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/ ln -sf /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived chmod +x /etc/init.d/keepalived chkconfig --add keepalived chkconfig keepalived on如果你用的是 systemd 系统,直接写一份单元文件更干净,路径全部显式指定,不依赖软链:
# /etc/systemd/system/keepalived.service [Unit] Description=Keepalived VRRP After=network.target [Service] Type=forking PIDFile=/var/run/keepalived.pid ExecStart=/usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure [Install] WantedBy=multi-user.targetExecStart里的-D是详细日志开关,排查阶段很有用,稳定之后可以去掉少刷点日志。KillMode=process是为了让 keepalived 自己管理那几个子进程,否则 systemd 停服务时可能只杀掉父进程,留下孤儿子进程继续持有 VIP。
5. 踩坑排查:1.2.13 编译和启动时的 5 个常见翻车点
下面这几条是我在不同机器上实际撞过的,按「现象 → 原因 → 解决」记,遇到问题先按现象对号入座。
5.1 configure 报 Popt library not found
现象:./configure跑到一半直接退出,最后一行是configure: error: Popt library not found.,前面没有任何关于 popt 的提示。
原因:系统装了 popt 运行时库但没装开发头文件,或者装了popt-devel但版本太老,configure 的探测程序链接不上。另外有一种少见情况是只装了libpopt0这类运行时包,popt.h根本不存在。
解决:CentOS 上yum install -y popt-devel,Debian 系apt-get install -y libpopt-dev。装完确认/usr/include/popt.h存在,然后删掉源码目录重新解压再 configure——1.2.13 的 configure 缓存会记住上次的探测结果,直接重跑有时还是报同样的错。
5.2 make 阶段报 OpenSSL 相关的未定义引用
现象:make到链接阶段报一串undefined reference to 'EVP_...'或者error: dereferencing pointer to incomplete type,指向keepalived/vrrp/vrrp_...下的源文件。
原因:系统上的 OpenSSL 是 1.1 或 3.0,1.2.13 的代码按 1.0.x 的结构体写法来访问内部字段,新版本把这些结构改成了不透明类型,编译期就炸。这不是你配置错了,是版本跨代的问题。
解决:优先换一台 OpenSSL 1.0.x 的机器或容器编译,编好把二进制拷过去,ldd确认依赖的libssl.so.10目标机上也有。如果必须在本机编,只能改源码里报错的那几处字段访问,工作量不小,且改完后续行为没法保证,不推荐在生产环境这么干。
5.3 启动后两台机器都有 VIP,业务流量分叉
现象:ip addr show eth0在主备两台机器上都能看到 192.0.2.10,抓包能看到两边都在发 VRRP 通告,日志里反复出现Transition to MASTER STATE。
原因:排在第一的是防火墙拦了 VRRP 协议。VRRP 走 IP 协议号 112,不是 TCP 也不是 UDP,默认策略里经常被 DROP 掉,两边互相收不到对方通告,都以为自己是唯一的主。第二可能是virtual_router_id和同网段别的组撞了,或者auth_pass主备不一致导致认证失败。
解决:先放行协议号。CentOS 7 用firewall-cmd --permanent --add-protocol=vrrp && firewall-cmd --reload,iptables 用iptables -I INPUT -p vrrp -j ACCEPT。然后用tcpdump -i eth0 -nn 'ip proto 112'在两台机器上同时抓,正常情况下应该看到双向的组播包。如果只有单向,就是网络侧的组播被禁了,常见于跨网段或虚拟化环境,这种情况要么让网络侧放开组播,要么换成单播方式通信,1.2.13 支持在vrrp_instance里写unicast_peer指定对端地址。
5.4 启动报 Unknown keyword,配置改了不生效
现象:/var/log/messages里出现Unknown keyword 'vrrp_iptables'之类,keepalived 启动后在跑但配置里的某些段完全没生效。
原因:配置是从 2.x 的文档里抄的。vrrp_iptables、vrrp_strict、nopreempt的某些位置、track_interface的写法在不同版本上差异不小,1.2.13 遇到不认识的词是忽略加告警,不像新版本那样直接退出,所以很容易误以为配置生效了。
解决:拿 1.2.13 源码目录里的keepalived/etc/keepalived/keepalived.conf示例当基准,所有关键字在示例里找不到就不要写。排查时把服务停掉手工前台跑一次,第一屏的告警会直接打出来,比翻日志快。
5.5 用 init 脚本起不来,但手工敲命令能跑
现象:service keepalived start提示已启动,ps里却找不到进程;手工执行/usr/local/keepalived/sbin/keepalived -D又一切正常。
原因:init 脚本里的路径、pid 文件位置、配置目录三者有一个不对。最常见的是脚本按/usr/sbin/keepalived找二进制但软链没做,或者/etc/keepalived目录压根没建,程序读不到配置就退出了。
解决:先看/var/log/messages里脚本执行那一刻的输出,再确认三件事——ls -l /usr/sbin/keepalived软链是否存在、ls /etc/keepalived/keepalived.conf是否存在、ps -ef | grep keepalived是否真有残留进程占着 pid 文件。三件事都对还起不来,就改用 systemd 单元文件,路径写死的托管方式比 init 脚本透明得多。
6. 装完怎么验证:从三个进程到一次真漂移
编译装完、配置写好,很多人到这一步就发一条「服务启动成功」收工了,结果第一次真切换才发现不通。验证要分两层做:先确认静态状态对,再人为制造一次切换,看它是不是真能漂。
6.1 静态自检:版本、配置、进程数
# 1. 版本和编进去的选项 /usr/local/keepalived/sbin/keepalived --version # 2. 停掉服务,前台跑一次看配置解析有没有告警 systemctl stop keepalived /usr/local/keepalived/sbin/keepalived -D -f /etc/keepalived/keepalived.conf -l # 3. 另开一个终端确认进程形态 ps -ef | grep [k]eepalived第一步的输出里会列出 configure 时启用的特性,能看到是否带 LVS,方便确认你编的是不是想要的那份。第二步是关键——1.2.13 没有-t这种纯语法检查参数(新版本才有),最接近的做法是用-D前台运行一遍,配置解析的告警会直接打在屏幕上,看到Unknown keyword或者Configuration file error就别急着往下走。第三步正常应该看到至少两个进程:一个父进程,一个 VRRP 子进程;配置了virtual_server的话还会多一个 healthcheck 子进程。
然后看 VIP 和日志:
ip addr show eth0 | grep 192.0.2.10 tail -f /var/log/messages | grep -i keepalived主节点上应该能看到 VIP,备节点上没有。日志里应当出现VRRP_Instance(VI_1) Entering BACKUP STATE接着Entering MASTER STATE的序列,备节点则一直停在 BACKUP。如果主节点状态在 MASTER 和 BACKUP 之间来回跳,回到 5.3 检查组播和认证。
6.2 动态验证:制造一次真漂移
静态检查都过了,最后一步是拔电源式的真切换。我一般用最温和的方式:在主节点上停服务,观察备节点接管,再启动主节点,观察它是否按优先级夺回(或者因为nopreempt不夺回)。
| 验证项 | 操作 | 期望结果 |
|---|---|---|
| VIP 落地 | ip addr show eth0 | 只在主节点上出现 |
| 备节点静默 | 看备节点日志 | 持续 BACKUP,无 VIP |
| 切换速度 | 主节点systemctl stop keepalived | 备节点 1 至 3 秒内转 MASTER |
| 流量连通 | 切换过程中持续ping VIP | 丢包不超过 3 个 |
| 回切行为 | 主节点启动服务 | 按优先级夺回,或保持备机(看配置) |
切换时开一个窗口持续ping 192.0.2.10 -i 0.2,另一个窗口抓tcpdump -i eth0 -nn 'ip proto 112',能看到主节点停掉后组播通告消失,备节点在advert_int * 3个周期内判定对方失效并抢占。如果 VIP 已经挪过去了但 ping 还是断,多半是 4.2 里那个免费 ARP 没发,或者上游交换机的 ARP 表没刷新。
这套流程我在后来的每一次部署里都强制走一遍,包括备节点重启后再切回来的那一遍——血泪经验是,单向切换通了不代表双向都对,回切时优先级和nopreempt的组合最容易被配错,而这一遍恰恰是很多人省掉的。keepalived 1.2.13 这种老版本不会给你太多提示,配置写错它也只是安静地跑着,所以验证这一步没有后悔药可吃,只能老老实实切一次看。希望这套流程能帮到你,少在编译和漂移上耗时间。
本文还有配套的精品资源,点击获取