[TOC]

利用Keepalive+Nginx搭建与阿里云SLB一样高效的高可用应用架构

安装keepalive请查看另一篇文章

安装nginx 略

高可用集群规划

集群环境介绍

  • 操作系统环境: CentOS Linux release 7.9.2009
  • Nginx 版本: nginx/1.20.1
  • 高可用版本:keepalived-2.2.2
  • root 系统管理员用户登录安装部署

集群规划与配置

节点名称 节点 IP Addr 主机名 Nginx端口 默认主从 配置
VIP 192.168.233.100
MASTER 192.168.233.129 master 80 MASTER 2核2G20GB
BACKUP 192.168.233.130 backup 80 BACKUP 2核2G20GB

编写脚本

编写 nginx 服务存活检测脚本

1
vim /usr/bin/check_nginx_alive.sh

不重启脚本

1
2
3
4
5
6
7
8
9
10
#!/bin/sh

PATH=/bin:/sbin:/usr/bin:/usr/sbin

A=$(ps -C nginx --no-header | wc -l)

if [ "$A" -eq 0 ]; then
echo 'nginx server is died'
killall keepalived
fi

重启一次脚本:一般keepalived 不会挂,所以重启nginx 一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
A=$(ps -C nginx --no-header |wc -l)
if [ "$A" -eq 0 ]
then
### 这种方式启动nginx,使用 systemctl status nginx 查看状态非 active
#/usr/local/nginx/sbin/nginx
systemctl start nginx
sleep 2
A2=$(ps -C nginx --no-header |wc -l)
if [ "$A2" -eq 0 ]
then
#systemctl stop keepalived
killall keepalived
fi
fi
1
2
chmod +x /usr/bin/check_nginx_alive.sh

监测脚本解析

1
ps -C nginx --no-header

这里涉及ps 的用法,我们一般用ps查看相关进程,一般都是用
ps -ef | grep XX 或 ps -aux| grep XX 的模式
如下:

1
2
3
4
5
$ ps -ef | grep nginx
root 2248 1 0 19:13 ? 00:00:00 nginx: master process ./nginx
nobody 3265 2248 0 20:16 ? 00:00:00 nginx: worker process
root 4791 4742 0 22:05 pts/1 00:00:00 grep --color=auto nginx

但是这样通常都会覆盖一个grep的进程
我们可以用ps -C 或ps -c 的方式, -C 后面接命令的名字 ,如下:

1
2
3
4
5
# ps -C nginx
PID TTY TIME CMD
4983 ? 00:00:00 nginx
4984 ? 00:00:00 nginx

–no-header 就是去掉title

wc -l 行数计算

如果值为0,即代表服务未启动
如果值为非0,即代表服务已启动

安装killall命令

为验证高可用,因centos安装的是minimal 版本,默认没有该命令,需要安装一下

1
yum install -y psmisc

防止脑裂

关闭SELinux

  1. 查看 SELinux

    MASTER主

    1
    2
    3
    4
    5
    6
    7
    # getenforce
    Permissive ### 允许的
    # /usr/sbin/sestatus -v
    SELinux status: enabled
    SELinuxfs mount: /sys/fs/selinux
    SELinux root directory: /etc/selinux

    BACKUP从

    1
    2
    3
    4
    5
    6
    # getenforce
    Enforcing ### 强制执行
    # /usr/sbin/sestatus -v
    SELinux status: enabled
    SELinuxfs mount: /sys/fs/selinux
    SELinux root directory: /etc/selinux
  2. 临时关闭

    1
    2
    3
    ##设置SELinux 成为permissive模式
    ##setenforce 1 设置SELinux 成为enforcing模式
    # setenforce 0

    setenforce 0 #设置为宽容模式

    但这样只在本次生效,重启服务器后将失效。

  3. 永久关闭

    如果要永久关闭,还需要修改配置文件:

    1
    2
    3
    4
    5
    # vim /etc/selinux/config
    ### 将
    SELINUX=enforcing
    ### 改为
    SELINUX=disabled

    设置后需要重启才能生效

iptables防火墙配置

centos 防火墙有两种管理方式firewall, iptables两者不能同时开启

防火墙开启的情况下,我们需要加入一条配置:

iptables

编辑vim /etc/sysconfig/iptables

1
-A INPUT -p vrrp -j ACCEPT

注意:

添加规则一定不要在 -A INPUT -j REJECT --reject-with icmp-host-prohibited 之后,一定要加在其前面。

配置完之后 reload

1
service iptables reload

Firewalld 防火墙配置

问题就是出现在了防火墙这里,防火墙阻止了vrrp组包发送

如果是Firewalld防火墙 则主、备都运行下面的命令

centos7 默认防火墙firewall

开启vrrp 协议

主备都运行下面的命令

1
2
3
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --protocol vrrp -j ACCEPT

firewall-cmd --reload

重新启动服务

1
2
3
4
5
# systemctl restart keepalived

# journalctl -xe
# 查看进程情况
ps -aux |grep keepalived

配置 keepalive

1
2
# 非抢占模式,这种模式主要是针对主机崩溃,集群已经重新选出新的主机,并且原来的主机重新上线后并不争夺主机的情况。这种模式适合那些倾向于认为崩溃的主机即便上线还是会出现崩溃的场景。
这种模式的核心思想是将所有节点的优先级(priority)值设为相同,当两个节点的优先级相同时,以节点发送VRRP通告的IP作为比较对象,IP较大者为MASTER。
1
vim /etc/keepalived/keepalived.conf

master配置

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
! Configuration File for keepalived

# version keepalived-2.2.2

