Keepalived 的安装与使用

400 阅读10分钟

一、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。
—————————————————————————————\color{Silver} {—————————————————————————————}

二、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-devellibnl.png   如果出现以下错误,需要安装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 image.png

3. 访问VIP

  浏览器输入VIP访问,如果出现Nginx欢迎页面,表示搭建成功。 image.png

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