环境介绍
角色 |
操作系统 |
IP |
VIP |
主要软件 |
keepalived主节点 |
RockyLinux9.3 |
172.31.31.132 |
172.31.31.231 |
keepalived 2.2.8-3 |
keepalived从节点 |
RockyLinux9.3 |
172.31.31.133 |
172.31.31.231 |
keepalived 2.2.8-3 |
real server1 |
RockyLinux9.3 |
172.31.31.134 |
- |
nginx 1.20.1 |
real server2 |
RockyLinux9.3 |
172.31.31.135 |
- |
nginx 1.20.1 |
keepalived + lvs
安装程序
1
|
dnf install -y keepalived ipvsadm
|
外部配置
启用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
|
$ cat > /etc/modules-load.d/ipvs.conf <<EOF
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF
$ systemctl restart systemd-modules-load.service
$ lsmod | grep ip_vs
# ip_vs_sh 16384 0
# ip_vs_wrr 16384 0
# ip_vs_rr 16384 0
# ip_vs 188416 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
# nf_conntrack 176128 3 nf_nat,nft_ct,ip_vs
# nf_defrag_ipv6 24576 2 nf_conntrack,ip_vs
# libcrc32c 16384 5 nf_conntrack,nf_nat,nf_tables,xfs,ip_vs$ lsmod | grep nf_conntrack
|
程序配置
配置详情
这是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
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
! Configuration File for keepalived
global_defs {
# 邮件通知信息
notification_email {
# 定义收件人
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# 定义发件人
notification_email_from Alexandre.Cassen@firewall.loc
# SMTP服务器地址
smtp_server 192.168.200.1
# SMTP连接超时时间
smtp_connect_timeout 30
# 本节点的Router ID
router_id LVS_DEVEL
# 跳过VRRP广播地址检查
vrrp_skip_check_adv_addr
# 严格遵守VRRP协议
vrr_strict
# VRRP广播周期间隔
vrrp_garp_interval 0
# VRRP邻居广播周期间隔
vrrp_gna_interval 0
}
# VRRP实例配置
vrrp_instance VI_1 {
# 定义初始状态,可以是MASTER或者BACKUP
state MASTER
# 绑定接口
interface eth0
# 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个,而且这个虚拟
# ID还是虚拟MAC最后一段地址的信息,取值范围0-255
virtual_router_id 51
# 优先级,如果是Master,这里的优先级就需要定义的比其他的高
priority 100
# 通告频率,单位为秒
advert_int 1
# 认证配置
authentication {
# 认证方式
auth_type PASS
# 认证密码
auth_pass 1111
}
# 虚拟IP地址
virtual_ipaddress {
192.168.200.16
192.168.200.17
192.168.200.18
}
}
# 虚拟服务器 1
virtual_server 192.168.200.100 443 {
# 检测间隔
delay_loop 6
# 负载均衡算法 可用值为:rr|wrr|lc|wlc|lblc|sh|dh
lb_algo rr
# LB的模式,NAT|DR|TUN
lb_kind NAT
# 持久连接时间
persistence_timeout 50
# 协议 TCP|UDP
protocol TCP
# 真实服务器1
real_server 192.168.201.100 443 {
# 权重
weight 1
# 健康检查,MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET这些都是针对应用服务器做健康检查的方法
SSL_GET {
url {
# 检查路径
path /
# 响应内容md5
digest ff20ad2481f97b1754ef3e12ecd3a9cc
}
url {
path /mrtg/
digest 9b3a0c85a887a256d6939da88aabd8cd
}
# 连接超时时间
connect_timeout 3
# 重试次数
retry 3
# 重试间隔
delay_before_retry 3
}
}
}
# 虚拟服务器 2
virtual_server 10.10.10.2 1358 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
# 备用服务器
sorry_server 192.168.200.200 1358
# 真实服务器1
real_server 192.168.200.2 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
# 真实服务器2
real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
|
我的配置
主节点配置:
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
|
# Master
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict #我的机器启用了ipv6这个项不能开启
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1314
}
virtual_ipaddress {
172.31.31.231
}
}
virtual_server 172.31.31.231 80 {
delay_loop 1
lb_algo rr
lb_kind DR
# persistence_timeout 1
protocol TCP
sorry_server 172.15.110.34 9010
real_server 172.31.31.134 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
real_server 172.31.31.135 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
|
从节点配置:
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
|
# backup
! 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_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1314
}
virtual_ipaddress {
172.31.31.231
}
}
virtual_server 172.31.31.231 80 {
delay_loop 1
lb_algo rr
lb_kind DR
# persistence_timeout 1
protocol TCP
sorry_server 172.15.110.34 9010
real_server 172.31.31.134 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
real_server 172.31.31.135 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
|
验证
环境配置验证
主节点验证VIP分配与否
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ ip addr
#1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
# link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# inet 127.0.0.1/8 scope host lo
# valid_lft forever preferred_lft forever
# inet6 ::1/128 scope host
# valid_lft forever preferred_lft forever
#2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
# link/ether 00:0c:29:05:70:4f brd ff:ff:ff:ff:ff:ff
# altname enp3s0
# inet 172.31.31.132/24 brd 172.31.31.255 scope global dynamic noprefixroute ens160
# valid_lft 859924sec preferred_lft 859924sec
# inet 172.31.31.231/32 scope global ens160
# valid_lft forever preferred_lft forever
# inet6 fe80::20c:29ff:fe05:704f/64 scope link noprefixroute
# valid_lft forever preferred_lft forever
#3: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
# link/ipip 0.0.0.0 brd 0.0.0.0
|
检查路由规则
1
2
3
4
|
$ ip route
#default via 172.31.31.2 dev ens160 proto dhcp src 172.31.31.132 metric 100
#127.0.0.0/8 dev lo proto kernel scope link src 127.0.0.1 metric 30
#172.31.31.0/24 dev ens160 proto kernel scope link src 172.31.31.132 metric 100
|
检查ipvs规则
1
2
3
4
5
6
7
|
$ ipvsadm -ln
#IP Virtual Server version 1.2.1 (size=4096)
#Prot LocalAddress:Port Scheduler Flags
# -> RemoteAddress:Port Forward Weight ActiveConn InActConn
#TCP 172.31.31.231:80 rr
# -> 172.31.31.134:80 Route 1 0 0
# -> 172.31.31.135:80 Route 1 0 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
|
Dec 25 16:24:35 localhost.localdomain systemd[1]: Starting LVS and VRRP High Availability Monitor...
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Starting Keepalived v2.2.8 (04/04,2023), git commit v2.2.7-154-g292b299e+
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Running on Linux 5.14.0-362.8.1.el9_3.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Nov 8 17:36:32 UTC 2023 (built for Linux 5.14.0)
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Command line: '/usr/sbin/keepalived' '--dont-fork' '-D'
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Opening file '/etc/keepalived/keepalived.conf'.
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Configuration file /etc/keepalived/keepalived.conf
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: (Line 7) WARNING - number '0' outside range [0.000001, 4294.967295]
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: (Line 7) vrrp_garp_interval '0' is invalid
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: (Line 8) WARNING - number '0' outside range [0.000001, 4294.967295]
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: (Line 8) vrrp_gna_interval '0' is invalid
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: NOTICE: setting config option max_auto_priority should result in better keepalived performance
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Starting Healthcheck child process, pid=14876
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Starting VRRP child process, pid=14877
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: Registering Kernel netlink reflector
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: Registering Kernel netlink command channel
Dec 25 16:24:35 localhost.localdomain Keepalived_healthcheckers[14876]: WARNING - virtual server [172.31.31.231]:tcp:80 and sorry server ports don't match - resetting
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: Assigned address 172.31.31.133 for interface ens160
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: Assigned address fe80::20c:29ff:fe2e:5b54 for interface ens160
Dec 25 16:24:35 localhost.localdomain Keepalived_healthcheckers[14876]: Initializing ipvs
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: Registering gratuitous ARP shared channel
Dec 25 16:24:35 localhost.localdomain Keepalived_healthcheckers[14876]: Gained quorum 1+0=1 <= 11 for VS [172.31.31.231]:tcp:80
Dec 25 16:24:35 localhost.localdomain Keepalived_healthcheckers[14876]: Activating healthchecker for service [172.31.31.134]:tcp:80 for VS [172.31.31.231]:tcp:80
Dec 25 16:24:35 localhost.localdomain Keepalived_healthcheckers[14876]: Activating healthchecker for service [172.31.31.135]:tcp:80 for VS [172.31.31.231]:tcp:80
Dec 25 16:24:35 localhost.localdomain Keepalived[14875]: Startup complete
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) removing VIPs.
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Entering BACKUP STATE (init)
Dec 25 16:24:35 localhost.localdomain systemd[1]: Started LVS and VRRP High Availability Monitor.
Dec 25 16:24:35 localhost.localdomain Keepalived_vrrp[14877]: VRRP sockpool: [ifindex( 2), family(IPv4), proto(112), fd(12,13) multicast, address(224.0.0.18)]
Dec 25 16:24:36 localhost.localdomain Keepalived_healthcheckers[14876]: Remote Web server [172.31.31.134]:tcp:80 succeed on service.
Dec 25 16:24:36 localhost.localdomain Keepalived_healthcheckers[14876]: Remote Web server [172.31.31.135]:tcp:80 succeed on service.
Dec 25 16:24:50 localhost.localdomain systemd[1]: systemd-hostnamed.service: Deactivated successfully.
|
停止主节点,从节点升级成主节点,并获得VIP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Dec 25 16:26:05 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Backup received priority 0 advertisement
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Receive advertisement timeout
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Entering MASTER STATE
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) setting VIPs.
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Sending/queueing gratuitous ARPs on ens160 for 172.31.31.231
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:06 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Sending/queueing gratuitous ARPs on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
Dec 25 16:26:11 localhost.localdomain Keepalived_vrrp[14877]: Sending gratuitous ARP on ens160 for 172.31.31.231
|
启动主节点,从节点移除VIP
1
2
3
|
Dec 25 16:26:38 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Master received advert from 172.31.31.132 with higher priority 100, ours 99
Dec 25 16:26:38 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) Entering BACKUP STATE
Dec 25 16:26:38 localhost.localdomain Keepalived_vrrp[14877]: (VI_1) removing VIPs.
|
RealServer服务器
realserver 服务器需要修改 ARP 参数并在lo接口上添加 VIP,主要原因有:
-
arp_ignore 和 arp_announce:这些设置可以防止 realserver 对 VIP 地址的 ARP 请求做出响应。这样可以避免 realserver 与 keepalived VIP 之间的 ARP 冲突。
-
在loopback添加VIP: realserver需要配置VIP,以便它可以接受发往该IP的数据包。在loopback上添加可以避免与主网卡的冲突。
-
通过loopback路由: 这可以确保 VIP 连接的返回流量通过loopback上的VIP返回,而不是主网卡。
也可以用这个脚本:
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
|
#!/bin/bash
vip=$1
dev=lo
case $2 in
start)
sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.lo.arp_ignore=1
sysctl -w net.ipv4.conf.all.arp_announce=2
sysctl -w net.ipv4.conf.lo.arp_announce=2
ip addr add $vip/32 dev $dev brd $vip
ip route add $vip dev lo
nmcli d connect lo
echo "The Real Server is Ready!"
;;
stop)
sysctl -w net.ipv4.conf.all.arp_ignore=0
sysctl -w net.ipv4.conf.lo.arp_ignore=0
sysctl -w net.ipv4.conf.all.arp_announce=0
sysctl -w net.ipv4.conf.lo.arp_announce=0
ip add del $vip/32 dev $dev
ip route del $vip dev lo
nmcli d disconnect lo
echo "The Real Server is Stopped!"
;;
*)
echo "Usage: "
echo " start with: $(basename $0) [your_vip_address] start "
echo " stop with: $(basename $0) [your_vip_address] stop"
exit 1
;;
esac
|
每个后端服务器执行这个脚本,比如这个脚本叫setRS.sh
,VIP是172.31.31.231
1
|
$ ./setRS.sh 172.31.31.231 start
|
验证
环境配置验证
验证内核参数已经正确修改
1
2
3
4
5
|
$ sysctl -a | grep arp_ | grep -v 0
#net.ipv4.conf.all.arp_announce = 2
#net.ipv4.conf.all.arp_ignore = 1
#net.ipv4.conf.lo.arp_announce = 2
#net.ipv4.conf.lo.arp_ignore = 1
|
验证lo已经设置为connected
1
2
3
4
|
$ nmcli d
#DEVICE TYPE STATE CONNECTION
#ens160 ethernet connected ens160
#lo loopback connected lo
|
ip已经添加到lo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
$ ip addr
#1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
# link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# inet 127.0.0.1/8 scope host lo
# valid_lft forever preferred_lft forever
# inet 172.31.31.231/32 scope global lo
# valid_lft forever preferred_lft forever
# inet6 ::1/128 scope host
# valid_lft forever preferred_lft forever
#2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
# link/ether 00:0c:29:e1:ec:80 brd ff:ff:ff:ff:ff:ff
# altname enp3s0
# inet 172.31.31.134/24 brd 172.31.31.255 scope global dynamic noprefixroute ens160
# valid_lft 859628sec preferred_lft 859628sec
# inet6 fe80::20c:29ff:fee1:ec80/64 scope link noprefixroute
# valid_lft forever preferred_lft forever
|
功能验证
停止/启动一个realserver,keepalived日志(可以正确上线和下线realserver):
1
2
3
4
5
6
|
Dec 25 16:21:58 localhost.localdomain Keepalived_healthcheckers[8088]: HTTP_CHECK on service [172.31.31.135]:tcp:80 failed after 3 retries.
Dec 25 16:21:58 localhost.localdomain Keepalived_healthcheckers[8088]: Removing service [172.31.31.135]:tcp:80 from VS [172.31.31.231]:tcp:80
Dec 25 16:22:34 localhost.localdomain Keepalived_healthcheckers[8088]: HTTP status code success to [172.31.31.135]:tcp:80 url(/index.html)
Dec 25 16:22:35 localhost.localdomain Keepalived_healthcheckers[8088]: HTTP status code success to [172.31.31.135]:tcp:80 url(/index.html)
Dec 25 16:22:35 localhost.localdomain Keepalived_healthcheckers[8088]: Remote Web server [172.31.31.135]:tcp:80 succeed on service.
Dec 25 16:22:35 localhost.localdomain Keepalived_healthcheckers[8088]: Adding service [172.31.31.135]:tcp:80 to VS [172.31.31.231]:tcp:80
|