KeepAlived 详解

Posted by Jason Lee on 2021-05-07

概诉

Keepalived 作用

keepalived顾名思义是保持存活,常用来搭建设备的高可用,防止业务核心设备出现单点故障。keepalived基于VRRP协议来实现高可用,主要用作realserver的健康检查以及负载均衡主机和backup主机之间的故障漂移。他很大程度上是为ipvs服务的,也不需要共享存储。Keepalived主要的任务就是去调用ipvsadm命令,来生成规则,并自动实现将用户需要访问的地址转移到可用LVS节点实现。所以keepalive的高可用是属于具有很强针对性的高可用。

Keepalived的主要目的就是它自身启动为一个服务,它工作在多个LVS主机节点上,当前活动的节点叫做Master备用节点叫做Backup,Master会不停的向Backup节点通告自己的心跳,这种通告是基于VRRP协议的。Backup节点一旦接收不到Master的通告信息,它就会把LVS的VIP拿过来,并且把ipvs的规则也拿过来,在自己身上生效,从而替代Master节点。

Keepalived除了可以监控和转移LVS资源之外,它还可以直接配置LVS而不需要直接使用ipvsadm命令,因为它可以调用,也就是说在LVS+KEEPALIVED模型中,你所有的工作在Keepalived中配置就可以了,而且它还有对后端应用服务器健康检查的功能。

如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,实现自动剔除与恢复,不需要人工干涉,需要人工做的只是修复故障的服务器。

Keepalived 健康检查可以在三层 - 五层之间:

  • 三层机理是发送ICMP数据包即PING给某台服务器,如果不通,则认为其故障,并从服务器群中剔除;
  • 四层机理是检测TCP端口号状态来判断某台服务器是否故障,如果检测端口存在异常,则从服务器群中剔除;
  • 五层机理是根据用户的设定检查某个服务器应用程序是否正常运行,如果不正常,则从服务器群中剔除,比如说某个网页,可以通过http 状态码来判定是否正常。

详解

虚拟路由冗余协议(VRRP)协议

VRRP解决什么问题

VRRP 是 Virtual Router Redundancy Protocol 的简称,即 虚拟路由冗余协议 。

如图所示,通常,同一网段内的所有主机都设置一条相同的、以网关为下一跳的缺省路由。主机 发往其他网段的报文将通过缺省路由发往网关,再由网关进行转发,从而实现主机与外部网络的通信。

当网关发生故障时,本网段内所有以网关为缺省路由的主机将无法与外部网络通信。

所以,网关设备提出了很高的稳定性要求。增加出口网关是提高系统可靠性的常见方法,此时如何在多个出口之间进行选路就成为需要解决的问题。
通俗的讲,就是在设置不同的网关,在一个网关机器宕机或者有问题的时候,可以进行自动的切换。

VRRP,就是解决这个问题而存在的,它将可以承担网关功能的一组 路由器加入到备份组中,形成一台虚拟路由器,由 VRRP 的选举机制决定哪台路由器承担转发任务, 局域网内的主机只需将虚拟路由器配置为缺省网关。通俗的来讲就是将网关做成主备方案,用于容错。

VRRP 协议的实现有 VRRPv2 和 VRRPv3 两个版本。其中,VRRPv2 基于 IPv4,VRRPv3 基于 IPv6。 VRRPv2 和 VRRPv3 在功能实现上并没有区别,只是应用的网络环境不同。

VRRP 备份组

VRRP 将局域网内的一组路由器划分在一起,称为一个备份组。备份组由一个 Master 路由器和多个 Backup 路由器组成,功能上相当于一台虚拟路由器。 VRRP 备份组具有以下特点:

  • 虚拟路由器具有IP地址,称为虚拟IP地址。局域网内的主机仅需要知道这个虚拟路由器的IP地址,并将其设置为缺省路由的下一跳地址。

  • 网络内的主机通过这个虚拟路由器与外部网络进行通信。

  • 备份组内的路由器根据优先级,选举出 Master 路由器,承担网关功能。其他路由器作为 Backup 路由器,当 Master 路由器发生故障时,取代 Master 继续履行网关职责,从而保证网络内的 主机不间断地与外部网络进行通信。

如 图 2所示,Router A、Router B和Router C组成一个虚拟路由器。此虚拟路由器有自己的IP地址。 局域网内的主机将虚拟路由器设置为缺省网关。Router A、Router B和Router C中优先级最高的路 由器作为Master路由器,承担网关的功能。其余两台路由器作为Backup路由器。

