Keepalived 源码安装与 VIP 漂移实践

Keepalived 靠 VRRP 协议在主备机之间维护一个虚拟 IP(VIP),主机挂了 VIP 自动漂到备机。这篇记录源码安装、双机配置、以及和 Nginx 健康检查联动的完整过程。

环境与源码编译

Name IP Addr Description
VIP 192.168.66.100 虚拟 IP
MASTER 192.168.66.11 主服务器 IP
BACKUP 192.168.66.12 备服务器 IP

下载页在 https://www.keepalived.org/download.html,这里用 2.0.20,主备两台操作相同:

[root@load_balance-1 ~]# cd /opt/soft
[root@load_balance-1 soft]# wget https://www.keepalived.org/software/keepalived-2.0.20.tar.gz

直接 configure 会撞上三个问题:一是提示不安装 libnl/libnl-3 就不支持 IPv6 的 IPVS;二是 configure: error: libnfnetlink headers missing;三是 OpenSSL 头文件缺失报错。一条命令把依赖补齐:

[root@load_balance-1 soft]# yum -y install libnl libnl-devel libnfnetlink-devel openssl-devel

然后解包编译安装:

[root@load_balance-1 soft]# tar -zxvf keepalived-2.0.20.tar.gz
[root@load_balance-1 soft]# cd keepalived-2.0.20/
[root@load_balance-1 keepalived-2.0.20]# ./configure --prefix=/usr/local/keepalived
image-594
[root@load_balance-1 keepalived-2.0.20]# make && make install
image-598

配置文件字段详解

keepalived.conf 的骨架:global_defs 里的通知邮箱、router_id;vrrp_instance 里最关键的是 state(MASTER/BACKUP)、网卡 interface、virtual_router_id(主备必须一致)、priority(主必须大于备)、认证(主备密码必须一致)、virtual_ipaddress;最后是虚拟服务器段。带注释的完整版:

! Configuration File for keepalived

global_defs {
     notification_email {
     # email 接收方
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   # email 发送方
   notification_email_from Alexandre.Cassen@firewall.loc
   # 邮件服务器, smtp 协议
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id app2
   vrrp_skip_check_adv_addr
   
   # 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
   #vrrp_strict 
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

# vrrp实例
vrrp_instance VI_1 {
    # 指定 keepalived 的角色,MASTER 表示此主机是主服务器,BACKUP 表示此主机是备用服务器
    state MASTER

    # 指定网卡
    interface ens33

    # 虚拟路由标识,这个标识是一个数字,同一个vrrp实例使用唯一的标识。
    # 即同一vrrp_instance下,MASTER和BACKUP必须是一致的
    virtual_router_id 51

    # 定义优先级,数字越大,优先级越高(0-255)。
    # 在同一个vrrp_instance下,MASTER 的优先级必须大于 BACKUP 的优先级
    priority 100

    # 设定 MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位是秒
    advert_int 1

    # 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
    unicast_src_ip 192.168.66.11
    unicast_peer {
        192.168.66.12
    }

    # 设置验证类型和密码
    authentication {
        #设置验证类型,主要有PASS和AH两种
        auth_type PASS
        #设置验证密码,在同一个vrrp_instance下,MASTER与BACKUP必须使用相同的密码才能正常通信
        auth_pass 1111
    }

    #设置虚拟IP地址,可以设置多个虚拟IP地址,每行一个
    virtual_ipaddress {
        # 虚拟 IP
        192.168.66.100/24  // 如果两个nginx的ip分别是192.168.66.11,12,则此处的虚拟ip跟它俩同一个网段即可 24代表3个255的子网掩码
    }
}

# 虚拟服务器端口配置(以下配置根据实际情况配置)
virtual_server 192.168.66.100 80 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.66.11 80 {
        weight 1
    }
}

如果两台上联交换机禁了组播,就改用单播通告(unicast_src_ip / unicast_peer),同时注释掉 vrrp_strict。

主备两份配置

进配置目录先备份:

[root@load_balance-1 keepalived-2.0.20]# cd /usr/local/keepalived/
[root@load_balance-1 keepalived]# cd etc/keepalived/
[root@load_balance-1 keepalived]# cp keepalived.conf{,_bak}
[root@load_balance-1 keepalived]# ls
keepalived.conf  keepalived.conf_bak  samples

主机改法(router_id 用本机主机名、state MASTER、priority 100):

[root@load_balance-1 keepalived]# vim keepalived.conf
! 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 192.168.200.1
   smtp_connect_timeout 30
   router_id load_balance-1     //唯一值,一般为所在服务器的主机名
   vrrp_skip_check_adv_addr
   #vrrp_strict                 //注释该参数,如果开启了防火墙一定要注释
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER            //主为MASTER,备为BACKUP
    interface ens33         //绑定网卡,此处为网卡名称
    virtual_router_id 51    //主备Id必须一致,默认值51
    priority 100                //优先级,主必须大于备
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
       192.168.66.100/24      //虚拟IP地址,跟真实网卡同一网段即可,必须主备一致
    }
}

