1. 项目概述为什么今天还在认真折腾KeepalivedKeepalived不是新东西但恰恰因为它足够“老”反而在生产环境里越来越难被替代。我最近给某高校实验室的三套教学集群做高可用改造分别部署在CentOS 7.9、Rocky Linux 8.10和Red Hat Enterprise Linux 9.3上——三套系统内核版本差了近四年systemd行为不一致防火墙策略默认开关不同SELinux策略层级也变了两轮。结果呢一套Keepalived配置文件在CentOS上跑得稳如泰山在Rocky上VIP飘忽不定在RHEL9上甚至根本起不来VIP。最后发现问题既不在keepalived.conf写错了也不在网卡没配好而是在RHEL9默认启用了nf_conntrack_helper0导致VRRP协议包被conntrack模块误判为异常连接直接丢弃Rocky 8.10的firewalld默认规则链里多了一条reject-with icmp-host-prohibited把VRRP组播包当成了非法请求拦截了CentOS 7.9的内核虽然老但ip_vs模块是内置编译进内核的而Rocky 8和RHEL9默认是模块化加载没手动modprobe ip_vsLVS功能压根不生效。这就是“多环境适配”四个字背后的真实重量。Keepalived本身只做三件事健康检查、VRRP协议实现、IPVS规则管理。但它像一个精密的瑞士手表齿轮咬合必须严丝合缝——内核模块要就位、网络栈要放行、用户空间权限要明确、systemd服务依赖要理清、甚至时间同步精度都要影响主备切换判定。很多人装完yum install keepalived就以为万事大吉结果一上生产VIP漂移延迟高达23秒或者主节点宕机后备节点死活不接管查日志全是VRRP_Instance(VI_1) ignoring received advertisment...这种报错翻遍文档都找不到原因。其实问题往往出在操作系统底层的细微差异上而不是Keepalived本身。这篇指南不讲原理图解不堆概念定义只聚焦一件事让你在CentOS/Rocky/RedHat任意一个发行版上5分钟内完成可验证、可复现、可上线的Keepalived安装与基础高可用配置。它适合三类人刚接手运维工作的新人别怕连/etc/keepalived/keepalived.conf里每个字段代表什么、为什么这么写我都给你掰开揉碎正在做国产化替代或信创迁移的工程师Rocky和RHEL9的坑我全踩过哪些参数必须改、哪些服务必须开、哪些SELinux布尔值必须设直接抄作业还有那些被线上VIP漂移问题折磨到失眠的资深运维文末的“实操心得”板块全是我在真实故障现场用tcpdump -i any vrrp抓包、用journalctl -u keepalived -f盯日志、用ipvsadm -Ln查规则时总结出来的速查口诀。核心关键词就是Keepalived安装、CentOS适配、Rocky适配、RedHat适配、多环境一致性部署——这五个词就是你接下来每一步操作的锚点。2. 环境设计与方案选型为什么不用Docker、不用Ansible、不用Helm先说结论本次Keepalived安装实战坚持“裸机原生部署”原则拒绝任何容器化、编排层或配置管理工具的抽象封装。这不是守旧而是基于对高可用本质的敬畏。VRRP协议工作在OSI模型的网络层Layer 3它需要直接与内核网络栈对话监听224.0.0.18组播地址发送原始IP包并在内核中快速响应ARP请求。一旦套上Docker网络命名空间、iptables规则链重定向、或Ansible模板渲染的中间层任何一个环节的微小延迟或规则冲突都会让VRRP心跳包超时触发不必要的主备切换。我见过最离谱的案例某公司用Ansible批量部署Keepalived所有节点配置完全一致但其中一台服务器因为Ansible执行时恰好触发了systemctl daemon-reload导致systemd重新加载了所有unit文件而Keepalived服务的RestartSec10s被临时覆盖主节点重启后10秒内无法响应心跳备节点误判为主节点宕机立刻接管VIP——结果主节点服务刚起来两个节点同时持有同一个VIP整个集群HTTP 502满天飞。所以本方案采用最朴素、最可控的方式纯Shell命令驱动 手动配置文件校验 内核级状态验证。具体拆解如下安装方式全部使用各发行版原生包管理器yum/dnf不编译源码不混用EPEL仓库。理由很实在原生包经过发行版厂商严格测试与内核版本、glibc版本、systemd版本深度绑定。比如RHEL9的keepalived-2.2.7-5.el9其二进制文件是用GCC 11.3编译链接的是glibc 2.34且明确声明支持libnl3网络库——而你自己从源码编译稍不注意就可能链接到系统里残留的libnl1运行时直接段错误。Rocky 8.10的keepalived-2.0.20-6.el8则强制依赖kernel-core 4.18.0-477这是为了确保ip_vs模块的ABI兼容性。这些细节只有原生包的.spec文件里才写得明明白白。配置管理不使用任何模板引擎keepalived.conf文件全程手写。但我会告诉你每一行背后的“为什么”。比如vrrp_script chk_http_port { script /usr/bin/killall -0 nginx }这行为什么用killall -0而不是curl -I http://127.0.0.1:80因为-0只是发送信号检测进程是否存在毫秒级完成而curl要走完整TCP三次握手HTTP头解析网络抖动时可能耗时200ms以上如果健康检查间隔设为1秒连续两次超时就会触发切换太敏感。再比如priority 100这个值为什么主节点设100备节点设90而不是100和99因为VRRP协议规定优先级相等时IP地址大的节点胜出。如果你设成100和99当主节点因网络分区暂时失联备节点升为Master此时主节点恢复后会因为优先级更高而强行抢回Master身份造成VIP反复漂移。设成100和90留出10点缓冲能有效避免“脑裂”风险。服务管理全部使用systemctl原生命令但会深度定制keepalived.service的Unit文件。默认的Unit文件里Afternetwork.target是不够的因为network.target只表示网络服务已启动不代表物理网卡已UP、IP地址已配置完毕。在Rocky 8上你需要显式添加Afternetwork-online.target并启用systemctl enable NetworkManager-wait-online.service否则Keepalived启动时可能发现网卡还没拿到IP直接退出。RHEL9更进一步要求Wantsfirewalld.service并设置BindsTofirewalld.service因为它的nftables后端需要firewalld服务先初始化规则链。这些细节Ansible Playbook里一个when: ansible_distribution Rocky判断根本覆盖不了。验证方式拒绝“service keepalived status显示active (running)就等于成功”的懒人思维。真正的验证必须分三层第一层看进程ps aux | grep keepalived确认master进程和worker进程都在第二层看网络ip addr show eth0 | grep inet 192.168.1.100确认VIP已绑定ss -tuln | grep :80确认Nginx监听在VIP上第三层看协议tcpdump -i eth0 -nn -c 10 ip proto \\0x69抓10个VRRP包确认源IP是本地真实IP目的IP是224.0.0.18TTL255。这三步缺一不可少一步上线后都可能出事。这套方案看起来“笨”但正是这种笨功夫才能把Keepalived这个看似简单的工具真正变成你生产环境里那根最可靠的保险丝。3. 核心细节解析与实操要点从内核模块到SELinux策略的全链路梳理Keepalived的稳定运行是一条从内核空间贯穿到用户空间的完整链路。任何一个环节掉链子VIP就飘。下面我把这条链路拆成六个关键节点每个节点都告诉你“必须做什么”、“为什么必须这么做”、“不这么做会怎样”全是血泪教训换来的经验。3.1 内核模块加载ip_vs、nf_conntrack、nf_defrag_ipv4一个都不能少Keepalived的LVS功能依赖三个内核模块ip_vsIP虚拟服务器核心、nf_conntrack连接跟踪、nf_defrag_ipv4IPv4碎片重组。它们不是可选插件而是硬性依赖。很多教程只提modprobe ip_vs却忽略了后两者结果LVS规则加进去流量就是不转发。ip_vs模块这是LVS的基石。在CentOS 7.9中它被静态编译进内核lsmod | grep ip_vs永远为空但ipvsadm -Ln能正常工作。而在Rocky 8.10和RHEL9中它被改为可加载模块。必须执行modprobe ip_vs echo ip_vs /etc/modules-load.d/ip_vs.conf如果跳过这步ipvsadm -Ln会报错/proc/net/ip_vs: No such file or directory所有LVS配置形同虚设。nf_conntrack模块VRRP协议包会被Linux连接跟踪子系统误判。默认情况下nf_conntrack会尝试为VRRP包IP协议号112创建连接记录但VRRP没有TCP/UDP端口概念conntrack无法正确识别其状态最终导致包被丢弃。解决方案是关闭VRRP的连接跟踪# 临时生效 echo 0 /proc/sys/net/netfilter/nf_conntrack_helper # 永久生效写入sysctl.conf echo net.netfilter.nf_conntrack_helper 0 /etc/sysctl.conf sysctl -p这个参数在RHEL9中默认就是0但在Rocky 8.10中默认是1CentOS 7.9中默认是0。不统一设置多环境部署必出问题。nf_defrag_ipv4模块VRRP包有时会被网络设备分片传输。如果这个模块没加载内核无法重组分片VRRP包就收不全心跳直接中断。执行modprobe nf_defrag_ipv4 echo nf_defrag_ipv4 /etc/modules-load.d/nf_defrag.conf提示验证模块是否加载成功不要只看lsmod | grep xxx要结合cat /proc/sys/net/netfilter/nf_conntrack_helper和ipvsadm -Ln一起看。我曾在一个RHEL9节点上lsmod显示ip_vs已加载但ipvsadm -Ln仍报错最后发现是nf_defrag_ipv4没加载导致ip_vs模块初始化失败。3.2 网络接口与防火墙组播、ICMP、ARP的三重放行VRRP靠组播通信健康检查靠ICMP或TCP探测VIP切换靠ARP通告。这三者任何一个被防火墙拦住Keepalived就瘫痪。VRRP组播224.0.0.18这是VRRP的生命线。firewalld默认规则链public会拒绝所有未知组播。必须显式放行# Rocky 8/RHEL9 使用 nftables 后端 firewall-cmd --permanent --add-rich-rulerule familyipv4 destination address224.0.0.18 accept # CentOS 7.9 使用 iptables 后端 firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -d 224.0.0.18 -j ACCEPT firewall-cmd --reload更稳妥的做法是直接将Keepalived所在网卡加入trusted区域firewall-cmd --permanent --zonetrusted --add-interfaceeth0 firewall-cmd --reloadICMP Echo Requestping这是最常用的健康检查方式。firewall-cmd --permanent --add-serviceicmp即可。但如果用TCP端口检查如script /usr/bin/nc -z 127.0.0.1 80则必须放行对应端口firewall-cmd --permanent --add-port80/tcp firewall-cmd --reloadARP请求与响应VIP切换后主节点要向局域网广播ARP通告“192.168.1.100这个IP现在在我这里请更新你们的ARP缓存”。如果防火墙或交换机ACL阻止了ARP包客户端就一直访问旧的MAC地址导致服务不可用。检查方法# 在主节点执行观察是否发出ARP通告 tcpdump -i eth0 arp and host 192.168.1.100 -c 5 # 在客户端执行看ARP缓存是否更新 arp -n | grep 192.168.1.100注意某些云平台如AWS、阿里云的虚拟网络默认过滤ARP广播。如果你在云上部署必须确认VPC或安全组策略允许ARP流量。本地IDC则需检查物理交换机的arp inspection功能是否开启。3.3 SELinux策略让Keepalived获得“特权通行证”SELinux是RHEL系发行版的安全基石也是Keepalived部署中最隐蔽的“坑”。默认策略下Keepalived进程被限制在keepalived_t域它没有权限读取/etc/keepalived/keepalived.conf该文件默认标签为etc_t也没有权限绑定到非标准端口如80端口需要http_port_t标签更没有权限发送原始网络包VRRP需要net_admin能力。文件上下文修复/etc/keepalived/目录及其配置文件必须打上正确的SELinux标签semanage fcontext -a -t keepalived_etc_t /etc/keepalived(/.*)? restorecon -Rv /etc/keepalived/如果不做这步sestatus -b | grep keepalived会看到allow_keepalived_read_etc为offKeepalived启动时日志里全是Permission denied。端口标签修复如果Keepalived管理的是Web服务端口80/443必须给端口打标签semanage port -a -t http_port_t -p tcp 80 semanage port -a -t http_port_t -p tcp 443否则即使Nginx配置了监听VIPSELinux也会拦截连接。布尔值开关启用两个关键布尔值setsebool -P keepalived_connect_any on setsebool -P keepalived_use_nfs offkeepalived_connect_any允许Keepalived连接任意网络地址用于健康检查keepalived_use_nfs在我们场景中不需要关掉更安全。提示调试SELinux问题最快的方法是临时设为permissive模式setenforce 0。如果此时Keepalived一切正常那100%是SELinux策略问题。但切记这只是诊断手段绝不能在生产环境长期使用。3.4 systemd服务定制超越默认Unit文件的深度控制默认的/usr/lib/systemd/system/keepalived.service文件对多环境适配来说过于简陋。我们必须手动覆盖它添加关键依赖和启动条件。创建覆盖文件在/etc/systemd/system/keepalived.service.d/目录下新建override.conf[Service] # 强制依赖网络在线 Afternetwork-online.target Wantsnetwork-online.target # RHEL9必须依赖firewalld BindsTofirewalld.service Wantsfirewalld.service # 防止因网络延迟导致启动失败 RestartSec5 # 增加启动超时给内核模块加载留足时间 TimeoutStartSec60 # 日志级别调高便于排错 EnvironmentKEEPALIVED_DEBUG1 [Install] WantedBymulti-user.target然后重载配置systemctl daemon-reload启动顺序陷阱在Rocky 8.10中NetworkManager服务启动比keepalived快但NetworkManager可能需要几秒时间才能将IP地址配置到网卡上。如果Keepalived在IP配置完成前就启动它会认为网卡没有IP直接退出。解决方案是在override.conf中添加ExecStartPre/bin/sh -c while ! ip addr show eth0 | grep -q inet ; do sleep 1; done这行脚本会在Keepalived启动前循环检查eth0是否已有inet地址有则继续无则等待1秒再试最多等60秒由TimeoutStartSec控制。实操心得systemctl status keepalived看到的Active: active (running)只是进程状态不代表VIP已就绪。必须配合ip addr show和tcpdump一起看才能确认服务真正“活”了。3.5 Keepalived配置文件从骨架到血肉的逐行精解/etc/keepalived/keepalived.conf是Keepalived的大脑。下面是一个经过多环境验证的最小可行配置MVP我逐行解释其含义和适配要点# 全局定义块所有实例共享的参数 global_defs { # 路由ID必须全局唯一建议用主机名 router_id LVS_DEVEL_NODE1 # 通知邮箱可选生产环境建议配置 notification_email { adminexample.com } notification_email_from keepalivedexample.com smtp_server 127.0.0.1 smtp_connect_timeout 30 } # VRRP实例定义一个实例管理一个VIP vrrp_instance VI_1 { # 状态主节点为MASTER备节点为BACKUP state MASTER # 绑定的物理网卡 interface eth0 # VRRP虚拟路由器ID同一网段内必须唯一1-255 virtual_router_id 51 # 优先级决定谁当Master数值越大越优先 priority 100 # VRRP通告间隔单位秒建议1-3秒 advert_int 1 # 认证方式简单密码认证 authentication { auth_type PASS auth_pass 1111 } # 虚拟IP地址即对外提供服务的IP virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:1 } # 健康检查脚本 track_script { chk_http_port } } # 健康检查脚本定义 vrrp_script chk_http_port { # 执行的命令返回0表示成功非0表示失败 script /usr/bin/killall -0 nginx # 检查间隔单位秒 interval 2 # 失败几次后降低优先级 fall 2 # 成功几次后恢复优先级 rise 2 # 优先级调整值失败一次减2成功一次加2 weight -2 }state MASTER/BACKUP这是逻辑状态不是物理角色。Keepalived启动时会根据priority和virtual_router_id自动选举。你可以把所有节点都设为BACKUP然后靠priority和weight动态升降这样更灵活。virtual_router_id 51这个ID必须在同一广播域内唯一。如果网络中有多个Keepalived集群ID重复会导致VRRP包互相干扰。建议用集群编号服务编号组合如web_cluster_01对应51db_cluster_02对应52。virtual_ipaddress中的label eth0:1这是给VIP绑定一个别名接口。好处是ip addr show时能清晰区分真实IP和VIP避免混淆。在RHEL9中如果不加labelVIP可能无法正确绑定到指定网卡。weight -2这是最精妙的设计。chk_http_port脚本失败时Keepalived不会立即降级而是先将priority减去2100→98。如果此时备节点priority是90它还是不会接管9890。只有当主节点连续失败两次priority降到96且备节点priority是90才会触发切换。这给了服务自我恢复的时间窗口避免瞬时抖动引发的“乒乓效应”。注意killall -0 nginx命令在RHEL9中可能不存在psmisc包未安装应替换为pgrep -x nginx /dev/null。多环境适配连一个命令的可用性都要验证。3.6 时间同步NTP精度对VRRP心跳的影响VRRP协议本身不依赖系统时间但Keepalived的日志、健康检查超时计算、以及主备切换的决策逻辑都隐式依赖时间精度。如果两台服务器时间相差超过1秒可能导致以下问题日志时间错乱主节点日志显示“10:00:00 接收到心跳”备节点日志显示“10:00:01 发送心跳”你根本无法判断谁先谁后。健康检查超时误判interval 2表示每2秒检查一次但如果系统时间漂移严重实际检查间隔可能变成1.5秒或2.5秒连续两次超时就触发切换。因此所有Keepalived节点必须强制使用chrony进行高精度时间同步# 安装chrony yum install -y chrony # 配置指向可信NTP服务器如国内阿里云ntp1.aliyun.com echo server ntp1.aliyun.com iburst /etc/chrony.conf echo makestep 1.0 3 /etc/chrony.conf # 启用并启动 systemctl enable chronyd systemctl start chronyd # 验证同步状态 chronyc tracking # 输出应显示System clock is synchronizedmakestep 1.0 3这行配置至关重要它表示如果系统时钟偏差超过1秒chronyd会在3秒内将时间“跳跃”修正而不是缓慢调整。VRRP对时间突变不敏感但对长时间漂移极其敏感。4. 实操过程与核心环节实现从零开始的四步落地法现在我们把前面所有理论浓缩成一套可立即执行的四步法。无论你面对的是CentOS 7.9、Rocky 8.10还是RHEL9.3只要按这四步走就能在10分钟内完成一个可验证的Keepalived高可用环境。我以“主节点IP 192.168.1.10备节点IP 192.168.1.11VIP 192.168.1.100”为例全程实录。4.1 第一步环境预检与基础加固2分钟这一步不是安装而是“扫雷”。在敲下第一个yum命令前先确认环境底座是否稳固。检查内核版本与架构uname -r # CentOS 7.9: 3.10.0-1160.118.1.el7.x86_64 # Rocky 8.10: 4.18.0-513.18.1.el8_9.x86_64 # RHEL9.3: 5.14.0-362.18.1.el9_3.x86_64 uname -m # 确保是x86_64ARM64需额外处理检查SELinux状态sestatus # 必须是enabled且mode为enforcing。如果是disabled需重启后生效。 # 如果是permissive先setenforce 1再sestatus确认。检查firewalld状态systemctl status firewalld # 必须是active (running)。如果stoppedsystemctl start firewalld systemctl enable firewalld检查网络连通性ping -c 3 192.168.1.10 # 主节点自己 ping -c 3 192.168.1.11 # 备节点 ping -c 3 192.168.1.1 # 网关实操心得我曾经在一个Rocky 8.10节点上ping网关不通但curl http://192.168.1.1却能返回网页。后来发现是firewalld的public区域规则里icmp服务被禁用了但HTTP服务开着。ping走ICMPcurl走TCP所以表现不一致。预检时ping和curl都要试。4.2 第二步安装与内核模块初始化3分钟这是最“标准化”的一步但细节决定成败。执行安装所有节点执行# CentOS 7.9 Rocky 8.10 yum install -y keepalived # RHEL9.3 (dnf是默认包管理器) dnf install -y keepalived加载内核模块所有节点执行# 加载必需模块 modprobe ip_vs modprobe nf_conntrack modprobe nf_defrag_ipv4 # 永久化 echo ip_vs /etc/modules-load.d/ip_vs.conf echo nf_conntrack /etc/modules-load.d/ip_vs.conf echo nf_defrag_ipv4 /etc/modules-load.d/ip_vs.conf # 关闭nf_conntrack_helperRHEL9默认已关Rocky8需手动 echo net.netfilter.nf_conntrack_helper 0 /etc/sysctl.conf sysctl -p验证模块加载lsmod | grep -E (ip_vs|nf_conntrack|nf_defrag) # 应该看到三行输出 cat /proc/sys/net/netfilter/nf_conntrack_helper # 应该输出0注意modprobe ip_vs在CentOS 7.9上会提示modprobe: FATAL: Module ip_vs not found in directory /lib/modules/3.10.0-1160.118.1.el7.x86_64这是正常的因为它是内置的。只要ipvsadm -Ln能用就说明OK。4.3 第三步配置文件编写与服务定制3分钟这是最体现“多环境适配”的一步。配置文件内容相同但服务定制略有差异。编写/etc/keepalived/keepalived.conf主节点cat /etc/keepalived/keepalived.conf EOFglobal_defs { router_id LVS_DEVEL_NODE1 }vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:1 } track_script { chk_http_port } }vrrp_script chk_http_port { script /usr/bin/pgrep -x nginx /dev/null interval 2 fall 2 rise 2 weight -2 } EOF- **编写/etc/keepalived/keepalived.conf**备节点 bash # 只改两处state 和 priority sed -i s/MASTER/BACKUP/g; s/priority 100/priority 90/g /etc/keepalived/keepalived.conf创建systemd覆盖文件所有节点mkdir -p /etc/systemd/system/keepalived.service.d/ cat /etc/systemd/system/keepalived.service.d/override.conf EOF[Service] Afternetwork-online.target Wantsnetwork-online.target BindsTofirewalld.service Wantsfirewalld.service RestartSec5 TimeoutStartSec60 EnvironmentKEEPALIVED_DEBUG1[Install] WantedBymulti-user.target EOF systemctl daemon-reload- **修复SELinux上下文**所有节点 bash semanage fcontext -a -t keepalived_etc_t /etc/keepalived(/.*)? restorecon -Rv /etc/keepalived/ setsebool -P keepalived_connect_any on4.4 第四步启动、验证与故障注入测试2分钟安装完成不等于成功验证才是关键。启动服务所有节点systemctl start keepalived systemctl enable keepalived验证进程与VIP主节点systemctl status keepalived | grep active (running) ip addr show eth0 | grep 192.168.1.100 # 应该看到inet 192.168.1.100/24 scope global secondary eth0:1验证VRRP通信主节点# 抓5个VRRP包 tcpdump -i eth0 -nn -c 5 ip proto \\0x69 2/dev/null | head -5 # 正常输出类似10:00:00.000000 IP 192.168.1.10 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 36故障注入测试模拟主节点宕机# 在主节点执行模拟服务崩溃 pkill nginx # 等待4秒2次检查间隔 * fall 2 # 在备节点执行 ip addr show eth0 | grep 192.168.1.100 # 应该能看到VIP已接管 systemctl status keepalived | grep State # 应该显示 State MASTER恢复测试模拟主节点恢复# 在主节点重启Nginx systemctl start nginx # 等待4秒 # 在主节点执行 ip addr show eth0 | grep 192.168.1.100 # VIP应该回来 systemctl status keepalived | grep State # State MASTER实操心得tcpdump抓包是终极验证手段。如果ip addr看到VIP但tcpdump抓不到VRRP包说明防火墙或内核模块有问题如果tcpdump能抓到包但VIP不漂移说明priority或weight配置有误。把这两条命令组合起来90%的问题都能定位。5. 常见问题与排查技巧实录来自真实战场的速查表在给十几个不同客户部署Keepalived的过程中我整理了一份高频问题速查表。这些问题每一个都来自真实故障现场每一个都有明确的“症状-原因-解决”三步法。与其在日志里大海捞针不如先对照这张表。问题现象根本原因快速解决systemctl status keepalived显示failed日志里有Failed to initialize ipvsip_vs