备份组相关概念

  • 虚拟IP

虚拟IP技术。虚拟IP,就是一个未分配给真实主机的IP,也就是说对外提供数据库服务器的主机除了有一个真实IP外还有一个虚IP,使用这两个IP中的任意一个都可以连接到这台主机

其实现原理主要是靠 TCP/IP 的 ARP 协议。因为IP地址只是一个逻辑地址,在以太网中 MAC 地址才是真正用来进行数据传输的物理地址,每台主机中都有一个 ARP 高速缓存,存储同一个网络内的 IP 地址与 MAC 地址的对应关系,以太网中的主机发送数据时会先从这个缓存中查询目标 IP 对应的 MAC 地址,会向这个 MAC 地址发送数据。操作系统会自动维护这个缓存。

  • 虚拟MAC地址:

一个虚拟路由器拥有一个虚拟MAC地址。虚拟MAC地址的格式为00-00-5E-00-01-{VRID}。通常情况下,虚拟路由器回应ARP请求使用的是虚拟MAC地址,只有虚拟路由器做特殊配置的时候,才回应接口的真实MAC地址。

  • 角色

    • Master: 对外提供服务的主服务器,只能有一个
    • Backup: 备选防范,当Master 出现问题之后会取代master提供服务,可以有多个。
  • 优先级

VRRP 根据优先级来确定备份组中每台路由器的角色(Master 路由器或 Backup 路由器)。优先级越高,则越有可能成为 Master 路由器。

VRRP 优先级的取值范围为 0 到 255(数值越大表明优先级越高),可配置的范围是 1 到 254,优 先级 0 为系统保留给特殊用途来使用,255 则是系统保留给 IP 地址拥有者。当路由器为 IP 地址拥 有者时,其优先级始终为 255。因此,当备份组内存在 IP 地址拥有者时,只要其工作正常,则为 Master 路由器。

  • 工作方式

    • 非抢占方式:如果备份组中的路由器工作在非抢占方式下,则只要 Master 路由器没有出现故 障,Backup 路由器即使随后被配置了更高的优先级也不会成为 Master 路由器。

    • 抢占方式:如果备份组中的路由器工作在抢占方式下,它一旦发现自己的优先级比当前的 Master 路由器的优先级高,就会对外发送 VRRP 通告报文。导致备份组内路由器重新选举 Master 路由器,并最终取代原有的 Master 路由器。相应地,原来的 Master 路由器将会变成 Backup 路由器。

  • 认证方式

    • simple:简单字符认证。发送 VRRP 报文的路由器将认证字填入到 VRRP 报文中,而收到 VRRP 报文的路由器会将收到的 VRRP 报文中的认证字和本地配置的认证字进行比较。如果 认证字相同,则认为接收到的报文是真实、合法的 VRRP 报文;否则认为接收到的报文是一 个非法报文。

    • md5:MD5 认证。发送 VRRP 报文的路由器利用认证字和 MD5 算法对 VRRP 报文进行摘要 运算,运算结果保存在Authentication Header(认证头)中。收到VRRP报文的路由器会利 用认证字和 MD5 算法进行同样的运算,并将运算结果与认证头的内容进行比较。如果相同, 则认为接收到的报文是真实、合法的 VRRP 报文;否则认为接收到的报文是一个非法报文。

  • 定时器

    • VRRP 通告报文间隔时间定时器和

    VRRP 备份组中的 Master 路由器会定时发送 VRRP 通告报文,通知备份组内的路由器自己工作正常。用户可以通过设置 VRRP 定时器来调整 Master 路由器发送 VRRP 通告报文的时间间隔。如果 Backup 路由器在等待了 3 个间隔时间后,依然没有收到 VRRP 通告报文,则认为自己是 Master 路由器,并对外发送 VRRP 通告报文,重新进行 Master 路由器的选举。

    • VRRP 抢占延迟时间定时器。

    为了避免备份组内的成员频繁进行主备状态转换,让 Backup 路由器有足够的时间搜集必要的信息 (如路由信息),Backup 路由器接收到优先级低于本地优先级的通告报文后,不会立即抢占成为 Master,而是等待一定时间——抢占延迟时间后,才会对外发送 VRRP 通告报文取代原来的 Master 路由器。

