Keepalived 是什么?
-
Keepalived
起初是为LVS
(Linux虚拟服务器)设计的用来检测集群系统中各个服务节点的状态, 根据TCP/IP的第345层的交换机制检测每个服务的状态; 如果其中某个服务节点出现异常或者工作出现故障, 会将该节点从系统集群中剔除, 这个过程是自动完成的, 无须人工干预, 人工仅需要修复出现故障的服务节点; -
Keepalived
支持VRRP
(虚拟路由冗余协议), 主要是为了解决静态路由出现单点故障, 通过VRRP实现不间断持续可用性, 确保服务稳定运行; 因此Keepalived既拥有服务器状态检测和隔离功能又拥有HA cluster
(高可用集群)功能. -
Keepalived
可以用来检测节点部署的WEB
,数据库
等服务, 除了实现服务器自身故障自动转移同时还可以检测在节点部署的服务是否正常运行, 防止因当前节点负载过高导致相关服务进程被Kill
掉或服务意外崩溃导致服务暂停. 实现针对单一或多个应用程序的高可用.
工作原理
Keepalived
根据设置的权重进行选举出一台Master服务器, 并分配一个指定的虚拟IP来进行通信, 如果Master服务器出现断网, 重启, 关机, 本机的Keepalived crash或者其他崩溃的情况时, Backup服务器们检测到Master服务器通信不正常, 因此判定Master服务器故障, 然后Backup服务器们通过设置的权重重选出新的Master服务器并指定一样的虚拟IP充当Master服务器将服务恢复正常.
选举策略
Keepalived
是根据 VRRP
协议完全通过权重大小进行选举Master服务器, 权重最大0~255的会被选举为Master服务器, 下面几种情况会产生选举:
- Keepalived启动的时候.
- Master服务器断网, 重启, 关机, 本机的Keepalived crash或者其他崩溃的情况时.
- 有新的备份服务器加入且权重最大的时候.
搭建Keepalived环境
配置文件简介
Keepalived
官方使用说明英文原版PDF地址
keepalived
只有一个配置文件keepalived.conf
, 里面主要包括以下几个配置区域,
分别是global_defs
,static_ipaddress
,static_routes
,vrrp_script
,vrrp_instance
和virtual_server
-
global_defs
主要是配置故障发生时的通知对象以及机器标识notification_email
故障发生时给发送警告邮件, 可以设置多个, 每个一行notification_email_from
通知邮件的发件人smtp_server
通知邮件的smtp
发件服务器地址smtp_connect_timeout
连接发件服务器的超时时间, 单位秒enable_traps
开启SNMP
陷阱router_id
标识当前节点的字符串, 通常为主机名, 但不一定必须. 故障发生时, 邮件通知会用到该字符串lvs_sync_daemon
绑定lvs syncd的网卡enable_script_security
开启安全脚本执行script_user
设置执行脚本的 Linux 用户
global_defs { notification_email { admin@localhost.localdomain devops@localhost.localdomain } notification_email_from monitor@localhost.localdomain smtp_server localhost.localdomain smtp_connect_timeout 30 router_id BaseServer_1 vrrp_mcast_group4 lvs_sync_daemon enp0s3 BASE_1 enable_script_security script_user }
global_defs
设置的邮件信息不适合用于实际使用,所以一般需要自行编写脚本来发送邮件.
script_user
此项如不存在即不设置安全用户, 则必须保证keepalived_script
用户存在 -
static_ipaddress
和static_routes
分别表示当前节点的IP和路由信息.通常情况下服务器已经配置IP和路由, 这两个节点可以不用配置
static_ipaddress { 192.168.123.5/24 brd 192.168.123.255 dev eth0 scope global # 192.168.123.5/24 表示静态IP: 192.168.123.5 和子网掩码: 255.255.255.0 # dev eth0 表示网卡设备名称 # scope global 全局作用域有效 } static_routes { 192.168.123.0/24 via 192.168.123.1 dev eth0 # 设置外部路由, 192.168.123.1 - 192.168.123.254 都是从 192.168.123.1 出去 }
这相当于Keepalived在启动时执行:
/sbin/ip addr add 192.168.123.5/24 brd 192.168.123.255 dev eth0 scope global /sbin/ip route add 192.168.123.0/24 via 192.168.123.1 dev eth0
在停止时执行:
/sbin/ip addr del 192.168.123.5/24 brd 192.168.123.255 dev eth0 scope global /sbin/ip route del 192.168.123.0/24 via 192.168.123.1 dev eth0
一般在购买的服务器已经自动配置好了静态IP和网关, 所以这两个部分可以忽略不设置
-
vrrp_script
健康检查
当检查失败时会将vrrp_instance
的priority
减少相应的值.vrrp_script chk_http_port { script "echo hello" interval 1 weight -10 timeout rise fall user init_fail }
参数 说明 script 要执行的脚本 interval 脚本执行的间隔, 单位 秒
weight 要修改的权重大小, +-priority
timeout 脚本执行多少秒没有返回视为失败 rise 成功多少次后上升权重 fall 成功多少次后下降权重 user 执行脚本的用户 init_fail 假设脚本最初处于失败状态 如果脚本执行失败(这里是:
echo hello
), 相应的vrrp_instance
中的优先级会减少10个点 -
vrrp_instance
和vrrp_sync_group
区域
vrrp_instance
是用来定义对外提供服务的vIP
区域及其相关属性, 是检测节点本身状态的主要功能.
vrrp_sync_group
是用来定义vrrp_intance
组, 使得这个组内成员动作一致.例如两个
vrrp_instance
同属于一个vrrp_intance
组, 那么当其中一个vrrp_instance
出现故障切换时
另一个vrrp_instance
也会一同切换, 无论该节点本身是否出现故障.vrrp_sync_group
区域配置详情:vrrp_sync_group vGroup_1 { group { inside_network # vrrp_instance 节点的名称 outside_network # 每个可以移动的IP ... } notify_master /script/master.sh notify_backup /script/backup.sh notify_fault "/script/fault.sh vGroup_1" notify /script/notify.sh smtp_alert }
参数 说明 notify_master 当该节点切换为 Master
时执行的脚本notify_backup 当该节点切换为 Backup
时执行的脚本notify_fault 当该节点切换 故障/出错
时执行的脚本notify 当前节点切换(不管切换成功还是失败)时执行的脚本 smtp_alert 是否开启邮件通知 smtp_alert
使用全局区域的邮件设置来发通知
notify
会在前面三个脚本执行完成时进行调用, 并且会传递如下三个参数:$1 = 切换后会传递是 GROUP 还是 INSTANCE
$2 = 节点在 GROUP 或者 INSTANCE 设置的名称
$3 = 切换的目标节点状态(MASTER/BACKUP/FAULT)
vrrp_instance
区域配置详情vrrp_instance BASE_1 { state MASTER interface eth0 use_vmac <VMAC_INTERFACE> dont_track_primary track_interface { enp0s3 eth1 } mcast_src_ip <IPADDR> garp_master_delay 10 virtual_router_id 1 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.123.150/24 brd 192.168.123.255 dev enp0s3 } virtual_routes { 192.168.123.0/24 via 192.168.123.1 dev enp0s3 } track_script { chk_http_port } nopreempt preempt_delay 300 debug notify_master <STRING>|<QUOTED-STRING> notify_backup <STRING>|<QUOTED-STRING> notify_fault <STRING>|<QUOTED-STRING> notify <STRING>|<QUOTED-STRING> smtp_alert }
参数 说明 state Master/Backup
具体抢占IP是根据选举权重决定interface 主网卡,用来发 VRRP
包use_vmac 否使用 VRRP
的虚拟MAC地址dont_track_primary 忽略 VRRP
网卡错误,默认未设置track_interface 监控列表中的网卡,任何一个不通就会切换到 FAULT
状态(可选项)mcast_src_ip 修改 VRRP
组播包的源地址,默认源地址为Master
的IPgarp_master_delay 当切为主状态后多久更新 ARP
缓存,默认5秒virtual_router_id 用来区分多个 instance
的VRRP
组播,0~255
之间priority 选举权重 0~255
之间,不在此区间会识别为默认值100
advert_int 发 VRRP
包的间隔时间/健康检查, 即多久进行一次Master
选举authentication 认证区域[ PASS|HA(IPSEC)
],PASS:
密码只识别前8
位virtual_ipaddress 被选举为 Master
后设置的虚拟IP
virtual_routes 被选举为 Master
后设置的虚拟路由
virtual_ipaddress_excluded 发送的 VRRP
包里不包含的IP地址,减少回应VRRP
包的个数.网卡绑定IP比较多的时候有用nopreempt 允许一个低权重节点作为 Master
,即便有priority
更高的节点启动preempt_delay Master
启动多久之后进行接管资源(vIP/Route
信息等),前提没有设置nopreempt
选项当使用
track_script
时可以不用加nopreempt
,只需要加上preempt_delay 5
这里的间隔时间要大于vrrp_script
中定义的时长
注意: 同一网段中virtual_router_id
的值不能重复, 否则会出错, 相关错误信息如下
Tips: 可以用tcpdump -nn -i any net 224.0.0.0/8
命令来查看该网络中所存在的vrid
Keepalived_vrrp[27120]: ip address associated with VRID not present in received packet : one or more VIP associated with VRID mismatch actual MASTER advert bogus VRRP packet received on enp0s3 !!! receive an invalid ip number count associated with VRID! VRRP_Instance(xxx) ignoring received advertisment...
-
virtual_server_group
和virtual_server
区域virtual_server_group
一般在超大型的LVS
中用到, 一般情况下用不到, 暂时略过.
virtual_server
将后端某一台real_server
上的某个服务可以属于多个Virtual Server
并且只做一次健康检查这两项配置主要是针对
LVS+Keepalived
, 如果使用的Nginx
代替LVS
无需进行配置.virtual_server
区域配置详情virtual_server 192.168.123.150 80 { #虚拟服务地址和端口,使用空格分隔,其中地址为VIP delay_loop 1 lb_algo rr lb_kind NAT persistence_timeout 30 persistence_granularity 255.255.255.0 protocol TCP sorry_server 192.168.123.150 65000 real_server 192.168.123.151 80 { weight 1 HTTP_GET { url { path /index.php status_code 200 } connect_timeout 2 nb_get_retry 1 delay_before_retry 0 } } }
参数 说明 delay_loop 健康检查时间间隔,单位 秒
lb_algo 负载均衡 LB
调度算法lb_kind 节点模型,有 NAT/DR/TUN
三种persistence_timeout 持久会话保持时长 persistence_granularity 指定持久连接的掩码粒度 protocol 监控服务的协议类型 1.3.0
版本之后支持UDP
virtualhost 给 HTTP_GET
和SSL_GET
配置请求header
real_server 真正提供服务的服务器, 一般是当前节点的的IP和具体服务器的端口 sorry_server 当所有 real server
宕掉时,sorry server
顶替,一般由本机提供一个web
提示网站正在维护weight 节点权重 notify_up 当 real server
启动时运行的脚本notify_down 当 real server
宕机时运行的脚本HTTP_GET 健康状况检查的检查方式: [ HTTP_GET|SSL_GET|TCP_CHECK|MISC_CHECK
]url HTTP_GET|SSL_GET
时检查的路由,可以有多个path 要检查的路径, 例如 /index.php
digest 状态码: [ status_code|digest|digest+status_code
]digest
值用keepalived
的genhash
命令生成,一般使用status_code
就可以了connect_port 源端口
在指定的端口上连接远程服务器connect_timeout 响应超时,需要重新连接. 单位 秒
nb_get_retry 重试次数, 单位 numerical
delay_before_retry 重试的时间间隔
搭建环境实践
- 对外提供服务的前端服务器,
nginx
反代, 拟定IP:192.168.123.150
- 主web服务器, 提供
nginx, php
功能, 拟定IP:192.168.123.151
- 备web服务器, 提供
nginx, php
功能, 拟定IP:192.168.123.152
- 拟定
Keepalived
虚拟IP为:192.168.123.155
数据库服务器也可以进行双机热备, 读写分离等, 后面单独发布文章.
安装 Keepalived
安装Keepalived
非常容易, 在Linux各大发行版官方仓库中都包含该软件, 只要使用的发行版不是太旧, 可以获得比较新的版本, 该软件在Debian Buster
官方仓库中的版本为: 2.0.10
. 使用以下命令分别在主备服务器安装Keepalived
# 查看仓库中的 keepalived 版本, 看是否符合预期
sudo apt show keepalived
# 安装 keepalived
sudo apt install keepalived -y
# 执行 keepalived --vresion 查看是否正常输出
sudo keepalived --vresion
实践
- 制定配置文件
-
开始配置之前需要准备发送邮件的脚本, 由于默认配置的邮件不适合实际使用, 所以手写了发送邮件的程序
sendmail
, 主要包含如下功能:Usage: parameter [-s | -u | -c| -a | -h] -s Fault server name -u Send to user name -a Send to email address -c Email text -t Email title -h Print help info --help Please input fault server name, send to user and send to address.
-
编写发送邮件的脚本
keepalived_sendmail.sh
, 大致内容如下:#!/bin/bash # Author: AENO - 南岭第一烤橘王 # 脚本执行时间, 可以当做切换时间 change_time=$(date "+%Y-%m-%d %H:%M:%S") # 节点标识, 将作为发件人用户 server_id="$2" # 发送到的邮箱用户 to_user="mail" # 发送到的邮箱地址 to_user_address="mail@admin.cn" # 标题 title="$1->$2 State: $3" # 消息正文, 支持 HTML 标签 comment="<h3>热备节点状态切换通知<h3> <p>当前节点: $2</p> <p>所属区域: $1</p> <p>当前状态: $3</p> <p>切换时间: $change_time</p>" function send_mail() { /home/base/sendmail -s $server_id -u $to_user -a $to_user_address -t "$title" -c "$comment" } function write_log() { cat <<EOF | tee -a /home/base/keepalived_change.log ####################################################### Change_TIME : $change_time SERVER_ID : $server_id SERVER_STATE : $title SENDMAIL_STATE : $1 ####################################################### EOF } function main() { send_mail write_log $? } main
-
编写用于监测站点运行状况的脚本, 当该节点web服务出现异常时也需要切换到备用服务器, 大致如下:
#!/bin/bash # Author: AENO # 检测站点状态码 function site_state_check() { status_code=$(curl -sILw "%{http_code}" -o /dev/null http://$1/index.php) if [[ $status_code != 200 ]]; then send_fault_notify $@ exit 1 else send_fault_recovery $@ exit 0 fi } # 故障发生通知 function send_fault_notify() { # 如果故障锁定文件不存在, 则创建故障锁定文件并同时发送故障通知 if [[ ! -f /tmp/fault.lock ]]; then touch /tmp/fault.lock bash /home/base/keepalived_sendmail.sh 故障通知 $2 "$2--故障通知!!!" fi } # 故障恢复通知 function send_fault_recovery() { if [[ -f /tmp/fault.lock ]]; then rm -rf /tmp/fault.lock bash /home/base/keepalived_sendmail.sh 故障恢复通知 $2 "$2--故障恢复通知!" fi } function main() { site_state_check $@ } main $@
开始制定主服务器配置
```CoffeeScript
# 全局设置
global_defs {
# 开启安全脚本执行
enable_script_security
# 设置执行脚本的用户
script_user base
}
# 健康检测
vrrp_script site_check {
script "/usr/bin/bash /home/base/site_check.sh 192.168.123.151 Master-BASE_1"
interval 1
weight -30
timeout 1
# rise 2
fall 3
# 执行该脚本的用户
user base
# 如果主服务器执行 site_check.sh 失败 3 次权重下降 30,
# 下降后选举权重低于备用服务器将发生切换
# 当再次成功执行后, 权限恢复, 重新切换回主服务器
}
# 检测服务器本身状态
vrrp_instance BASE_1 {
# 将 Base_1 设置标示为主服务器抢占IP, 最终决定权在选举权限设置的priority大小
state MASTER
# 设置发送 VRRP 包的网卡, 填写主网卡设备(负责通信的网卡设备名称)
interface enp0s3
virtual_router_id 51
# 当切为主状态后多久更新ARP缓存,默认5秒
garp_master_delay 5
# 选举权重 默认100
priority 50
# 发送 VRRP 包的间隔时间
advert_int 1
# 认证区域
authentication {
auth_type PASS
auth_pass 12345678
}
# 虚拟IP --- vIP
virtual_ipaddress {
192.168.123.155/24 brd 192.168.123.255 dev enp0s3 scope global
}
# 健康检查, 调用前面设置的健康检查具体规则
track_script {
site_check
}
# debug
notify "/usr/bin/bash /home/base/keepalived_sendmail.sh"
# 由于 global_defs 设置的邮件警告环境不太适合实际使用,
# 因而没有进行配置, 所以这里的邮件发送选项不需要设置, 使用上面的脚本通知即可
# smtp_alert
}
```
制定备服务器配置
```CoffeeScript
# 全局设置
global_defs {
# 开启安全脚本执行
enable_script_security
# 设置执行脚本的用户
script_user base
}
# 健康检测
vrrp_script site_check {
script "/usr/bin/bash /home/base/site_check.sh 192.168.123.152 BUCKUP-BASE_2"
interval 1
# weight -30
timeout 1
# rise 2
fall 3
# 执行该脚本的用户
user base
# 如果主服务器执行 site_check.sh 失败 3 次权重下降 30,
# 下降后选举权重低于备用服务器将发生切换
# 当再次成功执行后, 权限恢复, 重新切换回主服务器
}
# 检测服务器本身状态
vrrp_instance BASE_2 {
# 将 Base_1 设置标示为主服务器抢占IP, 最终决定权在选举权限设置的priority大小
state BACKUP
# 设置发送 VRRP 包的网卡, 填写主网卡设备(负责通信的网卡设备名称)
interface enp0s3
virtual_router_id 51
# 当切为主状态后多久更新ARP缓存,默认5秒
garp_master_delay 5
# 选举权重 默认100
priority 40
# 发送 VRRP 包的间隔时间
advert_int 1
# 认证区域
authentication {
auth_type PASS
auth_pass 12345678
}
# 虚拟IP --- vIP
virtual_ipaddress {
192.168.123.155/24 brd 192.168.123.255 dev enp0s3 scope global
}
# 健康检查, 调用前面设置的健康检查具体规则
track_script {
site_check
}
# debug
notify "/usr/bin/bash /home/base/keepalived_sendmail.sh"
# 由于 global_defs 设置的邮件警告环境不太适合实际使用,
# 因而没有进行配置, 所以这里的邮件发送选项不需要设置, 使用上面的脚本通知即可
# smtp_alert
}
```
备用服务器其实只需要做如下修改即可
- 将监测脚本修改为
site_check.sh 192.168.123.152 BUCKUP-BASE_2
进行监测和发送通知- 注释
weight -30
, 当备用服务器站点监测故障时此时主备都无法提供服务, 但备用服务器不用修改权重, 因为此时不适合再参与选举- 修改备用服务器的选举权重
priority 40
确保小于主服务器
- 测试热备效果, 校验配置是否正确
开始之前, 分别在两台web服务器上创建
index.php
确保可以正常访问.
前端服务器访问:
主
服务器访问
备
服务器访问
-
测试当
主
服务器网络中断后前端服务器访问:nmcli con down static
测试访问结果如下:
查看邮件通知情况, 可以查看到BACKUP--BASE_2
成功切换为主
服务器, 继续提供服务.
-
重新启动
主
服务器的网络连接, 然后停止Nginx
服务后再测试访问前端
服务器查看效果.sudo systemctl stop nginx
可以查看到已经从
主
服务器成功切换到备
服务器了
此时查看邮件:
可以查看到邮件也收到了
- 第二封表示重新启动
主
服务器后主
服务器成功通过选举成为Master
服务器 - 第三封表示
主
服务器网络恢复后,备
服务器重新被选举为BACKUP
服务器 - 第四封表示
主
服务器停止Nginx
后健康检测
脚本检测到主
服务器无法继续提供服务,发送了故障邮件 - 第五封表示
主
服务器停止服务后健康检测
脚本检测到并降低了主
服务器的选举权重被重选为BACKUP
服务器 - 第六封表示
主
服务器停止服务后健康检测
脚本降低主
服务器权重BASE_2
被重选选举为MASTER
服务器,并继续提供服务
- 第二封表示重新启动
-
重新启动
主
服务器的Nginx
并停止备
服务器的Nginx
查看访问效果和邮件通知base@base1:~$ sudo systemctl start nginx base@base2:~$ sudo systemctl stop nginx
可以查看到
主
服务器待Nginx
恢复服务后健康检测
脚本重新提升了主
服务器选择权重成功通过竞选重新成为MASTER
服务器
从邮件通知来看也是可以明显查看到切换状态,正确收到BASE_1
故障恢复通知并竞选为MASTER
, 而备
服务器BASE_2
被重新选举回BACKUP
服务器,同时也收到了因备
服务器停止Nginx
服务后发送的故障邮件.
总结
- 通过前面的部署及测试可以更加详细了解
Keepalived
的热备
切换流程. - 当
主
服务器本身出现故障(网络中断
)时可以及时被备用
服务器的Keepalived
侦测到并快速
切换为Master
服务器继续提供服务, 很好的保证了服务的高可用性
. - 通过使用
健康检测
功能加上检测脚本: site_check.sh
成功检测主
服务器提供的服务
故障后成功将其降权
, 然后选举备
服务器为MASTER
服务器将vIP
漂移到BASE_2
继续提供服务. - 无论是
主
服务器和备
服务器哪个发生了故障
, 都可以通过设置的邮件通知脚本收到故障邮件
便于及时处理发生故障的服务器使其恢复,.
一般情况下, 因为当前两个节点部署的服务是完全一样的, 服务的公共配置文件和
WEB
站点的目录应该由NFS
共享, 然后做软链接便于统一管理, 当前实践只是测试运行效果并非生产环境所以没有这样操作.