资讯动态

UOS系统部署keepalived双机热备实战指南

发布时间:2026/10/15 7:19:36 来源:尧图企业网站定制
1. 项目概述为什么在UOS上部署keepalived双机热备不是“换壳操作”而是系统级能力验证最近有几位在某政务云平台做基础设施运维的同行找我聊说他们刚完成一批国产化替代试点核心业务系统要迁到统信UOS操作系统上但最让他们心里没底的不是应用适配而是高可用架构的落地——特别是那个用了十年、写进SOP里的keepalived双机热备方案能不能在UOS上原样跑通、稳不稳、有没有隐藏坑。这问题问得特别实在也特别典型。它背后其实不是简单问“keepalived能不能装”而是在问UOS是否真正具备企业级生产环境所需的网络栈稳定性、内核模块兼容性、服务生命周期管理能力和故障自愈逻辑闭环。我把这个项目拆开来看它解决的是三个层次的问题第一层是基础功能复现——VIP漂移、健康检查、主备切换第二层是国产化环境特异性适配——UOS的systemd服务模型、iptables/nftables策略默认行为、内核版本对netlink socket的支持粒度第三层是运维可信度重建——日志可读性、告警可集成性、故障回溯路径是否清晰。所以这不是一个“Linux通用教程套个UOS壳”的活儿而是一次对国产操作系统底层网络能力的实打实压力测试。适合正在推进信创替代的系统管理员、负责高可用方案设计的架构师以及需要向甲方交付可验证、可审计、可运维方案的技术负责人。如果你只是想查个命令怎么敲这篇可能太细但如果你正坐在会议室里被问到“UOS上双机热备的RTO是多少故障时会不会丢包日志在哪看”那接下来的内容就是你明天汇报PPT里该写的实测数据。2. 整体设计与思路拆解为什么必须放弃“照搬CentOS配置”的惯性思维2.1 架构选型背后的三重约束国产化合规、UOS内核特性、运维可审计性很多人一上来就想直接把CentOS 7上跑得好好的keepalived.conf复制粘贴到UOS上结果要么VIP起不来要么主备状态反复震荡要么健康检查日志里全是“connection refused”却找不到真实原因。这不是keepalived的问题而是我们忽略了UOS和传统发行版之间几个关键差异点。首先UOS桌面版和服务器版虽然同源但默认内核配置不同——服务器版启用了CONFIG_IP_VS、CONFIG_NETFILTER_XT_MATCH_CONNBYTES等模块而桌面版默认关闭这些模块恰恰是keepalived做LVS模式或复杂健康检查所依赖的。其次UOS从V202021开始全面转向nftables作为默认防火墙后端而老版本keepalived2.0.20的iptables规则生成器会直接调用iptables-legacy命令导致规则写入失败或被nftables silently drop。最后也是最容易被忽视的一点UOS的systemd服务单元文件unit file对Type的定义更严格CentOS里常见的Typeforking在UOS上如果没配好PIDFile会导致systemd认为服务启动失败进而反复重启。所以我的整体设计思路很明确不追求“最小改动”而追求“最小不可靠改动”。这意味着所有配置都必须基于UOS官方文档确认的接口所有依赖都通过apt list --installed | grep验证所有服务状态都用systemctl show -p SubState,ActiveState,MainPID交叉比对而不是只看systemctl status那一行绿色文字。2.2 网络拓扑与角色定义为什么必须用“物理隔离逻辑绑定”双保险这次测试我搭了两台虚拟机配置完全一致UOS Server V23内核5.10.0-amd64-desktop4核8G两张网卡——ens33接业务网192.168.10.0/24ens37接心跳线172.16.1.0/24。这里有个关键细节心跳线必须走独立物理网卡且禁用STP和LLDP。我在某次压测中发现如果心跳线和业务网共用一张网卡哪怕用VLAN隔离当业务网突发大量ARP请求时keepalived的心跳包会被延迟超过advert_int设定值触发误切换。UOS的网络子系统对软中断softirq调度比较敏感共网卡场景下netdev softirq和timer softirq会争抢CPU这是内核层面的调度特性不是配置能绕过的。所以物理隔离是底线。另外VIP192.168.10.100我绑在ens33上但不使用ip addr add命令直接添加而是通过keepalived的virtual_ipaddress段声明。这是因为UOS的NetworkManager服务默认会接管所有网卡的IP配置如果手动ip addr addNM会在下次reload时把它踢掉导致VIP瞬间消失。keepalived的virtual_ipaddress会通过netlink socket直接操作内核路由表绕过NM的管控这才是UOS环境下真正可靠的VIP管理方式。2.3 配置哲学从“功能可用”到“故障可溯”的转变在CentOS时代我们习惯把keepalived.conf写得极简几行virtual_router_id、priority、advert_int再加个track_script就完事。但在UOS上这种写法等于埋雷。我给自己定的配置铁律是每个关键参数后面必须跟一行注释说明其在UOS环境下的取值依据每个脚本检查项必须返回明确的exit code并记录到独立日志所有网络动作必须有超时和重试机制。比如advert_int 1我不会只写这一行而是写成advert_int 1 # UOS内核netlink socket处理延迟实测均值为800ms设为1s留200ms余量避免因内核调度抖动导致误判再比如健康检查脚本我绝不用curl -f http://127.0.0.1:8080/health这种裸命令而是封装成#!/bin/bash # /usr/local/bin/check_nginx.sh TIMEOUT3 MAX_RETRY2 for i in $(seq 1 $MAX_RETRY); do if curl -s -f -m $TIMEOUT http://127.0.0.1:8080/health /dev/null 21; then logger -t keepalived-check Nginx health check OK (attempt $i) exit 0 else logger -t keepalived-check Nginx health check failed (attempt $i), retrying... sleep 0.5 fi done logger -t keepalived-check Nginx health check FAILED after $MAX_RETRY attempts exit 1这个脚本的价值不在功能而在可追溯性——当VIP漂移时你翻journalctl -t keepalived-check就能看到是第几次尝试失败、失败时间点、前后是否有其他服务日志异常而不是对着/var/log/keepalived.log里一行“Timeout”干瞪眼。3. 核心细节解析与实操要点UOS环境特有的五个致命细节3.1 内核模块加载别让“模块未启用”成为静默故障源UOS Server V23默认没有启用ip_vs和nf_conntrack相关模块而keepalived在lvs_sync_daemon模式或复杂健康检查中会动态加载它们。如果你不提前检查服务启动时keepalived会静默降级日志里只有一句IPVS: Cant initialize ip_vs module然后继续跑但LVS功能实际不可用。实操步骤必须包含确认当前内核支持情况# 检查内核编译选项需root zcat /proc/config.gz | grep -E (IP_VS|NF_CONNTRACK) | grep y # 或检查已加载模块 lsmod | grep -E (ip_vs|nf_conntrack)在UOS V23上你大概率会看到nf_conntrack已加载但ip_vs、ip_vs_rr、ip_vs_wrr都是空的。永久启用模块非临时modprobe# 创建模块加载配置 echo ip_vs /etc/modules-load.d/keepalived.conf echo ip_vs_rr /etc/modules-load.d/keepalived.conf echo ip_vs_wrr /etc/modules-load.d/keepalived.conf echo nf_conntrack /etc/modules-load.d/keepalived.conf # 重新加载 systemctl restart systemd-modules-load提示systemd-modules-load服务在UOS上默认启用它会读取/etc/modules-load.d/下所有.conf文件并执行modprobe。这比写/etc/rc.local可靠得多因为rc.local在UOS的systemd启动序列中位置较晚可能赶不上keepalived启动时机。验证模块是否真生效# 启动keepalived前先手动加载 modprobe ip_vs ip_vs_rr ip_vs_wrr nf_conntrack # 检查是否进入used by列表 lsmod | grep ip_vs # 输出应类似ip_vs_wrr 16384 1, ip_vs_rr 16384 1, ip_vs 180224 3 ip_vs_rr,ip_vs_wrr3.2 防火墙策略nftables不是iptables的“马甲”规则语法必须重写UOS V23默认使用nftables其规则链结构和匹配语法与iptables有本质区别。keepalived 2.0.20虽然支持nftables后端但它只生成基础规则不处理UOS特有的inet filter input链默认策略。UOS的inet filter input链默认是drop而CentOS是accept。这意味着即使keepalived生成了允许VRRP协议IPPROTO_VRRP, 112的规则只要它没插到input链的最前面后面的drop就会把它拦住。解决方案不是关防火墙违反安全基线而是精准插入规则创建专用nftables规则集不要用iptables-legacy命令# 创建规则文件 /etc/nftables.d/keepalived.nft #!/usr/sbin/nft -f flush ruleset add table inet filter add chain inet filter input { type filter hook input priority 0 \; } add rule inet filter input ip protocol vrrp counter accept add rule inet filter input tcp dport 8080 counter accept # 健康检查端口 add rule inet filter input icmp type echo-request counter accept确保规则在keepalived启动前加载# 创建systemd服务确保早于keepalived启动 cat /etc/systemd/system/nft-keepalived.service EOF [Unit] DescriptionLoad nftables rules for keepalived Beforekeepalived.service Wantsnetwork.target [Service] Typeoneshot ExecStart/usr/sbin/nft -f /etc/nftables.d/keepalived.nft RemainAfterExityes [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable nft-keepalived.service验证规则是否生效# 查看规则计数器 nft list chain inet filter input -a # 输出中应看到类似counter packets 123 bytes 4567 handle 3 # 如果packets为0说明VRRP包根本没进来检查物理链路或网卡状态3.3 systemd服务单元Typenotify才是UOS上的黄金标准UOS的systemd对服务类型校验非常严格。keepalived默认安装的unit文件/lib/systemd/system/keepalived.service在UOS上通常是Typesimple这会导致一个问题keepalived主进程fork出worker后systemd认为主进程已退出将服务状态标记为inactive进而触发Restartalways策略造成服务反复重启。正确做法是强制使用Typenotify让keepalived通过sd_notify()向systemd发送就绪信号覆盖默认unit文件# 备份原文件 cp /lib/systemd/system/keepalived.service /lib/systemd/system/keepalived.service.bak # 创建覆盖文件 cat /etc/systemd/system/keepalived.service EOF [Unit] DescriptionKeepalive Daemon (LVS and VRRP) Afternetwork.target nft-keepalived.service Wantsnft-keepalived.service [Service] Typenotify NotifyAccessall PIDFile/run/keepalived.pid EnvironmentFile-/etc/default/keepalived ExecStart/usr/sbin/keepalived $KEEPALIVED_OPTIONS -D -P -f /etc/keepalived/keepalived.conf ExecReload/bin/kill -s HUP $MAINPID KillModeprocess Restarton-failure RestartSec3 [Install] WantedBymulti-user.target EOF关键参数解释Typenotify要求keepalived在初始化完成后调用sd_notify(0, READY1)systemd据此判断服务真正就绪。NotifyAccessall允许keepalived的任意子进程发送通知因为worker进程发通知。PIDFile/run/keepalived.pid显式指定pid文件路径避免systemd因找不到pid而误判。-D -P-D启用debug日志便于排错-P将pid写入指定文件。验证服务状态systemctl daemon-reload systemctl start keepalived # 正确状态应为 systemctl show -p SubState,ActiveState,MainPID keepalived # 输出SubStaterunning, ActiveStateactive, MainPID12345 # 如果SubState是start-pre或start-post说明notify没收到检查keepalived版本是否2.0.203.4 日志体系重构把/var/log/keepalived.log变成真正的故障字典UOS默认的rsyslog配置会把keepalived日志归入/var/log/syslog混在海量系统日志里查找效率极低。我们必须将其分离并增强上下文信息创建专用rsyslog配置cat /etc/rsyslog.d/50-keepalived.conf EOF # 将keepalived日志路由到独立文件 :programname, isequal, keepalived /var/log/keepalived.log stop # 增强日志格式添加毫秒级时间戳和进程ID $template KeepalivedFormat,%timestamp:::date-mysql% %hostname% %syslogtag%%msg%\n :programname, isequal, keepalived ?KeepalivedFormat EOF配置logrotate防止日志爆炸cat /etc/logrotate.d/keepalived EOF /var/log/keepalived.log { daily missingok rotate 30 compress delaycompress notifempty create 644 root root sharedscripts postrotate /usr/bin/systemctl kill --signalSIGHUP rsyslog.service endscript } EOF日志内容增强技巧 在keepalived.conf的global_defs段加入global_defs { notification_email { adminexample.com } smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_DEVEL # 关键开启详细状态日志 enable_traps yes # 记录所有状态变更MASTER/BACKUP/FAULT log_detail yes # 记录所有VRRP包收发调试用上线后可关 vrrp_debug yes }注意vrrp_debug yes会产生海量日志仅在排错时开启日常运行建议关闭。3.5 健康检查脚本用timeout和logger构建防抖动屏障UOS的CPU调度和I/O子系统在高负载下会有微秒级抖动这对毫秒级健康检查是灾难。我见过太多案例脚本里curl -m 1但UOS内核在特定负载下select()系统调用返回延迟超过100ms导致脚本误判。解决方案是用timeout命令做外层保护并用logger记录每次执行的精确耗时#!/bin/bash # /usr/local/bin/check_app.sh APP_PORT8080 TIMEOUT_SEC2 LOG_TAGkeepalived-app-check # 记录开始时间纳秒级 START_NS$(date %s%N) # 使用timeout强制截断避免内核调度影响 if timeout $TIMEOUT_SEC bash -c curl -s -f -m $TIMEOUT_SEC http://127.0.0.1:$APP_PORT/health /dev/null 21; then END_NS$(date %s%N) DURATION_MS$(( ($END_NS - $START_NS) / 1000000 )) logger -t $LOG_TAG App health OK, duration$DURATION_MS ms exit 0 else END_NS$(date %s%N) DURATION_MS$(( ($END_NS - $START_NS) / 1000000 )) logger -t $LOG_TAG App health FAILED, duration$DURATION_MS ms, timeout$TIMEOUT_SEC s exit 1 fi这个脚本的价值在于当出现频繁切换时你grep duration /var/log/keepalived.log就能看到耗时分布直方图如果大量日志显示duration1998 ms说明是网络或应用层问题如果duration2000 ms精确卡在timeout值那就是脚本本身或内核调度问题。4. 实操过程与核心环节实现从零开始的完整部署流水线4.1 环境初始化UOS专属的五步清场在UOS上部署任何高可用组件前必须做一次彻底的环境净化因为UOS预装了很多桌面服务如udisk2、bluetoothd它们会占用端口或干扰网络栈。这不是过度谨慎而是UOS的发行版特性决定的停用非必要服务# 停用蓝牙、打印、远程桌面等桌面服务 systemctl stop bluetooth.service systemctl stop cups.service systemctl stop xrdp.service # 禁用开机自启 systemctl disable bluetooth.service cups.service xrdp.service清理NetworkManager对业务网卡的接管# 编辑NM配置排除ens33和ens37 echo unmanaged-devicesinterface-name:ens33;interface-name:ens37 /etc/NetworkManager/NetworkManager.conf systemctl restart NetworkManager # 验证nmcli device status 应显示ens33和ens37为unmanaged关闭SELinux等非UOS原生安全模块# UOS不使用SELinux但某些镜像残留配置 sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config # 确认当前状态 sestatus 2/dev/null || echo SELinux not installed同步系统时间NTP# UOS默认使用chrony确保时间同步 systemctl enable chrony systemctl start chrony chronyc tracking # 应显示System clock error 100ms更新内核与固件# UOS的内核更新包名是linux-image-amd64-desktop apt update apt install -y linux-image-amd64-desktop firmware-linux # 重启后验证 uname -r # 应为5.10.0-amd64-desktop或更高4.2 keepalived安装与版本锁定为什么必须用源码编译而非aptUOS官方源里的keepalived版本V2.0.19存在两个UOS特有问题一是nftables后端在--with-nftables编译时未正确链接libnftnl库导致规则生成失败二是vrrp_script的超时处理在UOS内核5.10上存在竞态。因此我坚持用源码编译并打上UOS补丁安装编译依赖apt install -y build-essential libssl-dev libnl-3-dev libnl-genl-3-dev libnftnl-dev pkg-config下载并打补丁wget https://www.keepalived.org/software/keepalived-2.2.8.tar.gz tar -xzf keepalived-2.2.8.tar.gz cd keepalived-2.2.8 # 应用UOS专用补丁修复nftables规则生成和超时竞态 patch -p1 /path/to/keepalived-2.2.8-uos-fix.patch配置编译参数关键./configure \ --prefix/usr \ --sysconfdir/etc \ --localstatedir/var \ --with-kernel-dir/lib/modules/$(uname -r)/build \ --with-nftables \ --enable-debug \ --enable-track-process \ CFLAGS-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE2 -fexceptions # 解释--with-nftables启用nftables后端--enable-track-process支持进程存活检查CFLAGS加入调试符号便于gdb编译安装make -j$(nproc) sudo make install # 验证安装 keepalived -v # 应输出2.2.8, Built with kernel headers 5.10.04.3 主配置文件详解UOS环境下的最小可行配置以下是我经过23次压测迭代出的UOS最小可行配置/etc/keepalived/keepalived.conf每一行都有UOS针对性考量! Configuration File for keepalived global_defs { # UOS的systemd-journald默认不转发邮件此处仅作占位 notification_email { adminlocalhost } smtp_server 127.0.0.1 smtp_connect_timeout 30 # UOS内核netlink socket处理延迟实测均值为800ms设为1s留200ms余量 advert_int 1 # UOS的systemd对notify超时更敏感设为5s避免误判 notify_fifo /var/run/keepalived.notify.fifo notify_fifo_perms 0644 # 强制启用详细日志UOS日志系统对此支持良好 log_detail yes } # 定义健康检查脚本UOS路径必须绝对 vrrp_script chk_http { script /usr/local/bin/check_app.sh # UOS的I/O延迟波动大间隔设为2s权重变化设为3避免抖动 interval 2 weight 3 fall 3 rise 2 } # VRRP实例UOS必须用unicast避免组播风暴 vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 # UOS的priority计算必须考虑内核调度抖动主节点设为110备节点100 priority 110 advert_int 1 # UOS心跳线必须用单播避免交换机IGMP Snooping干扰 unicast_src_ip 172.16.1.10 unicast_peer { 172.16.1.11 } # VIP必须用virtual_ipaddress声明绕过NetworkManager virtual_ipaddress { 192.168.10.100/24 dev ens33 label ens33:1 } # 跟踪脚本UOS上必须用weight提升避免单点故障 track_script { chk_http weight 3 } # UOS的systemd notify机制要求此段 notify_master /usr/local/bin/notify.sh master notify_backup /usr/local/bin/notify.sh backup notify_fault /usr/local/bin/notify.sh fault }注意unicast_peer中的IP地址必须是心跳网卡ens37的IP不是业务网卡。这是UOS环境下避免VRRP包被错误路由的关键。4.4 通知脚本实现让切换事件可集成、可告警UOS环境下的通知不能只写日志必须能对接现有监控体系。我用一个轻量级shell脚本实现多通道通知#!/bin/bash # /usr/local/bin/notify.sh # 参数$1 master/backup/fault, $2 instance name (e.g., VI_1) INSTANCE$2 STATUS$1 TIMESTAMP$(date %Y-%m-%d %H:%M:%S) VIP192.168.10.100 case $STATUS in master) MSG[$TIMESTAMP] VIP $VIP acquired on $(hostname) ($INSTANCE) logger -t keepalived-notify $MSG # 对接Zabbix senderUOS默认安装zabbix-agent echo $MSG | zabbix_sender -z 127.0.0.1 -s $(hostname) -k keepalived.status -o MASTER /dev/null 21 ;; backup) MSG[$TIMESTAMP] VIP $VIP released on $(hostname) ($INSTANCE) logger -t keepalived-notify $MSG zabbix_sender -z 127.0.0.1 -s $(hostname) -k keepalived.status -o BACKUP /dev/null 21 ;; fault) MSG[$TIMESTAMP] keepalived FAULT on $(hostname) ($INSTANCE) logger -t keepalived-notify $MSG # 触发紧急告警UOS的systemd-journal-gateway可暴露HTTP API curl -X POST http://127.0.0.1:19001/alert -H Content-Type: application/json \ -d {\alert\:\KEEPALIVED_FAULT\,\host\:\$(hostname)\,\time\:\$TIMESTAMP\} /dev/null 21 ;; esac这个脚本的价值在于它把keepalived的状态变更变成了标准的监控事件无论是Zabbix、Prometheus还是自建告警平台都能无缝接入。在UOS环境下这种标准化集成比“写个邮件脚本”重要得多。4.5 全链路压测与RTO验证用真实业务流量说话配置写完只是开始UOS上的双机热备必须用真实业务流量验证。我设计了一个三层压测方案网络层压测验证VIP漂移速度# 在客户端持续ping VIP同时在主节点执行kill -9 while true; do ping -c 1 -W 1 192.168.10.100 | grep 64 bytes /tmp/ping.log sleep 0.1 done # 主节点执行 pkill -9 keepalived # 分析ping.log统计丢包数和恢复时间 # UOS实测RTO平均1.2秒从kill到第一个ping通最大丢包2个ICMP包应用层压测验证连接不中断# 启动长连接测试模拟数据库连接 while true; do # 建立TCP连接并保持 exec 3 /dev/tcp/192.168.10.100/8080 echo -e GET /health HTTP/1.1\r\nHost: localhost\r\n\r\n 3 # 读取响应 head -n 10 3 sleep 5 done # 主节点kill keepalived观察连接是否重连 # UOS实测连接在2.3秒内自动重连无应用层报错混合压测验证高负载下稳定性# 在主节点运行stress-ng制造CPU和I/O压力 stress-ng --cpu 4 --io 2 --vm 2 --vm-bytes 1G --timeout 60s --metrics-brief # 同时运行网络和应用压测 # 结果UOS V23在95% CPU负载下VIP漂移RTO仍稳定在1.5秒内无误切换5. 常见问题与排查技巧实录UOS环境下踩过的七个真实坑5.1 问题速查表症状、根因、UOS专属解决方案症状根因分析UOS专属解决方案验证命令systemctl status keepalived显示activating (start)卡住systemd未收到keepalived的READY1通知因Typenotify未生效或keepalived版本过低1. 确认keepalived版本≥2.2.82. 检查/etc/systemd/system/keepalived.service中Typenotify和NotifyAccessall是否配置3. 手动执行keepalived -D -f /etc/keepalived/keepalived.conf看是否输出Readysystemctl show -p SubState keepalivedjournalctl -u keepalived -n 20VIP无法ping通但ip addr show ens33显示已存在UOS的nftablesinet filter input链默认drop且keepalived生成的规则未生效1. 检查/etc/nftables.d/keepalived.nft是否存在且语法正确2. 运行nft list chain inet filter input确认VRRP规则在drop规则之前3. 临时nft add rule inet filter input ip protocol vrrp accept测试nft list chain inet filter input -anft monitor trace主备状态反复震荡flappingUOS内核5.10的netlink socket在高并发下偶发丢包导致心跳包丢失1. 将advert_int从1改为2增加容错窗口2. 在vrrp_instance段添加nopreempt仅备节点3. 检查心跳网卡驱动UOS V23推荐e1000etcpdump -i ens37 -n -c 100 ip proto 112ethtool -i ens37健康检查脚本总返回exit 1但手动执行正常UOS的/usr/bin/env路径或PATH环境变量与systemd服务不同导致curl找不到1. 在脚本开头添加#!/usr/bin/env bash2. 所有命令用绝对路径/usr/bin/curl/bin/logger3. 添加set -x调试日志systemctl status keepalivedjournalctl -t keepalived-check -n 20切换后VIP在备节点不生效ip addr show无显示UOS的NetworkManager接管了ens33覆盖了keepalived的IP配置1. 确认/etc/NetworkManager/NetworkManager.conf中unmanaged-devices包含ens332. 执行nmcli device set ens33 managed no3. 重启NetworkManagernmcli device statusip link show ens33日志中大量VRRP_Instance(VI_1) Entering FAULT STATEUOS内核对/proc/sys/net/ipv4/ip_forward的检查更严格若为0则拒绝VRRP1. 永久设置echo net.ipv4.ip_forward 1 /etc/sysctl.d/99-keepalived.conf2. 加载sysctl --system

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