VRRP 工作方式

  • 选举MASTER:路由器使能 VRRP 功能后,会根据优先级确定自己在备份组中的角色。优先级高的路由器成 为 Master 路由器,优先级低的成为 Backup 路由器。Master 路由器定期发送 VRRP 通告报文, 通知备份组内的其他路由器自己工作正常;Backup 路由器则启动定时器等待通告报文的到来。

  • MASTER 通过ARP 协议对外通告该备份组的虚拟ip以及MAC地址

  • 在抢占方式下,当 Backup 路由器收到 VRRP 通告报文后,会将自己的优先级与通告报文中 的优先级进行比较。如果大于通告报文中的优先级,则成为 Master 路由器;否则将保持 Backup 状态。

  • 如果 Backup 路由器的定时器超时后仍未收到 Master 路由器发送来的 VRRP 通告报文,则认 为 Master 路由器已经无法正常工作,此时 Backup 路由器会认为自己是 Master 路由器,并对 外发送 VRRP 通告报文。备份组内的路由器根据优先级选举出 Master 路由器,承担报文的转 发功能。

  • Backup 通过ARP 协议对外通告该备份组的虚拟ip以及MAC地址

  • MASER 恢复之后,根据是否是抢占模式,逐步恢复对路由转发的功能。

Keepalived 配置详解

安装keepalived

1
yum install keepalived -y

配置文件详解

文件 说明
/usr/sbin/keepalived 二进制程序
/etc/keepalived/keepalived.conf 配置文件
/usr/lib/systemd/system/keepalived.service 服务文件

里面主要包括以下几个配置区域,分别是:

  • global_defs: 主要是配置故障发生时的通知对象以及机器标识。
  • static_ipaddress
  • static_routes
  • vrrp_script
  • vrrp_instance
  • virtual_server
  1. global_defs区域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 全局配置
global_defs {
# 邮件通知信息
notification_email {
# 定义收件人
acassen@firewall.loc
}
# 定义发件人
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1 # SMTP服务器地址
smtp_connect_timeout 30 # smtp_connect_timeout 连接smtp服务器的超时时间
# 路由器标识,一般不用改,也可以写成每个主机自己的主机名 router_id 标识本节点的字条串,通常为hostname,但不一定非得是hostname。故障发生时,邮件通知会用到
router_id LVS_DEVEL
# VRRP的ipv4和ipv6的广播地址,配置了VIP的网卡向这个地址广播来宣告自己的配置信息,下面是默认值
# vrrp_mcast_group4表示的ipv4协议下的组播地址,举个例子,因为集群中的心跳通信用单播每个服务器都要单独发送,用广播会给局域网内所有的服务器都发送信息,因此此处使用组播,向拥有同一组播地址的服务器发送心跳信息比较合适。
vrrp_mcast_group4 224.0.0.18
vrrp_mcast_group6 ff02::12
}
  1. static_ipaddress和static_routes区域[可忽略]

static_ipaddress和static_routes区域配置的是是本节点的IP和路由信息。如果你的机器上已经配置了IP和路由,那么这两个区域可以不用配置。其实,一般情况下你的机器都会有IP地址和路由信息的,因此没必要再在这两个区域配置。

1
2
3
4
5
6
7
8
static_ipaddress {
10.210.214.163/24 brd 10.210.214.255 dev eth0
...
}
static_routes {
10.0.0.0/8 via 10.210.214.1 dev eth0
...
}
  1. vrrp_script区域

用来做健康检查的,当时检查失败时会将vrrp_instance的priority减少相应的值。

1
2
3
4
5
6

vrrp_script chk_http_port {
script "</dev/tcp/127.0.0.1/80" #一句指令或者一个脚本文件,需返回0(成功)或非0(失败),keepalived以此为依据判断其监控的服务状态。
interval 1 #健康检查周期
weight -10 # 优先级变化幅度,如果script中的指令执行失败,那么相应的vrrp_instance的优先级会减少10个点。
}
  1. vrrp_instance和vrrp_sync_group区域

vrrp_instance用来定义对外提供服务的VIP区域及其相关属性。
vrrp_rsync_group用来定义vrrp_intance组,使得这个组内成员动作一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

