一、Keepalived 初识
1. 作用简介
Keepalived一个基于VRRP协议的虚拟路由来解决单点故障,搭配自身LVS服务可实现设备服务高可用方案。也可以与其他的软件组合实现服务高可用,比如采用Nginx。
2. 实现原理
在多台服务器上运行Keepalived,分为主(MASTER)备(BACKUP)服务器。设置相同的虚拟IP池(VIP)和不同的节点优先级,通过VRRP协议广播(多播或单播)的方式,来竞选主节点MASTER,MASTER的网卡绑定对外的同一VIP。初始配置MASTER服务器优先级设置最高,BACKUP低一些各不相同。由MASTER定时发送VRRP广播到各BACKUP,如果BACKUP在固定时间内收不到MASTER的广播,认为MASTER服务器已经挂掉,会向其它的BACKUP服务器发送广播,进行MASTER的竞选并绑定VIP。如果是非抢占模式,由先发送广播的BACKUP成为新的MASTER,旧的MASTER重新加入虚拟路由后成为BACKUP;如果是抢占模式,收到广播后会对比彼此的优先级,由优先级高的BACKUP节点成为新的MASTER,旧的MASTER重新加入虚拟路由后会夺回MASTER,优先级低的节点重回BACKUP。
二、Keepalived 安装
1. yum安装
执行命令yum install -y keepalived 。
如果用到LVS,需要安装ipvs模块,执行命令yum install ipvsadm。
2 源码安装
2.1 下载
前往官网Keepalived for Linux,下载需要的版本安装包,一般下载最新的。
2.2 安装
tar -zxvf keepalived-2.2.18.tar.gz
cd keepalived-2.2.8
./configure --prefix=/usr/local/keepalived
make && make install
编译时如果出现以下警告,需要安装libnl模块,执行命令yum install -y libnl libnl-devel。
如果出现以下错误,需要安装libnfnetlink模块,执行命令
yum install -y libnfnetlink-devel。
configure: error: libnfnetlink headers missing
解决完错误后再进行编译和安装:
./configure --prefix=/usr/local/keepalived
make && make install
如果需要将Keepalived加入系统服务,需要将需要的文件从安装目录复制到系统管理目录下:
mkdir /etc/keepalived
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/init.d/keepalived
再刷新系统服务,加载新添加的Keepalived服务并加入自启动:
systemctl daemon-reload
systemctl enable keepalived
三、配置文件
Keepalived配置文件是keepalived.conf,配置里有全局配置、VRRPD配置和LVS配置,本文实现只用到全局配置和部分VRRPD配置,负载均衡用Nginx实现。所以除了Keepalived配置文件,还有Nginx配置文件nginx.conf和Nginx检测脚本文件check_nginx_pid_restart.sh。
三个文件路径为:
/usr/local/keepalived/etc/keepalived/keepalived.conf
/usr/local/nginx/conf/nginx.conf
/usr/local/keepalived/check_nginx_pid_restart.sh
1. Keepalived 全局配置
# 全局配置
global_defs {
# keepalived自带的邮件提醒需要开启sendmail 服务,建议用独立的监控或第三方SMTP
# 指定keepalived在发生事件(比如切换) 时,需要发送email到的对象
notification_email {
# 邮件接收人员信息,可以为多个
acassen@firewall.loc
}
# 指定运行脚本的用户名和组
script_user root
# 如过路径为非root可写,不要配置脚本为root用户执行。
enable_script_security
# 邮件发送者地址
notification_email_from Alexandre.Cassen@firewall.loc
# 指定发送email的smtp服务器,如果本地开启了sendmail的话,可以使用上面的默认配置
smtp_server 127.0.0.1
# 邮件发送连接超时时间,单位秒
smtp_connect_timeout 30
# 标识本节点的字条串,发送邮件会带上此标识
router_id LVS_DEVEL
#vrrp_skip_check_adv_addr
# 如果ping不通vip地址,把这个注释掉,建议直接注释掉
#vrrp_strict
# 小数类型,单位秒,默认为0,一个发送的消息=n组 arp报文
# 在一个网卡上每组gratuitous arp消息之间的延迟时间
#vrrp_garp_interval 0
# 小数类型,单位秒,默认为0,在一个网卡上每组na消息之间的延迟时间
#vrrp_gna_interval 0
# 指定发送VRRP组播消息使用的IPV4组播地址。默认是224.0.0.18
#vrrp_mcast_group4 224.0.0.18
# 指定发送VRRP组播消息所使用的IPV6组播地址。默认是ff02::12
#vrrp_mcast_group6 ff02::12
}
Unable to set default user keepalived_script for script.
SECURITY VIOLATION - scripts are being executed but script_security not enabled.
是Nginx检测脚本(后面会提到)的执行用户和权限安全问题,需要在全局配置加上对应配置或取消注释:
script_user root
enable_script_security
2. Keepalived VRRPD配置
2.1 Nginx 检测脚本配置
# 检测机制的脚本名称为check_nginx_pid_restart
vrrp_script check_nginx_pid_restart {
# 执行Nginx运行检测脚本
script "/usr/local/keepalived/check_nginx_pid_restart.sh"
# 每隔2秒检测一次
interval 2
# 当脚本执行成立,那么把当前服务器优先级改为-20
weight -20
# 执行监测脚本的用户或组
#user root
# 超时时间
timeout 10
# 执行脚本连续几次都失败,则转换为失败,建议设为2以上
#fall 2
# 执行脚本连续几次都成功,把服务器从失败标记为成功
#rise 2
# 设置默认标记为失败状态,监测成功之后再转换为成功状态
#init_fail
}
如果Keepalived运行时,日志显示以下错误:
Track script check_nginx_pid_restart is already running, expect idle - skipping run
VRRP_Script(check_nginx_pid_restart) timed_out
需要在vrrp_script添加timeout参数或取消注释timeout 10。
2.2 虚拟路由配置
主备服务器配置基本相同,但虚拟路由ID参数virtual_router_id、虚拟IP池virtual_ipaddress和认证权限密码authentication必须相同;初始身份参数state(MASTER/BACKUP)和节点优先级参数priority必须做区分,其它的源IP、IP段、路由参数根据节点机实际情况做调整。
# 定义虚拟路由,主备必须一致,VI_1为虚拟路由的标示符(可自定义名称)
vrrp_instance VI_1 {
# 当前节点的身份标识:用来决定主从(MASTER为主机只设一个,BACKUP为从机)
state MASTER
# 绑定虚拟IP的网络接口
interface ens33
# 指定VRRP虚拟mac地址
#user_vmac [<VMAC_INTERFACE>]
# 从基本接口发送和接受vrrp消息,而不是VMAC接口
# 强制instance使用ipv6(当混合ipv4和ipv6的配置)
#native_ipv6
#vmac_xmit_base
# 发送多播包的源IP, 如果不设置, 默认使用绑定的网卡的primary IP
mcast_src_ip 192.168.1.4
# 单播主备在不同网段
#unicast_peer {
# 128.192.11.11
#}
# 发送单播包的源IP
#unicast_src_ip <IPADDR>
# 在切换到MASTER状态后, 延迟进行gratuitous ARP请求
#garp_master_delay
# 虚拟路由的ID号,主从两个节点设置必须一样(0…255)
virtual_router_id 51
# 节点优先级,值范围 0-254,MASTER要比BACKUP高
priority 100
# 不设置默认为抢占模式,设置为非抢占模式,BACKUP设置
# 非抢占模式:优先级高的机器上线,仍让已成MASTER的低优先级机器继续
#nopreempt
# 抢占延迟,单位是秒,范围是0---1000
#preempt_delay 5
# 组播信息发送间隔(心跳检测),两个节点设置必须一样,默认1s
advert_int 1
# 设置验证信息,两个节点必须一致
authentication {
auth_type PASS
# 用于通信的密码
auth_pass 1111
}
# 将track_script块加入instance配置块
track_script {
# 执行Nginx监控的脚本
check_nginx_pid_restart
}
# 设置虚拟ip池,两个节点设置必须一样
virtual_ipaddress {
# 网段多个地址192.168.200.17/24 dev eth1
192.168.1.116/24 dev ens33
}
# 从VRRP中排出一部分VRRP ip地址
#virtual_ipaddress_excluded {
# <IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE>
# <IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE>
#}
# 当状态改变时,增加或删除route
#virtual_routes {
#src <IPADDR> [to] <IPADDR>/ <MASK> via
#gw <IPADDR> [ or<IPADDR>] dev <STRING> scope <SCOPE> table <TABLE>
#src 192.168.100.1 to 192.168.109.0/24 via 192.168.200.254 dev eth1
#192.168.100.0/24 via 192.168.200.254 dev eth1
#192.168.111.0/24 dev eth2
#192.168.112.0/24 via 192.168.100.254
#192.168.113.0/24 via 192.168.200.254 or 192.168.100.254 dev eth1
#blackole 192.168.114.0/24
#0.0.0./0 gw 192.168.0.1 table 100 #设置默认网关为表100
#}
# vrrpd状态发生变化是,添加或删除rules
#virtual_rules {
# from 192.168.2.0/24 table 1
# to 192.168.2.0/24 table 1
#}
}
3. Nginx 配置
只测试Keepalived解决单点故障,Nginx配置使用默认配置,高可用在Nginx配置里面加上负载均衡即可。
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
listen监听可以不配IP,默认监听所有IP。也可以配上VIP:
listen 192.168.1.116:80;
配置加上监听VIP后,因为配置了一个服务器原本不存在的IP,启动Nginx会报错
Cannot assign requested address
需要开启 Kernel 的参数:
vim /etc/sysctl.conf
#添加IPv4和IPv6,保存退出
net.ipv4.ip_nonlocal_bind=1
net.ipv6.ip_nonlocal_bind=1
#执行新配置
sysctl -p
4. Nginx 检测脚本
#!/bin/sh
# 通过ps指令查询后台的nginx进程数,并将其保存在变量nginx_number中,wc -l表示获取行数
nginx_number=`ps -C nginx --no-header | wc -l`
# 判断后台是否还有Nginx进程在运行
if [ $nginx_number -eq 0 ];then
# 如果后台查询不到Nginx进程存在,则执行重启指令
echo "nginx is not running....., starting nginx...."
`/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf`
# 重启后等待2s后,再次查询后台进程数
sleep 2
# 如果重启后依旧无法查询到nginx进程
nginx_number=`ps -C nginx --no-header | wc -l`
if [ $nginx_number -eq 0 ];then
# 将keepalived主机下线,将虚拟IP漂移给从机,从机上线接管Nginx服务
echo "nginx is starting failed...."
`killall keepalived`
else
echo "nginx is starting success...."
fi
else
echo "nginx is running...."
fi
需要对脚本进行权限修改,保证使用:
chmod +x /usr/local/keepalived/check_nginx_pid_restart.sh
当Nginx未运行,脚本执行Nginx启动不成功时,下线本机Keepalived失败,需要安装killall:
yum install -y psmisc
四、测试
1. 启动Keepalived
/usr/local/keepalived/sbin/keepalived
如果将Keepalived加入了系统服务,可以以服务方式启动:
service keepalived start
2. 观察
观察主从节点是否加入虚拟路由tail -f /var/log/messages
观察VRRP广播是否成功收发tcpdump -i ens33 vrrp -n
观察Nginx启动是否成功tail -f /usr/local/nginx/logs/error.log
观察访问VIP是否请求到Nginxtail -f /usr/local/nginx/logs/access.log
VIP是否成功挂载网卡ip addr
3. 访问VIP
浏览器输入VIP访问,如果出现Nginx欢迎页面,表示搭建成功。
4. 高可用VIP漂移
关闭MASTER服务器Keepalived:
killall keepalived
# 或
service keepalived stop
观察优先级高的BACKUP服务器日志是否成为MASTER,绑定的网卡是否挂载VIP,然后再访问VIP
5. 测试中的问题
这里主要是还可能碰到防火墙的问题,其它的问题需要在配置文件里增改参数,前面已经做了提出和解决。
5.1 脑裂现象
即Keepalived的主备服务器配置的网卡都挂载了VIP,观察VRRP广播主备节点都在发送VRRP包。这是防火墙打开后,将VRRP广播过滤了,导致Keepalived都没有收到其它节点的广播,有三种解决方式:
a. 关闭防火墙
systemctl stop firewalld
b. 将防火墙VRRP打开
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --direct --permanent --add-rule ipv6 filter INPUT 0 --in-interface ens33 --destination ff02::12 --protocol vrrp -j ACCEPT
firewall-cmd --reload
c. 采用单播方式,在虚拟路由配置里对多播IP注释,开启单播IP
# 发送多播包的源IP
#mcast_src_ip 192.168.1.4
# 发送单播包的源IP
unicast_src_ip 192.168.1.4
5.2 访问请求未能进Nginx
这是防火墙打开后,没有开启Nginx监听的端口,有两种解决方式:
a. 关闭防火墙
systemctl stop firewalld
b. 将防火墙端口打开
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports