高可用是生产环境中绕不开的话题。单台服务器无论配置多高,都存在宕机风险,一旦机器故障,业务就会中断。Keepalived基于VRRP协议提供了虚拟IP漂移能力,配合Docker的轻量化部署,可以用较低的成本搭建一套主备切换的高可用架构。本文从原理讲到实战配置,把部署过程中容易踩的坑也一并说明。

一、Keepalived高可用的核心原理
Keepalived的核心是VRRP协议(Virtual Router Redundancy Protocol,虚拟路由冗余协议)。它把多台服务器划分成一个VRRP组,组内有一台主节点(MASTER)和多台备节点(BACKUP)。整个组对外暴露一个虚拟IP(VIP),客户端只访问这个VIP,完全不需要关心请求最终落在哪台机器上。
主节点会周期性地向组内广播VRRP通告报文,默认间隔1秒。备节点如果在这个时间内没有收到通告,就会认为主节点故障。通常配置为连续3个周期未收到报文(即advert_int乘以3),备节点立即发起切换,将VIP接管到自己身上。整个切换过程在秒级完成,对客户端来说几乎无感知。
选举谁做主节点由优先级(priority)决定,数值越大越优先。如果两台机器优先级相同,就比较IP地址大小。需要注意的是,当原主节点恢复后,是否要抢回VIP取决于nopreempt配置。抢占模式(默认)下原主机会重新接管VIP,非抢占模式下则保持现状,避免不必要的切换抖动。
除了IP漂移,Keepalived还提供了vrrp_script健康检查机制,可以自定义脚本检测应用进程是否正常。这一点非常关键:如果Keepalived进程本身活着,但业务进程已经挂了,VIP依然会指向这台机器,请求照样失败。所以实际生产中必须配置健康检查,让VIP的漂移条件与业务状态挂钩,而不仅仅是主机存活。
二、Docker环境下运行Keepalived的网络模式选择
Keepalived需要操作网卡、发送VRRP组播报文,这对网络能力有较高要求。在Docker中部署时,网络模式的选择直接决定方案能否成立,这也是最容易出问题的地方。
最推荐的是host模式。容器直接共享宿主机网络栈,没有NAT转换,Keepalived可以像直接安装在宿主机上一样操作网卡。配置简单,VRRP组播报文正常收发,性能也没有损耗。命令如下:
docker run -d --name keepalived \ --network host \ --cap-add NET_ADMIN \ --cap-add NET_RAW \ -v /etc/keepalived/keepalived.conf:/etc/keepalived/keepalived.conf \ keepalived:latest
其中NET_ADMIN和NET_RAW两个权限必不可少。NET_ADMIN允许容器修改网络配置(添加VIP、修改路由),NET_RAW允许发送原始协议报文,VRRP协议号是112,属于IP层协议而非TCP或UDP,没有NET_RAW权限报文根本发不出去。
bridge模式则是另一条思路。默认桥接网络下容器有独立网络命名空间,Keepalived拿不到宿主机网卡,VIP漂移发生在容器内部,外部完全看不到,方案不成立。变通办法是使用PIPскоN或macvlan,让容器直接以独立MAC地址接入物理网络。macvlan方式下每个容器看起来像局域网里一台独立主机,VIP可以直接漂移到容器上,但要求宿主机网卡支持混杂模式,且部分云服务器(尤其是公有云)对自定义ARP响应有限制,使用前务必确认网络环境支持。
还有一种更简洁的架构:Keepalived直接装在宿主机上,只把业务应用放在Docker里。Keepalived本来就极轻量,把它容器化并没有太多收益,反而增加了网络调试的复杂度。业务容器化、Keepalived留在宿主机,健康检查脚本直接探测宿主机上业务容器的端口,这是生产中最常见也最稳妥的方案。
三、完整配置实例:主备节点搭建与验证
假设有两台服务器:主节点192.168.1.10,备节点192.168.1.11,VIP为192.168.1.100。主节点配置文件如下:
global_defs {
router_id LVS_MASTER
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -30
fall 2
rise 2
}
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
}
track_script {
check_nginx
}
}备节点的配置基本相同,只需修改三处:state改为BACKUP,priority降为90,router_id改名以示区分。virtual_router_id必须一致,否则两台机器不会被认作同一个VRRP组。注意同一局域网内如果有多个Keepalived集群,各自的virtual_router_id不能冲突。
健康检查脚本负责探测业务进程,这里以Nginx容器为例:
#!/bin/bash
if ! curl -sf http://127.0.0.1:8080/health >/dev/null; then
# 业务异常,退出码非0,触发weight变化
exit 1
fi
exit 0脚本配合weight -30使用:检查失败时优先级减30,主节点优先级从100降到70,低于备节点的90,VIP自动漂移过去。相比直接杀掉Keepalived进程,权重调整方式更平滑,业务恢复后优先级回升,VIP又能漂回主节点。
验证漂移效果很简单。先在主节点执行ip addr show eth0,能看到VIP绑定在eth0上。然后停掉主节点的业务容器,等待约4秒(interval乘以fall),在备节点再次查看网卡,VIP已经出现。用一台客户端持续ping 192.168.1.100,只会丢失一两个包,切换完成后服务继续可用。
四、常见问题与踩坑总结
第一个高频问题是VIP配了但不漂移。排查思路:两节点防火墙是否放行了VRRP协议(协议号112,不是端口号),iptables对协议类报文的过滤容易被忽略;virtual_router_id是否一致;组播网络是否互通,部分云环境的VPC默认禁止组播,此时需要改用单播配置,在vrrp_instance中添加unicast_peer指向对端IP。
第二个问题是脑裂,即主备都认为自己是MASTER,同时持有VIP,导致MAC地址来回漂移、请求时通时断。典型原因是主备之间VRRP报文不通,比如防火墙拦截或认证密码不一致。部署完成后应该主动验证:拔掉心跳线或用iptables阻断VRRP报文,观察是否出现双主。防护手段是增加第三条检测通道,例如通过健康检查脚本探测网关连通性,探测失败就主动放弃VIP。
第三,Docker环境下还要注意容器重启策略的设置。Keepalived容器要配置--restart=always或--restart=unless-stopped,宿主机重启后集群要能自动恢复。如果Keepalived跑在容器里,还需要保证它比业务容器晚启动或带重试逻辑,否则开机初期健康检查全部失败,可能触发一次不必要的漂移。
最后提醒一点,Keepalived解决的是“IP指向哪台机器”的问题,它不复制数据。如果业务有状态,比如数据库、会话,还需要配合数据同步方案(主从复制、共享存储等)才能真正实现业务连续性。高可用是系统工程,Keepalived只是其中一环,理解它的边界才能设计出可靠的架构。
KeepalivedDocker高可用修改时间:2026-09-05 09:28:37