vrrp_sync_group VG_1 { #监控多个网段的实例
group {
inside_network # name of vrrp_instance (below)
outside_network # One for each moveable IP.
...
}
notify_master /path/to_master.sh # notify_master表示切换为主机执行的脚本
notify_backup /path/to_backup.sh # notify_backup表示切换为备机师的脚本
notify_fault "/path/fault.sh VG_1" # notify_fault表示出错时执行的脚本
notify /path/notify.sh # notify表示任何一状态切换时都会调用该脚本,且在以上三个脚本执行完成之后进行调用
smtp_alert # smtp_alert 表示是否开启邮件通知(用全局区域的邮件设置来发通知)
}

# 一个vrrp_instance就是定义一个虚拟路由器的,实例名称为VI_1
vrrp_instance VI_1 {
state MASTER # state MASTER或BACKUP,当其他节点keepalived启动时会将priority比较大的节点选举为MASTER,因此该项其实没有实质用途。
interface eth0 # interface 节点固有IP(非VIP)的网卡,用来发VRRP包
use_vmac dont_track_primary # use_vmac 是否使用VRRP的虚拟MAC地址,dont_track_primary 忽略VRRP网卡错误(默认未设置)

# track_interface 监控以下网卡,如果任何一个不通就会切换到FALT状态。(可选项)
track_interface {
eth0
eth1
}
#mcast_src_ip 修改vrrp组播包的源地址,默认源地址为master的IP
mcast_src_ip lvs_sync_daemon_interface eth1 #lvs_sync_daemon_interface 绑定lvs syncd的网卡

garp_master_delay 10 # garp_master_delay 当切为主状态后多久更新ARP缓存,默认5秒

virtual_router_id 1 # virtual_router_id 取值在0-255之间,用来区分多个instance的VRRP组播, 同一网段中virtual_router_id的值不能重复,否则会出错

priority 100 #priority用来选举master的,根据服务是否可用,以weight的幅度来调整节点的priority,从而选取priority高的为master,该项取值范围是1-255(在此范围之外会被识别成默认值100)

advert_int 1 # advert_int 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)

authentication { # authentication 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)
auth_type PASS #认证方式
auth_pass 12345678 #认证密码
}

virtual_ipaddress { # 设置vip
# IP/掩码 dev 配置在哪个网卡
192.168.200.16/24 dev eth1
# IP/掩码 dev 配置在哪个网卡的哪个别名上
192.168.200.17/24 dev label eth1:1
}

# 虚拟路由,在需要的情况下可以设置lvs主机 数据包在哪个网卡进来从哪个网卡出去 即当IP漂过来之后需要添加的路由信息
virtual_routes {
172.16.0.0/12 via 10.210.214.1
192.168.1.0/24 via 192.168.1.1 dev eth1
default via 202.102.152.1
}

# 追踪脚本,通常用于去执行上面的vrrp_script定义的脚本内容
track_script {
chk_http_port
}

nopreempt # nopreempt 允许一个priority比较低的节点作为master,即使有priority更高的节点启动
preempt_delay 300 # preempt_delay master启动多久之后进行接管资源(VIP/Route信息等),并提是没有nopreempt选项
debug
notify_master| notify_backup| notify_fault| notify| smtp_alert

# 三个指令,如果主机状态变成Master|Backup|Fault之后会去执行的通知脚本,脚本要自己写
notify_master ""
notify_backup ""
notify_fault ""
}
  1. virtual_server_group和virtual_server区域
    定义LVS集群服务,可以是IP+PORT;也可以是fwmark 数字,也就是防火墙规则,所以通过这里就可以看出来keepalive天生就是为ipvs而设计的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