备机差异只在 state BACKUP、priority 90、router_id 换一个,virtual_router_id 和 VIP 与主机保持一致:

[root@load_balance-2 keepalived-2.0.20]# cd /usr/local/keepalived/
[root@load_balance-2 keepalived]# cd etc/keepalived/
[root@load_balance-2 keepalived]# cp keepalived.conf{,_bak}
[root@load_balance-2 keepalived]# ls
keepalived.conf  keepalived.conf_bak  samples

[root@load_balance-2 keepalived]# vim keepalived.conf
! 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 192.168.200.1
   smtp_connect_timeout 30
   router_id load_balance-2   //唯一值,一般为所在服务器的主机名
   vrrp_skip_check_adv_addr
   #vrrp_strict              //注释该参数,如果开启了防火墙一定要注释
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state BACKUP             //备为BACKUP
    interface ens33          //绑定的网卡名称
    virtual_router_id 51     //与主ID保持一致
    priority 90              //备的优先级低于主
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.66.100/24     //虚拟IP地址,与主保持一致
    }
}

防火墙与 SELINUX

Keepalived 的 VRRP 组播默认地址是 224.0.0.18,防火墙不放行的话主备互相看不见对方。主备都要执行:

[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

# 注意下面的网卡更改为自己服务器的真实网卡名称(更改前一定要确认自己服务器的网卡名称)
[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0  --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0  --out-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

[root@load_balance-1 ~]# firewall-cmd --reload
success

删策略把 --add-rule 换成 --remove-rule 再跑一遍。SELINUX 也一并关掉:

[root@load_balance-1 ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

[root@load_balance-1 ~]# setenforce 0
[root@load_balance-1 ~]# getenforce 
Permissive

Nginx 心跳联动

Nginx 挂了要让 VIP 自动漂走,思路是健康检查脚本发现 nginx 进程数为 0 就停掉 keepalived,同时调用推送脚本发告警(示例走企业微信机器人 webhook):

[root@load_balance-1 ~]# cd /script/
[root@load_balance-1 script]# vim check_nginx.sh
#!/bin/bash
network=`ifconfig ens33 |grep -w inet |awk '{print $2}'` &>/dev/null
nginx=`ps -C nginx --noheader|wc -l` &>/dev/null
if [ "$nginx" -eq 0 ];then
    #这里调用消息通知脚本,并配置需要发送的消息
    /script/qywx_nginx.py "主机:$(hostname)--主机IP:$network:Nginx服务心跳检测异常,请登入服务器查看;VIP已切换,请注意"
    systemctl stop keepalived.service
fi
#安装pip和request库
[root@load_balance-1 ~]# curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py   # 下载安装脚本

[root@load_balance-1 ~]# python get-pip.py
[root@load_balance-1 ~]# pip install requests

#这里我通过企业微信机器人的方式将Nginx健康检查的状态推送至企业微信
[root@load_balance-1 ~]# cd /script/
[root@load_balance-1 script]# vim qywx_nginx.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import json
import sys
import os

headers = {'Content-Type': 'application/json;charset=utf-8'}
api_url = "企业微信机器人的webhook地址"
def msg(text):
    json_text= {
     "msgtype": "text",
        "text": {
            "content": text
        },
    }
    print requests.post(api_url,json.dumps(json_text),headers=headers).content

if __name__ == '__main__':
    text = sys.argv[1]
    msg(text)

加执行权限、把两个脚本传到备机(备机同样要 chmod):

[root@load_balance-1 script]# chmod +x check_nginx.sh qywx_nginx.py
[root@load_balance-1 script]# scp check_nginx.sh root@192.168.66.12:/script/
[root@load_balance-1 script]# scp qywx_nginx.py root@192.168.66.12:/script/

#注意:备机将这2个脚本同样需要赋予执行权限

配置文件里挂上这个脚本:vrrp_script 段声明脚本路径和检测间隔(每 2 秒),vrrp_instance 里用 track_script 引用,名称必须和 vrrp_script 定义的一致:

[root@load_balance-1 ~]# cd /usr/local/keepalived/etc/keepalived/

[root@load_balance-1 keepalived]# vim keepalived.conf
! 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 192.168.200.1
   smtp_connect_timeout 30
   router_id load_balance-1		#每台主机该值必须唯一
   vrrp_skip_check_adv_addr
   # vrrp_strict        //注释该参数
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_script check_nginx {
    script "/bin/bash /script/check_nginx.sh"	#上面步骤中创建的Nginx健康检查脚本路径
    interval 2			#每隔2秒执行一次脚本
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
       192.168.66.100/24
    }
    track_script {   #调用脚本
       check_nginx   #这里的名称必须与vrrp_scrip写的保证一致
    }
}
image-602

改好的配置传给备机,备机同样加 vrrp_script 段,没有 Nginx 的机器不要加:

[root@load_balance-1 keepalived]#  scp keepalived.conf root@192.168.66.12:/usr/local/keepalived/etc/keepalived/

[root@load_balance-2 ~]# cd /usr/local/keepalived/etc/keepalived/
[root@load_balance-2 keepalived]# vim keepalived.conf
! 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 192.168.200.1
   smtp_connect_timeout 30
   router_id load_balance-2
   vrrp_skip_check_adv_addr
   # vrrp_strict         //注释该参数
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

#注意此处添加配合Nginx服务做健康检查,如果没有Nginx则无需添加
vrrp_script check_nginx {
    script "/bin/bash /script/check_nginx.sh"	#Nginx健康检查脚本路径
    interval 2			#每隔2秒执行一次脚本
}

vrrp_instance VI_1 {
state BACKUP
    interface ens33
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
	192.168.66.100/24
    }
    track_script {   #调用脚本
       check_nginx   #这里的名称必须与vrrp_scrip写的保证一致
    }
}

启动与验证

keepalived 默认读取 /etc/keepalived/keepalived.conf,把编译目录里的配置拷过去:

[root@load_balance-1 ~]# mkdir /etc/keepalived/
[root@load_balance-1 ~]# cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/

[root@load_balance-2 ~]# mkdir /etc/keepalived/
[root@load_balance-2 ~]# cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
[root@load_balance-1 ~]# systemctl start keepalived
[root@load_balance-1 ~]# systemctl enable keepalived
[root@load_balance-1 ~]# systemctl status keepalived

看 VIP 是否已经绑在主的网卡上:

[root@load_balance-1 ~]# ip a | grep ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 192.168.66.11/24 brd 192.168.66.255 scope global noprefixroute ens33
inet 192.168.66.100/24 scope global secondary ens33

验证漂移的三个动作:手动停 Nginx 触发健康脚本,看 VIP 是否漂到 BACKUP;MASTER 恢复后若没配非抢占模式,看 VIP 是否抢回来;配了 nopreempt 则 VIP 应留在 BACKUP。

三个常见问题

一、主备同时出现 VIP:用 tcpdump 能看到两台都在往 224.0.0.18 发包,说明备机收不到主机的 VRRP 广播,误判主机挂了。解法就是上面放通组播的策略,网卡名换成自己的真实网卡:

# 注意下面的网卡更改为自己服务器的真实网卡名称(更改前一定要确认自己服务器的网卡名称)
[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0  --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

[root@load_balance-1 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0  --out-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

[root@load_balance-1 ~]# firewall-cmd --reload
success

二、keepalived 起不来又没有错误日志:多半是配了健康检查脚本而对应服务(如 Nginx)根本没装,脚本一执行就 stop keepalived,形成“起不来”的假象,查 /var/log/messages 能对上时间线。

三、VIP ping 不通、关防火墙就正常:除了防火墙规则,还要检查配置里是否注释了 vrrp_strict,这个参数默认开启,开着防火墙就必须注释掉,主备都要改。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容