Keepalived介绍
Keepalived是一个基于VRRP协议来实现的服务高可用方案。VRRP协议(虚拟路由冗余协议—— Virtual Router Redundancy Protocol,简称VRRP),是由IETF提出的解决局域网中配置静态网关出现单点失效现象的路由协议,1998年已推出正式的RFC2338协议标准。VRRP广泛应用在边缘网络 中,它的设计目标是支持特定情况下IP数据流量失败转移不会引起混乱,允许主机使用单路由器,以 及即使在实际第一跳路由器使用失败的情形下仍能够维护路由器间的连通性。 大白话来说就是,VRRP协议允许一台机器可以拥有一个或者多个虚拟IP。在高可用的一组机器中,有 一个master,多个slave,对外提供一个虚IP,通过虚IP访问master,slave负责监控master,如果 master宕机,则选举其中一个slave接管master,虚IP绑定到新的master上(俗称IP漂移),从而实现了高可用。深入了解请查看 keepAlived官网。
环境
硬件
配置 | 测试配置 |
---|---|
CPU | 1.8GHz |
内存 | 4GB |
核心 | 4核 |
带宽 | 1000Mb |
软件
- VMware® Workstation 16 Pro 16.1.1 build-17801498
- CentOS Linux release 7.6.1810 (Core)
- nginx-1.9.9
- keepalived-1.3.5-19.el7.x86_64
规划
IP | host | 说明 |
---|---|---|
192.168.88.100 | KP的VIP | |
192.168.88.54 | node1 | 节点1,安装kp与ng,设置master |
192.168.88.59 | node2 | 节点2,安装kp与ng,设置slave |
安装过程
因为两个节点配置过程基本都是相同的,可以使用xhell的“发送键入到所有会话”的方式,同时安装两个节点(相信我,试一下,非常爽)。
nginx
基础安装过程参考文章:《CentOS 7 安装 nginx 极简教程》《nginx安装 ./configure参数详解》
安装完成后,修改index.html,区分node1和node2。最后一个字符关闭同步输入。
vim /usr/local/nginx/html/index.html
修改配置文件,默认使用运维用户(www)运行进程,并且将项目的配置文件从默认配置文件独立出去。运维用户的创建过程参考文章《CentOS 7 创建运维用户》
vim /usr/local/nginx/conf/nginx.conf
创建项目配置目录
mkdir /usr/local/nginx/conf/vhost
chmod 777 /usr/local/nginx/conf/vhost
nginx命令提升权限
chmod u+s /usr/local/nginx/sbin/nginx
运行测试
/usr/local/nginx/sbin/nginx
ps -ef | grep nginx
可以看到nginx进程已经起来了。
防火墙添加端口。通过浏览器验证一下。
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload
node1:
node2:
keepalived
安装依赖
yum install -y net-snmp-agent-libs ipset ipset-libs net-snmp-libs
安装keepalived
yum install ‐y keepalived
准备相关脚本,并上传到服务器
check_ng.sh
#!/bin/bash
if [ "$(ps -ef | grep "nginx: master process"| grep -v grep )" == "" ];
then
/usr/local/nginx/sbin/nginx
sleep 2
if [ "$(ps -ef | grep "nginx: master process"| grep -v grep )" == "" ];
then
systemctl stop keepalived
fi
fi
master.sh
#!/bin/bash
ip=$(hostname -I | awk '{print $1}')
dt=$(date +'%Y-%m-%d %H:%M:%S')
echo "$0--${ip}--${dt}">>/joinway/tools/keepalived/log/kp.log
backup.sh
#!/bin/bash
ip=$(hostname -I | awk '{print $1}')
dt=$(date +'%Y-%m-%d %H:%M:%S')
echo "$0--${ip}--${dt}">>/joinway/tools/keepalived/log/kp.log
fault.sh
#!/bin/bash
ip=$(hostname -I | awk '{print $1}')
dt=$(date +'%Y-%m-%d %H:%M:%S')
echo "$0--${ip}--${dt}">>/joinway/tools/keepalived/log/kp.log
stop.sh
#!/bin/bash
ip=$(hostname -I | awk '{print $1}')
dt=$(date +'%Y-%m-%d %H:%M:%S')
echo "$0--${ip}--${dt}">>/joinway/tools/keepalived/log/kp.log
修改kp配置
vim /etc/keepalived/keepalived.conf
node1(master)配置:
! 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_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
script_user root
enable_script_security
}
vrrp_script check_ng
{
script "/joinway/tools/keepalived/check_ng.sh"
interval 1
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass joinway
}
virtual_ipaddress {
192.168.88.100
}
track_script {
check_ng
}
notify_master /joinway/tools/keepalived/master.sh
notify_backup /joinway/tools/keepalived/backup.sh
notify_fault /joinway/tools/keepalived/fault.sh
notify_stop /joinway/tools/keepalived/stop.sh
}
node2(backup)配置:
! 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_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
script_user root
enable_script_security
}
vrrp_script nginx_check {
script "/joinway/tools/keepalived/check_ng.sh"
interval 1
user root
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass joinway
}
virtual_ipaddress {
192.168.88.100
}
track_script {
nginx_check
}
notify_master /joinway/tools/keepalived/master.sh
notify_backup /joinway/tools/keepalived/backup.sh
notify_fault /joinway/tools/keepalived/fault.sh
notify_stop /joinway/tools/keepalived/stop.sh
}
配置文件中的第24/30/39/44/45/46/47行需要根据实际情况进行调整。
创建脚本路径并修改文件权限
mkdir -p /joinway/tools/keepalived
chmod 755 /joinway/tools/keepalived/*.sh
至此,所有的配置就做好了,可以启动keepalived了。
等一下,这里还有一个坑,如果没有关闭防火墙,请记得配置vrrp协议,否则脑裂 ̄へ ̄
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent && firewall-cmd --reload
管理命令如下:
systemctl start keepalived.service # 启动
systemctl stop keepalived.service # 停止
systemctl status keepalived.service # 查看状态
start之后可以看到keepalived已经运行起来的
但是这时发现一个问题,我们在脚本中配置的“/joinway/tools/keepalived/log/kp.log”路径下log并没有输出出来,并且在nginx挂掉的时候,check_ng.sh脚本也没起到应有的作用。
于是在调查原因的过程中,发现KP日志有如下错误信息。
“Unable to access script”、“Disabling notify script”,这个错误信息可谓是赫赫有名啊,可能很多小伙伴都会遇到一样的情况,在网上找了好多的方案,试来试去,基本都是徒劳。最靠谱的算是关闭selinux,关闭了确实有效果,但是作为生产服务器,关闭厂家自带的安全机制很显然不是一个很好的选择,在山穷水尽之后,果然是柳暗花明。
在这里特别感谢阿里云大神咸鱼运维杂谈,详细解析了selinux拦截kp运行脚本的原因以及解决方案。
修改kp脚本的安全上下文。
chcon -t keepalived_unconfined_script_exec_t /joinway/tools/keepalived/*.sh
手动创建kp.log日志文件后,脚本触发的日志也正常了。
/joinway/tools/keepalived/log
vim /joinway/tools/keepalived/log/kp.log
调整KP日志
在解决问题过程中,发现kp的日志默认是写在系统“/var/log/messages”路径中的,考虑到以后kp的维护需要交给运维账户,需要把kp日志单独独立出来,权限单独控制。
编辑配置文件/etc/sysconfig/keepalived,将第14行的KEEPALIVED_OPTIONS="-D"修改为KEEPALIVED_OPTIONS="-D -d -S 0"
vim /etc/sysconfig/keepalived
修改rsyslog的配置文件/etc/rsyslog.conf,在结尾加入如下2行内容,将local0设备的所有日志都记录到/var/log/keepalived.log文件.
vim /etc/rsyslog.conf
重启rsyslog服务
service rsyslog restart
修改日志文件权限,让运维用户可以看得到。
chmod 755 /var/log/keepalived.log
至此keepalived已可以正常使用。
模拟node1挂掉
node2接管服务
模拟node1恢复
node1重新接管服务
测试运维用户(www)
[www@node1 ~]$ sudo systemctl stop keepalived.service
[www@node1 ~]$ sudo systemctl start keepalived.service
[www@node1 ~]$ sudo systemctl status keepalived.service
[www@node1 ~]$ tail -f /var/log/keepalived.log
[www@node1 ~]$ tail -f /joinway/tools/keepalived/log/kp.log
KP指令均可正常执行
[www@node1 vhost]$ sudo /usr/local/nginx/sbin/nginx -t
[www@node1 vhost]$ sudo /usr/local/nginx/sbin/nginx -s stop
[www@node1 vhost]$ sudo /usr/local/nginx/sbin/nginx -s quit
[www@node1 vhost]$ sudo /usr/local/nginx/sbin/nginx -s reload
[www@node1 vhost]$ sudo /usr/local/nginx/sbin/nginx
[www@node1 vhost]$ tail -f /usr/local/nginx/logs/access.log
[www@node1 vhost]$ tail -f /usr/local/nginx/logs/error.log
NG指令正常