virtual_server IP Port {
delay_loop # delay_loop 延迟轮询时间(单位秒)
lb_algo rr|wrr|lc|wlc|lblc|sh|dh # lb_algo 后端调试算法(load balancing algorithm)
lb_kind NAT|DR|TUN # lb_kind LVS调度类型NAT/DR/TUN
persistence_timeout #会话保持时间
persistence_granularity #lvs会话保持粒度
protocol TCP #使用的协议
ha_suspend
virtualhost # virtualhost 用来给HTTP_GET和SSL_GET配置请求header的
alpha
omega
quorum
hysteresis
quorum_up|
quorum_down|

sorry_server #备用机,所有realserver失效后启用 如果后端应用服务器都不可用,就会定向到那个服务器上
# 后端应用服务器 IP PORT
real_server 192.168.200.2 1358 {
# 权重
weight 1
# MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET这些都是
# 针对应用服务器做健康检查的方法
MISC_CHECK {}
# 用于检查SMTP服务器的
SMTP_CHEKC {}

# 如果应用服务器不是WEB服务器,就用TCP_CHECK检查
TCP_CHECK {
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
connect_timeout 3
}

# 如果对方是HTTPS服务器就用SSL_GET方法去检查,里面配置的内容和HTTP_GET一样
SSL_GET {}

# 应用服务器UP或者DOWN,就执行那个脚本
notify_up "这里写的是路径,如果脚本后有参数,整体路径+参数引起来"
notify_down "/PATH/SCRIPTS.sh 参数"

# 使用HTTP_GET方法去检查
HTTP_GET {
# 检测URL
url {
# 具体检测哪一个URL
path /testurl/test.jsp
# 检测内容的哈希值
digest 640205b7b0fc66c1ea91c463fac6334d
# 除了检测哈希值还可以检测状态码,比如HTTP的200 表示正常,两种方法二选一即可
status_code 200
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
connect_timeout 3
# 尝试次数
nb_get_retry 3
# 每次尝试之间间隔几秒
delay_before_retry 3
}
}

实战

1
2
3
4
5
6
[root@lvs-node-0 ~]# man 5 keepalived.conf
[root@lvs-node-0 ~]# cd /etc/keepalived/
[root@lvs-node-0 keepalived]# ls
keepalived.conf
[root@lvs-node-0 keepalived]# cp keepalived.conf keepalived.conf.bak
[root@lvs-node-0 keepalived]#

配置VIP漂移配置

本次来配置 vip 漂移配置 网络拓扑如下:

  • keepalived.conf 配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# lvs-node-0 配置如下
global_defs {
notification_email {
root@localhost
}
notification_email_from roor@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

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.16.100.104/24 dev ens33 label ens33:1
}
}

# lvs-node-0-backup 配置如下

global_defs {
notification_email {
root@localhost
}
notification_email_from roor@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.16.100.104/24 dev ens33 label ens33:1
}
}
  • 启动keepalived
1
2
3
4
5
6
7
8
9
10
11
12
[root@lvs-node-0 keepalived]# systemctl restart  keepalived

[root@lvs-node-0 keepalived]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disabled)
Active: active (running) since 三 2021-05-12 11:38:41 CST; 16min ago
Process: 6306 ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 6307 (keepalived)
CGroup: /system.slice/keepalived.service
├─6307 /usr/sbin/keepalived -D
├─6308 /usr/sbin/keepalived -D
└─6309 /usr/sbin/keepalived -D
  • keepalived 进程

我们可以通过日志看到 keepalived 一共启动了三个进程,分别是

1
2
3
├─6307 /usr/sbin/keepalived -D
├─6308 /usr/sbin/keepalived -D
└─6309 /usr/sbin/keepalived -D

keepalived正常启动的时候,共启动3个进程:

  • 一个是父进程,负责监控其子进程;一个是VRRP子进程,另外一个是checkers子进程;

  • 两个子进程都被系统watchlog(为keepalived程序当中的模块)看管,两个子进程各自负责复杂自己的事。

  • Healthcheck(为keepalived程序当中的模块)子进程检查各自服务器的健康状况,,例如http,lvs。如果healthchecks进程检查到master上服务不可用了,就会通知本机上的VRRP子进程,让他删除通告,并且去掉虚拟IP,转换为BACKUP状态。

  • 查看配置
    我们来卡一下 lvs-node-0 的机器是否配置成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# lvs-node-0 的机器