# 全局配置
global_defs {
# 定义报警邮件地址
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# 定义发送邮件的地址
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
# 定义路由标识信息,相同局域网唯一
router_id LVS_DEVEL
# 检查vrrp报文中的所有地址比较耗时,设置此标志的意思是如果接收的到报文和上一个报文来至同一个路由器,则不执行检查。默认是跳过检查
vrrp_skip_check_adv_addr
# 严格遵守vrrp协议,下面这些功能将会禁止:1. 0 VIP 2. unicast(单播) peers 3. vrrp 版本2的ipv6功能
vrrp_strict
# 小数类型,单位秒,在一个网卡上每组gratuitous arp消息之间的延迟时间,默认为0,一个发送的消息=n组 arp报文
vrrp_garp_interval 0
# 小数类型,单位秒, 在一个网卡上每组na消息之间的延迟时间,默认为0
vrrp_gna_interval 0
}

vrrp_script check_nginx_alive {
# 检查nginx的脚本
script "/usr/bin/check_nginx_alive.sh"
# 检查时间间隔,这个时间不要超过脚本的执行时间,否则会报“Track script chk_nginx is being timed out, expect idle - skipping run”
interval 3
# 脚本执行失败则优先级减10
weight -10
# 表示两次失败才算失败
fall 2
}

# 定义实例
vrrp_instance VI_1 {
# 主机配置,从机为BACKUP
state MASTER
# 网卡名称
interface ens33
# 指定VRRP实例ID,范围是0-255.同一个组要一致
virtual_router_id 51
## 权重值,值越大,优先级越高,backup设置比master小,这样就能在master宕机后讲backup变为master,而master回复后就可以恢复.
priority 100
# 指定发送VRRP通告的间隔。单位是秒。
advert_int 1
# 指定认证方式。PASS简单密码认证(推荐),AH:IPSEC认证(不推荐)。密码" 最多8位
authentication {
auth_type PASS
auth_pass 1111
}
# 设备之间使用的虚拟ip地址
virtual_ipaddress {
192.168.233.100
}
# 执行脚本
track_script {
check_nginx_alive
}
}

# 虚拟 vip
virtual_server 192.168.233.100 80 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP

# 真实服务器
real_server 192.168.233.129 80 {
weight 1
TCP_CHECK{
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

BACKUP配置

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
! Configuration File for keepalived

# version keepalived-2.2.2

# 全局配置
global_defs {
# 定义报警邮件地址
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# 定义发送邮件的地址
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
# 定义路由标识信息,相同局域网唯一
router_id LVS_DEVEL
# 检查vrrp报文中的所有地址比较耗时,设置此标志的意思是如果接收的到报文和上一个报文来至同一个路由器,则不执行检查。默认是跳过检查
vrrp_skip_check_adv_addr
# 严格遵守vrrp协议,下面这些功能将会禁止:1. 0 VIP 2. unicast(单播) peers 3. vrrp 版本2的ipv6功能
vrrp_strict
# 小数类型,单位秒,在一个网卡上每组gratuitous arp消息之间的延迟时间,默认为0,一个发送的消息=n组 arp报文
vrrp_garp_interval 0
# 小数类型,单位秒, 在一个网卡上每组na消息之间的延迟时间,默认为0
vrrp_gna_interval 0
}

vrrp_script check_nginx_alive {
# 检查nginx的脚本
script "/usr/bin/check_nginx_alive.sh"
# 检查时间间隔,这个时间不要超过脚本的执行时间,否则会报“Track script chk_nginx is being timed out, expect idle - skipping run”
interval 3
# 脚本执行失败则优先级减10
weight -10
# 表示两次失败才算失败
fall 2
}

# 定义实例
vrrp_instance VI_1 {
# 主机配置,从机为BACKUP
state MASTER
# 网卡名称
interface ens33
# 指定VRRP实例ID,范围是0-255.同一个组要一致
virtual_router_id 51
## 权重值,值越大,优先级越高,backup设置比master小,这样就能在master宕机后讲backup变为master,而master回复后就可以恢复.
priority 90
# 指定发送VRRP通告的间隔。单位是秒。
advert_int 1
# 指定认证方式。PASS简单密码认证(推荐),AH:IPSEC认证(不推荐)。密码" 最多8位
authentication {
auth_type PASS
auth_pass 1111
}
# 设备之间使用的虚拟ip地址
virtual_ipaddress {
192.168.233.100
}
# 执行脚本
track_script {
check_nginx_alive
}
}

# 虚拟 vip
virtual_server 192.168.233.100 80 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP

# 真实服务器
real_server 192.168.233.130 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

重启 keepalive 生效

1
systemctl restart keepalived

注意

新版本

1
ip a 

查看网卡,只会存在 主master 可以看到 虚拟vip

测试

初始化

启动

启动两台机器的nginx 和keepalived

这里129 为master,130 为backup

image-20210901164430138

image-20210901164446850

虚拟vip正确显示master 机器

image-20210901164516002

master 当前状态

master 当前状态

backup 当前状态

BACKUP当前状态

使用不重启脚本

模拟master 宕机

停止master nginx

1
systemctl stop nginx

image-20210901165255246

image-20210901165325387

模拟master 存活

重启master

1
2
3
systemctl restart nginx

systemctl restart keepalived

可以看见虚拟vip 自动切换为129

使用重试1次脚本

image-20210902100322114

模拟master 宕机

制造配置文件错误

image-20210902100605827

image-20210902102102375

可见成功漂移 backup

模拟master 存活

image-20210902102238847

image-20210902102302342

成功成功漂移到master

更多请查看keepalived官网http://www.keepalived.org