Keepalived 是一个用 C 语言编写的路由软件,它通过维护 VIP(Virtual IP) 实现为 Linux 系统提供简单而健壮的负载均衡和高可用性设施。
介绍

说明:
- 图中的 VIP 由 keepalive 维护
- 使用场景
- 双活主备
- 冷备(注意是否切换成功)
-
主 priority > 备 priority && 主 priority + 主 vrrp_script.weight < 备 priority + 备 vrrp_script.weight
- 备的 notify_master 脚本中有启动服务的命令,备中服务最初处于关闭状态
重要概念
- 虚拟 IP 地址(VIP 或 VIPA)是指与实际物理网口不对应的 IP 地址。对 vip 的使用包括网络地址转换(特别是一对多 NAT)、容错和移动性
- A virtual IP address (VIP or VIPA) is an IP address that doesn’t correspond to an actual physical network interface. Uses for VIPs include network address translation (especially, one-to-many NAT), fault-tolerance, and mobility.
LVS(Linux virtual server) Linux 虚拟服务器,是一个虚拟的服务器集群系统。工作原理:用户请求 LVS VIP,LVS 根据转发方式和算法,将请求转发给后端服务器,后端服务器接收到请求,返回给用户。
ARP(Address Resolution Protocol) 协议属于 TCP/IP 协议族里面一种用户将 IP 地址解析为 MAC 地址的协议。该协议是用户局域网内解析 IP 地址对应的物理地址。
- 虚拟路由冗余协议
VRRP(Virtual Router Redundancy Protocol) 通过把几台路由设备联合组成一台虚拟的路由设备,将虚拟路由设备的 IP 地址作为用户的默认网关实现与外部网络通信。
VRRP/224.0.0.18
在 Keepalived 的 VRRP (Virtual Router Redundancy Protocol) 中,224.0.0.18 是一个组播(Multicast)IP 地址,它在协议通信中起着至关重要的作用。
224.0.0.18 是 Keepalived 集群中的 VRRP 路由器用来互相通信、进行主备状态同步和故障检测的信道地址。
以下是关于 224.0.0.18 的要点总结:
- VRRP 通信地址: VRRP 协议使用 224.0.0.18 这个特定的 IP 组播地址来发送 VRRP **通告(Advertisement)**报文。
- 目的:
- **主节点(Master)**会定期向这个地址发送通告报文,以宣布自己处于主控状态。
- **备用节点(Backup)**会监听这个地址的报文。如果备用节点在设定的时间间隔内没有接收到主节点的通告,它就会认为主节点已失效,并触发选举过程,尝试成为新的主节点。
- 协议号: VRRP 通信使用的 IP 协议号是 112 (IANA 分配给 VRRP 的协议号),而不是常见的 TCP 或 UDP。
- 防火墙要求: 由于 VRRP 的工作依赖于这个组播地址和特定的协议号,因此在使用 Keepalived 的服务器上,防火墙必须允许:
- 目标地址为 224.0.0.18
- IP 协议号为 112 (或协议名称
vrrp)
- 的**入站(Input)和出站(Output)**流量通过。
安装部署
环境说明
VMware Fusion pro,自定义网络已经打开混杂模式(VMware Fusion -> 偏好设置 -> 网络 -> 勾选 允许通过鉴定才能进入混杂模式):
- host1: 172.20.0.21
- host2: 172.20.0.22
- vip: 172.20.0.20
所有机器均配置 ip_nonlocal_bind 绑定(实现没有 vip 时,可以启动 haproxy 等服务):
echo net.ipv4.ip_nonlocal_bind=1 >> /etc/sysctl.conf
sysctl -p
CentOS 安装
为 host1、host2 安装软件
yum install -y nginx keepalived
sed -i "s#Welcome to CentOS#Welcome to CentOS`ip a | grep "172.20" | awk '{print $2}'`#g" /usr/share/nginx/html/index.html
通过 ip 地址区分访问的是哪个 nginx
systemctl start nginx.service
systemctl enable nginx.service
systemctl start keepalived.service
systemctl enable keepalived.service
配置 nginx
- nginx 存活检测脚本
/usr/local/bin/check_nginx_alive.sh
#!/bin/bash
nginx_count=`ps -C nginx --no-header |wc -l`
if [ $nginx_count -eq 0 ]; then
echo 'nginx server is died'
exit 1
fi
exit 0
或使用 systemctl is-active nginx 命令检测。
chmod +x /usr/local/bin/check_nginx_alive.sh
配置 host1 keepalive
host1 为 MASTER,priority 优先级为 100
-
如果 rise 次脚本执行都是成功的(返回 0),则增加 weight 数量的优先级
-
如果是 fall 次脚本执行都是失败的(返回 1),则减少|weight|数量的优先级
-
/etc/keepalived/keepalived.conf
- 配置文件示例
/etc/keepalived/keepalived.conf.sample 或 /usr/share/.../keepalived.conf.vrrp.localcheck(不同版本略有不同)
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script check_nginx_alive {
script "/usr/local/bin/check_nginx_alive.sh"
interval 3
rise 2
fall 3
weight -15
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.20.0.20 dev ens33
# 172.20.0.20 dev ens33 label ens33:1
}
track_script {
check_nginx_alive
}
# notify_master xxx
# notify_backup xxx
# notify_f.. xxx
}
virtual_server 172.20.0.20 80 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
# preempt
real_server 172.20.0.21 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
systemctl restart keepalived
配置 host2 keepalive
host2 为 BACKUP,priority 优先级为 90(比 host1 底)
- /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script check_nginx_alive {
script "/usr/local/bin/check_nginx_alive.sh"
interval 3
weight -15
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.20.0.20 dev ens33
}
track_script {
check_nginx_alive
}
}
virtual_server 172.20.0.20 80 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
real_server 172.20.0.22 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
systemctl restart keepalived
检测
$ ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:33:42:98 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.21/24 brd 172.20.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet 172.20.0.20/32 scope global ens33
valid_lft forever preferred_lft forever
systemctl stop nginx
可以观察到 vip 漂移到 host2,并且 访问 http://172.20.0.20 可以看到为 host2 的 nginx
systemctl start nginx
可以观察到 vip 漂移到 host1,并且 访问 http://172.20.0.20 可以看到为 host1 的 nginx
运维
问题是排查命令
tcpdump proto 112
tcpdump -i ens33 vrrp -n
arp -n
ip -br a 查看 ip 地址
haproxy 存活检测脚本
vrrp_script check_haproxy {
script "/usr/local/bin/check_keepalive.sh"
interval 1
weight -15
fall 3
rise 2
timeout 2
}
/usr/local/bin/check_haproxy_alive.sh
#!/bin/bash
# This will return 0 when it successfully talks to the haproxy daemon via the socket
# Failures return 1
echo "show info" | socat unix-connect:/var/lib/haproxy/stats stdio > /dev/null
chmod a+x /usr/local/bin/check_haproxy_alive.sh
/usr/local/bin/check_haproxy_alive2.sh 另一种实现方式?
#!/bin/bash
/usr/bin/killall -0 haproxy || systemctl restart haproxy
nginx
vrrp_script chk_nginx {
script "/etc/keepalived/nginx_check.sh"
interval 2 # 指定脚本执行的间隔,单位是秒,默认为1s
weight -20 # 调整优先级。默认为2。如果脚本执行失败(退出状态码为非0),weight小于0,则priority减少
fall 3 # 执行失败多少次才认为失败
rise 2 # 执行成功多少次才认为是成功
user root # 加上用户名,使用root用户登录的话
}
#!/bin/bash
A=`ps -ef | grep nginx | grep -v grep | wc -l`
if [ $A -eq 0 ];then
nginx
sleep 2
if [ `ps -ef | grep nginx | grep -v grep | wc -l` -eq 0 ];then
# killall keepalived
ps -ef|grep keepalived|grep -v grep|awk '{print $2}'|xargs kill -9
fi
fi
Tracking files
- Keepalived 支持根据文件内容来决定优先级,如运行的应用程序能向该文件(
/var/run/my_app/vrrp_track_file)写入值
- 若
echo 5 > /var/run/my_app/vrrp_track_file,则 prio 249 = 244 + 5
vrrp_track_file track_app_file {
file /var/run/my_app/vrrp_track_file
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 244
advert_int 1
authentication {
auth_type PASS
auth_pass 12345
}
virtual_ipaddress {
192.168.122.200/24
}
track_file {
track_app_file weight 1
}
}
Track interface
- 对于有多个接口的服务器,根据接口的状态调整 Keepalived 实例的优先级
- 若接口 ens5 是 up 的状态,prio 249 = 244 + 5
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 244
advert_int 1
authentication {
auth_type PASS
auth_pass 12345
}
virtual_ipaddress {
192.168.122.200/24
}
track_interface {
ens9 weight 5
}
}
F&Q
脚本开头加 #!bin/bash
Disabling track script xxx since not found/accessible
脚本需要写绝对路径
Keepalived_vrrp[]: WARNING - default user ‘keepalived_script’ for script execution does not exist
keepalived.conf 中添加:
global_defs {
script_user root
}
scripts are being executed but script_security not enabled
keepalived.conf 中添加:
global_defs {
enable_script_security
}
vip ping 不通
删除如下配置中的 vrrp_strict,严格遵守 VRRP 协议,不允许状况:
- 没有 VIP 地址
- 单播
- 在 VRRP 版本 2 中使用 IPv6 地址
global_defs {
vrrp_strict
}