[root@lvs-node-0 keepalived]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.100.100 netmask 255.255.255.0 broadcast 172.16.100.255
inet6 fe80::20c:29ff:fe15:e448 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:15:e4:48 txqueuelen 1000 (Ethernet)
RX packets 16648 bytes 11694770 (11.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10336 bytes 1105559 (1.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.100.104 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:0c:29:15:e4:48 txqueuelen 1000 (Ethernet)

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 56 bytes 5592 (5.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 56 bytes 5592 (5.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

# lvs-node-0-backup 的机器
[root@lvs-node-0-backup keepalived]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.100.103 netmask 255.255.255.0 broadcast 172.16.100.255
inet6 fe80::fe47:7422:c78:9b51 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:53:4c:39 txqueuelen 1000 (Ethernet)
RX packets 11694 bytes 11187317 (10.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5520 bytes 538341 (525.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

下面我们做一下验证,将lvs-node-0 ens33网卡down 掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@lvs-node-0 keepalived]# ifconfig ens33 down

# 根据现实 lvs-node-0-backup 已经有172.16.100.104 虚拟地址了
[root@lvs-node-0-backup keepalived]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.100.103 netmask 255.255.255.0 broadcast 172.16.100.255
inet6 fe80::fe47:7422:c78:9b51 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:53:4c:39 txqueuelen 1000 (Ethernet)
RX packets 48331 bytes 13390569 (12.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5572 bytes 544595 (531.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.100.104 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:0c:29:53:4c:39 txqueuelen 1000 (Ethernet)

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Keepalived 手动宕机脚本

keepalived 支持 vrrp_script 配置,用于可以手动关闭 keepalived,用户手动切换vrrp 具体配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
# ... 其他配置

vrrp_script chk_mt {
script "/etc/keepalived/down.sh"
interval 1
weight -20
}

vrrp_instance VI_1 {
# ... 其他配置
track_script {
chk_mt
}
# ... 其他配置
}

/etc/keepalived/down.sh 内容如下(注意增加chmod +x down.sh) 权限

1
2
3
4
#!/bin/bash
if [ -f /etc/keepalived/down ];then
weight -2
fi

上面的配置为,当我们 /etc/keepalived/down 文件存在的时候,会将改keepalived 监控的vip 转移到 backup 机器上,笔者已经试验过,没有问题。

配置虚拟vip 变更之后的通知

本次主要配置当vip切换之后,需要给我们发邮件通知
先来看通知脚本(/etc/keepalived/notify.sh)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
通知脚本:
#!/bin/bash
# 这里是我们的vip 地址
vip=172.16.100.104
contact='root@localhost'

notify() {
mailsubject="`hostname` to be $1: $vip floating"
mailbody="`date '+%F %H:%M:%S'`: vrrp transition, `hostname` changed to be $1"
echo $mailbody | mail -s "$mailsubject" $contact # 发送
}

case "$1" in
master)
notify master
exit 0
;;
backup)
notify backup
exit 0
;;
fault)
notify fault
exit 0
;;
*)
echo 'Usage: `basename $0` {master|backup|fault}'
exit 1
;;
esac

再来看一下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
# ... 其他配置

vrrp_script chk_mt {
script "/etc/keepalived/down.sh"
interval 1
weight -20
}

vrrp_instance VI_1 {
# ... 其他配置
track_script {
chk_mt
}
# ... 其他配置
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"

}

keepalived 配置 LVS DR 模型

关于LVS的细节,这里不再详细赘述,有兴趣的读者可以看负载均衡(3)LVS服务的搭建机及其高级应用

  • 拓扑结构:

  • 搭建过程:

在准备两台服务器,lvs-node-1(172.16.100.101), lvs-node-2(172.16.100.101)
在两台服务器上分别执行:

1
2
3
4
5
6
7
echo "1">/proc/sys/net/ipv4/conf/all/arp_ignore
echo "1">/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2">/proc/sys/net/ipv4/conf/all/arp_announce
echo "2">/proc/sys/net/ipv4/conf/lo/arp_announce

ifconfig lo:0 172.16.100.104/32 broadcast 172.16.100.104 up
route add -host 172.16.100.104 dev lo:0

在 lvs-node-0 和lvs-node-0-backup 编辑keepalived配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# ... 其他配置

vrrp_instance VI_1 {
# ... 其他配置
}

virtual_server 172.16.100.104 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
nat_mask 255.255.244.0
protocol TCP
# sorry_server 127.0.0.1 80 这了不配置sorry 服务器,有需要的读者自己配置

real_server 172.16.100.101 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
real_server 172.16.100.102 80 {
weight 2
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}

在lvs-ndoe-0 上执行安装lvs 命令

1
2
3
ipvsadm -A -t 172.16.100.104:80 -s rr
ipvsadm -a -t 172.16.100.104:80 -r 172.16.100.101:80 -g
ipvsadm -a -t 172.16.100.104:80 -r 172.16.100.102:80 -g

在一台机器上执行是否生效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  ~ curl http://172.16.100.104
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Welcome to nginx in lvs-node-2</h1>
</body>
</html>

➜ ~ curl http://172.16.100.104
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Welcome to nginx in lvs-node-1</h1>
</body>
</html>

查看心跳信息:

1
2
3
[root@lvs-node-2 ~]# tailf /var/log/nginx/access.log
172.16.100.100 - - [13/May/2021:15:04:02 +0800] "GET / HTTP/1.0" 200 101 "-" "KeepAliveClient" "-"
172.16.100.103 - - [13/May/2021:15:04:05 +0800] "GET / HTTP/1.0" 200 101 "-"

停掉一台lvs-node-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

[root@lvs-node-2 ~]# systemctl stop nginx.service
[root@lvs-node-2 ~]#

# 查看 lvs-node-0 的lvs 配置 看到已经将102排除在外
[root@lvs-node-0 keepalived]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.16.100.104:80 wrr
-> 172.16.100.101:80 Route 1 0 0

# 恢复 lvs-ndoe-2 的ngixn

[root@lvs-node-2 ~]# systemctl start nginx.service

# 查看 lvs-node-0 的lvs 配置 看到已经将102 已经加回来了

[root@lvs-node-0 keepalived]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.16.100.104:80 wrr
-> 172.16.100.101:80 Route 1 0 0
-> 172.16.100.102:80 Route 2 0 0
[root@lvs-node-0 keepalived]#

keepalived 双主模型搭建

以上的环境是基于主备模型,当master 节点工作正常的状态下,BACKUP是不对外提供服务的,这就意味着我们使用有一个节点处于备份状态,无法对外提供服务。这就会导致一部分的性能浪费,为了解决这个问题,提出了双主模型,也就是说 我们提供两个VIP 并且使用 DNS轮询的方式,使得两个keepalived 都在工作,互为准备,当一台机器失败之后,其中的vip 会转移到另外一个节点上去,该节点拥有两个vip 地址。

上面我们已经演示过如果搭建 LVS, 本次演示keepalived Track的功能,也就是监视功能。

  • VRRP 监视功能

keepalived 通过track 脚本实现对服务的监控, 根据服务的状态,改变路由器的优先级。当服务出现故障,被监视 Track 项的状态为 Negative,并将路由器的优先级降低指 定的数额。从而,使得备份组内其它路由器的优先级高于这个路由器的优先级,成为 Master 路由器,保证局域网内主机与外部网络的通信不会中断。

  • 在 Backup 路由器上监视 Master 路由器的状态。当 Master 路由器出现故障时,工作在切换模 式的 Backup 路由器能够迅速成为 Master 路由器,以保证通信不会中断。

  • lvs-node-0 keepalived 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
##配置nginx检查脚本
vrrp_script chk_nginx {
script "/etc/keepalived/chk_nginx.sh"
interval 1
weight -20
}

vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
chk_nginx
}
virtual_ipaddress {
172.16.100.104/24 dev ens33 label ens33:1
}
}


vrrp_instance VI_2 {
state BACKUP
interface ens33
virtual_router_id 52
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 2222
}
track_script {
chk_nginx
}
virtual_ipaddress {
172.16.100.105/24 dev ens33 label ens33:2
}
}
  • lvs-node-0-backup keepalived 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
##配置nginx检查脚本
vrrp_script chk_nginx {
script "/etc/keepalived/chk_nginx.sh"
interval 1
weight -20
}

vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
chk_nginx
}
virtual_ipaddress {
172.16.100.104/24 dev ens33 label ens33:1
}
}


vrrp_instance VI_2 {
state MASTER
interface ens33
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 2222
}
track_script {
chk_nginx
}
virtual_ipaddress {
172.16.100.105/24 dev ens33 label ens33:2
}
}
  • /etc/keepalived/chk_nginx.sh 脚本
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
run=`ps -C nginx --no-header | wc -l`
if [ $run -eq 0 ]
then
echo "stop nginx ....."
systemctl stop nginx
echo "start nginx ..."
systemctl start nginx
ps -C nginx --no-header
sleep 3
fi
  • 在lvs-node-0 和lvs-node-0-backup 上安装 nginx 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# vim /etc/nginx/conf.d/default.conf
# 负载到 lvs-node-1 和 lvs-node-2 的机器上
upstream monitor_server {
server 172.16.100.102:80;
server 172.16.100.101:80;
}

server {
listen 80;
server_name localhost;
access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://monitor_server;
}
}


支付宝打赏 微信打赏

赞赏一下