一、详解keepalived配置和使用
keepalived使用
keepalived介绍
vrrp 协议的软件实现,原生设计目的为了高可用 ipvs服务
功能:
- 基于vrrp协议完成地址流动
- 为vip地址所在的节点生成ipvs规则(在配置文件中预先定义)
- 为ipvs集群的各RS做健康状态检测
- 基于脚本调用接口完成脚本中定义的功能,进而影响集群事务,以此支持nginx、haproxy等服务
Keepalived 架构
官方文档:Keepalived User Guide — Keepalived 1.4.3 documentationKeepalived for Linux
- 用户空间核心组件:
- vrrp stack:VIP消息通告
- checkers:监测real server
- system call:实现 vrrp 协议状态转换时调用脚本的功能
- SMTP:邮件组件
- IPVS wrapper:生成IPVS规则
- Netlink Reflector:网络接口
- WatchDog:监控进程
- 控制组件:提供keepalived.conf 的解析器,完成Keepalived配置
- IO复用器:针对网络目的而优化的自己的线程抽象
- 内存管理组件:为某些通用的内存管理功能(例如分配,重新分配,发布等)提供访问权限
环境准备
- 各节点时间必须同步:ntp,chrony
- 关闭防火墙及SELinux
- 各节点之间可通过主机名互相通信:非必须
- 建议使用/etc/hosts文件实现:非必须
- 各节点之间的root用户可以基于密钥认证的ssh服务完成互相通信:非必须
keepalived配置
配置文件组成部分
配置文件:/etc/keepalived/keepalived.conf
配置文件组成部分:
- GLOBAL CONFIGURATION
Global definitions:定义邮件配置,route_id,vrrp配置,多播地址等
- VRRP CONFIGURATION
VRRP instance(s):定义每个vrrp虚拟路由器
- LVS CONFIGURATION
Virtual server group(s)
Virtual server(s):LVS集群的VS和RS
配置文件语法
当生产环境复杂时, /etc/keepalived/keepalived.conf 文件中内容过多,不易管理,可以将不同集群的配置,比如:不同集群的VIP配置放在独立的子配置文件中,利用include 指令可以实现包含子配置文件
全局配置
global_defs {
notification_email {
root@localhost #keepalived发生故障切换时邮件发送的目标邮箱,可以按行区分写多个
}
notification_email_from keepalived@localhost #发邮件的地址
smtp_server 127.0.0.1 #邮件服务器地址
smtp_connect_timeout 30 #邮件服务器连接timeout
router_id LVS_DEVEL #每个keepalived主机唯一标识,建议使用当前主机名,但多节点重名不影响
vrrp_skip_check_adv_addr #对所有通告报文都检查,会比较消耗性能,启用此配置后,如果收到的通告报文和上一个报文是同一个路由器,则跳过检查,默认值为全检查
vrrp_strict #严格遵守VRRP协议,禁止以下状况:1.无VIP地址 2.配置了单播邻居 3.在VRRP版本2中有IPv6地址,开启动此项会自动开启iptables防火墙规则,建议关闭此项配置
vrrp_garp_interval 0 #gratuitous ARP messages报文发送延迟,0表示不延迟
vrrp_gna_interval 0 #unsolicited NA messages (不请自来)消息发送延迟
vrrp_mcast_group4 224.0.0.18 #指定组播IP地址,默认值:224.0.0.18 范围:224.0.0.0到239.255.255.255
vrrp_iptables #此项和vrrp_strict同时开启时,则不会添加防火墙规则,如果无配置vrrp_strict项,则无需启用此项配置
}
include /etc/keepalived/conf.d/*.conf #将VRRP相关配置放在子配置文件中
配置虚拟路由器
vrrp_instance <STRING> { #<String>为vrrp的实例名,一般为业务名称
配置参数
......
}
#配置参数:
state MASTER|BACKUP #当前节点在此虚拟路由器上的初始状态,状态为MASTER或者BACKUP
interface IFACE_NAME #绑定为当前虚拟路由器使用的物理接口,如:eth0,bond0,br0,可以和VIP不在一个网卡
virtual_router_id VRID #每个虚拟路由器惟一标识,范围:0-255,每个虚拟路由器此值必须唯一,否则服务无法启动,同属一个虚拟路由器的多个keepalived节点必须相同
priority 100 #当前物理节点在此虚拟路由器的优先级,范围:1-254,每个keepalived主机节点此值不同
advert_int 1 #vrrp通告的时间间隔,默认1s
authentication { #认证机制
auth_type AH|PASS
auth_pass <PASSWORD> #预共享密钥,仅前8位有效,同一个虚拟路由器的多个keepalived节点必须一样
}
virtual_ipaddress { #虚拟IP
<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE> label <LABEL>
192.168.200.100 #指定VIP,不指定网卡,默认为eth0,注意:不指定/prefix,默认为/32
192.168.200.101/24 dev eth1 #指定VIP的网卡
192.168.200.102/24 dev eth2 label eth2:1 #指定VIP的网卡label
}
track_interface { #配置监控网络接口,一旦出现故障,则转为FAULT状态实现地址转移
eth0
eth1
…
}
启用keepalived日志功能
[root@node5 ~]# vim /etc/sysconfig/keepalived
KEEPALIVED_OPTIONS="-D -S 6"
[root@node5 ~]# vim /etc/rsyslog.conf
local6.* /var/log/keepalived.log
[root@node5 ~]# systemctl restart keepalived.service rsyslog.service
[root@node5 ~]# tail -f /var/log/keepalived.log
二、keeplived 结合nginx 实现高可用
keeplived+nginx节点1:172.20.21.170
keeplived+nginx节点2:172.20.21.175
后端web服务器1:172.20.22.11
后端web服务器2:172.20.22.12
#先准备好两台后端web服务器
[root@localhost ~]# yum install -y httpd
[root@localhost ~]# echo 'web1 172.20.22.11'
[root@localhost ~]# systemctl start httpd
#访问测试
[root@localhost ~]# curl 172.20.22.11
web1 172.20.22.11
[root@localhost ~]# curl 172.20.22.12
web2 172.20.22.12
#在两个节点都配置nginx反向代理
[root@node5 ~]# yum install -y nginx
[root@node5 ~]# vim /etc/nginx/nginx.conf
http {
upstream websrvs {
server 172.20.22.11 weight=1;
server 172.20.22.12 weight=1;
}
server {
listen 80;
server_name www.a.com;
location / {
proxy_pass http://websrvs/;
}
}
}
#在两个节点都配置实现nginx反向代理高可用
[root@node5 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id node5 #另一个节点为node8
vrrp_mcast_group4 224.20.0.18
}
vrrp_instance VI_1 {
state MASTER #在另一个节点为BACKUP
interface eth0
virtual_router_id 65
priority 100 #在另一个节点为80
advert_int 1
authentication {
auth_type PASS
auth_pass PbP2YKme
}
virtual_ipaddress {
172.20.22.50/16 dev eth0 label eth0:0
}
}
[root@node5 ~]# cat /etc/keepalived/keepalived.conf
[root@node5 ~]# systemctl start keepalived
[root@node5 ~]# ifconfig eth0:0
eth0:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.20.22.50 netmask 255.255.0.0 broadcast 0.0.0.0
ether 00:0c:29:47:bb:03 txqueuelen 1000 (Ethernet)
##访问172.20.22.50测试,当170的keepalived进程挂了之后vip:172.20.22.50会自动转移到175上,用户访问172.20.22.50不受影响。当170的keepalived进程恢复之后,170的设定的优先级比175的高,所以vip又会自动转移回170上。
[root@localhost ~]# while true;do curl http://172.20.22.50;sleep 1;done
web2 172.20.22.12
web2 172.20.22.12
web1 172.20.22.11
web2 172.20.22.12
web1 172.20.22.11
三、keepalived脑裂产生的原因以及解决的办法
keepalived脑裂产生的原因
脑裂(split-brain):指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。
一般来说裂脑的发生,有以下几种原因:
- 心跳线断开或连接心跳线的中间故障(交换机等);
- 设备故障,网卡及相关驱动存在问题;
- iptables防火墙阻挡IP或阻挡VRRP协议传输;
- virtual_router_id两端参数配置不一致;
keepalived脑裂解决办法
一般采用2个方法:
1、仲裁
当两个节点出现分歧时,由第3方的仲裁者决定听谁的。这个仲裁者,可能是一个锁服务,一个共享盘或者其它什么东西。
2、fencing
当不能确定某个节点的状态时,通过fencing把对方干掉,确保共享资源被完全释放,前提是必须要有可靠的fence设备
四、实现keeplived监控,通知
keepalived利用 VRRP Script 技术,可以调用外部的辅助脚本进行资源监控,并根据监控的结果实现优先动态调整,从而实现其它应用的高可用性功能
实现Keepalived 状态切换的通知脚本
#在所有keepalived节点配置如下
[root@node3 ~]# cat /etc/keepalived/notify.sh
#!/bin/bash
#
contact='root@localhost'
notify() {
local mailsubject="$(hostname) to be $1, vip floating"
local mailbody="$(date +'%F %T'): vrrp transition, $(hostname) changed to be $1"
echo "$mailbody" | mail -s "$mailsubject" $contact
}
case $1 in
master)
systemctl start nginx
notify master
;;
backup)
systemctl start nginx
notify backup
;;
fault)
systemctl stop nginx
notify fault
;;
*)
echo "Usage: $(basename $0) {master|backup|fault}"
exit 1
;;
esac
##配置示例
[root@node5 ~]# vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
......
virtual_ipaddress {
192.168.30.77/24 dev eth0 label eth0:0
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
VRRP Script 配置
分两步实现:
1、定义脚本
vrrp_script:自定义资源监控脚本,vrrp实例根据脚本返回值,公共定义,可被多个实例调用,定义在vrrp实例之外的独立配置块,一般放在global_defs设置块之后。
通常此脚本用于监控指定应用的状态。一旦发现应用的状态异常,则触发对MASTER节点的权重减至低于SLAVE节点,从而实现 VIP 切换到 SLAVE 节点
2、调用脚本
track_script:调用vrrp_script定义的脚本去监控资源,定义在实例之内,调用事先定义的vrrp_script
##定义VRRP script
vrrp_script <SCRIPT_NAME> { #定义一个检测脚本,在global_defs 之外配置
script <STRING>|<QUOTED-STRING> #shell命令或脚本路径
interval <INTEGER> #间隔时间,单位为秒,默认1秒
timeout <INTEGER> #超时时间
weight <INTEGER:-254..254> #此值为负数,表示fall((脚本返回值为非0)时,会将此值与本节点权重相加可以降低本节点权重,如果是正数,表示 rise (脚本返回值为0)成功后,会将此值与本节点权重相加可以提高本节点权重,通常使用负值较多
fall <INTEGER> #脚本连续监测成功后,把服务器从成功标记为失败的次数
rise <INTEGER> #脚本连续监测成功后,把服务器从失败标记为成功的次数
user USERNAME [GROUPNAME] #执行监测脚本的用户或组
init_fall #设置默认标记为失败状态,监测成功之后再转换为成功状态
}
##调用VRRP script
vrrp_instance VI_1 {
…
track_script {
chk_down
}
}
实现HAProxy高可用
##在两个节点修改内核参数
[root@node5 ~]# vim /etc/sysctl.conf
[root@node5 ~]# sysctl -p
net.ipv4.ip_nonlocal_bind = 1
#在两个节点先实现haproxy的配置
[root@node5 ~]# cat /etc/haproxy/haproxy.cfg
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456
listen web_port
bind 172.20.22.50:8899
mode http
log global
server web1 172.20.22.11:80 check inter 3000 fall 2 rise 5
server web2 172.20.22.12:80 check inter 3000 fall 2 rise 5
[root@node5 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id node5 #在另一个节点为node8
vrrp_mcast_group4 224.20.0.20
}
vrrp_script check_haproxy { #定义脚本
script "/etc/keepalived/chk_haproxy.sh"
interval 1
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER #在另一个节点为BACKUP
interface eth0
virtual_router_id 65
priority 100 #在另一个节点为80
advert_int 1
authentication {
auth_type PASS
auth_pass PbP2YKme
}
virtual_ipaddress {
172.20.22.50/16 dev eth0 label eth0:0
}
track_script {
check_haproxy #调用上面定义的脚本
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
[root@node3 ~]# cat /etc/keepalived/notify.sh
#!/bin/bash
#
contact='root@localhost'
notify() {
local mailsubject="$(hostname) to be $1, vip floating"
local mailbody="$(date +'%F %T'): vrrp transition, $(hostname) changed to be $1"
echo "$mailbody" | mail -s "$mailsubject" $contact
}
case $1 in
master)
systemctl start nginx
notify master
;;
backup)
systemctl start nginx
notify backup
;;
fault)
systemctl stop nginx
notify fault
;;
*)
echo "Usage: $(basename $0) {master|backup|fault}"
exit 1
;;
esac
[root@node5 ~]# yum install -y psmisc
[root@node5 ~]# cat /etc/keepalived/chk_haproxy.sh
#!/bin/bash
/usr/bin/killall -0 haproxy