首先需要明白我们准备使用keepalived来做什么,今天这里只是给大家简单安装和配置下keepalived实现vip对外服务,防止单点故障。keepalived是高可用高可用高可用 而非负载非负载非负载。

 下面我将使用keepalived部署双主模模式,实现方式,利用脚本检测某个服务,当服务宕机的时候,停止keepalived,vip漂移到另一个主机上。

  VIP1: 192.168.80.136 eth0:10.0.0.11 em1:10.0.0.67 

  VIP2: 192.168.80.139 eth1:10.0.0.12 em2:10.0.0.68 #vip/主机1网卡对应ip/主机2对应网卡ip

1.安装keepalived

yum install -y glibc openssl-devel
wget http://www.keepalived.org/software/keepalived-1.2.24.tar.gz 
tar zxf keepalived-1.2.24.tar.gz
cd keepalived-1.2.24
mkdir /usr/local/keepalived
./configure --prefix=/usr/local/keepalived && make && make install

 2.将keepalived配置为系统服务

mkdir /etc/keepalived
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/keepalived
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived
chmod +x /etc/init.d/keepalived
ln /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived 
chkconfig --add keepalived

3.配置keepalived服务

cd /etc/keepalived/

cat keepalived.conf (主机1配置)

! Configuration File for keepalived
global_defs {
   router_id NODE_B
}
vrrp_script checkALL {
   script "/etc/keepalived/script/check_nginx.sh"  #检测nginx服务脚本       
   interval 5
}
vrrp_instance VIP136 {
    state MASTER #VIP1的master 主机2的时候改为BACKUP
    interface eth0
    mcast_src_ip 10.0.0.11
    virtual_router_id 136  #虚拟路由id 2个主机需要一样              
    priority 100  #优先级 数值越大优先级越大,第二个主机设置比她它小
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass masterbrian  #双方认证使用的密码
    }
    virtual_ipaddress {
        192.168.80.136  #vip1虚拟ip
    }
    track_script {
        checkALL #检测脚本
}
    notify_master "/etc/keepalived/script/notify.sh master 10.0.0.11 192.168.80.136" #变为主的时候触发的脚本
    notify_backup "/etc/keepalived/script/notify.sh backup 10.0.0.11 192.168.80.136"
    notify_fault "/etc/keepalived/script/notify.sh fault 10.0.0.11 192.168.80.136"
}
vrrp_instance VIP139 {
   state BACKUP #VIP2的slave  主机改为MASTER
   nopreempt  #备机不抢占模式,当备机的优先级高于主机的时候不抢占
   interface eth1
   mcast_src_ip 10.0.0.12
   virtual_router_id 139
   priority 90
   advert_int 1
   authentication {
        auth_type PASS
        auth_pass masterrobinson
        }
   virtual_ipaddress {
        192.168.80.139
        }
    track_script {
        checkALL
}
    notify_master "/etc/keepalived/script/notify.sh master 10.0.0.12 192.168.80.139"
    notify_backup "/etc/keepalived/script/notify.sh backup 10.0.0.12 192.168.80.139"
    notify_fault "/etc/keepalived/script/notify.sh fault 10.0.0.12 192.168.80.139"
}


cat keepalived.conf (主机2配置) 

! Configuration File for keepalived
global_defs {
   router_id LVS_DEVEL
}
vrrp_script checkALL {
   script "/etc/keepalived/script/check_nginx.sh"
   interval 5
}
vrrp_instance VIP136 {
    state BACKUP
    interface em1
    nopreempt
    mcast_src_ip 10.0.0.67
    virtual_router_id 136
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass masterbrian
    }
    virtual_ipaddress {
        192.168.80.136
    }
    track_script {
        checkALL
}
    notify_master "/etc/keepalived/script/notify.sh master 10.0.0.67 192.168.80.136"
    notify_backup "/etc/keepalived/script/notify.sh backup 10.0.0.67 192.168.80.136"
    notify_fault "/etc/keepalived/script/notify.sh fault 10.0.0.67 192.168.80.136"
}
vrrp_instance VIP139 {
   state MASTER
   interface em2
   mcast_src_ip 10.0.0.68
   virtual_router_id 139
   priority 100
   advert_int 1
   authentication {
        auth_type PASS
        auth_pass masterrobinson
        }
   virtual_ipaddress {
        192.168.80.139
        }
    track_script {
        checkALL
}
    notify_master "/etc/keepalived/script/notify.sh master 10.0.0.68 192.168.80.139"
    notify_backup "/etc/keepalived/script/notify.sh backup 10.0.0.68 192.168.80.139"
    notify_fault "/etc/keepalived/script/notify.sh fault 10.0.0.68 192.168.80.139"
}

4.使用到的其他脚本文件

  4.1监控nginx服务脚本,当nginx服务不存在的时候停止keepalived服务

  这个脚本可以根需要使用高可用的服务来做相应的调整。

  cat /etc/keepalived/script/check_nginx.sh

#!/bin/bash 
checknginx=$(ps -C nginx --no-header | wc -l)
checkkeepalived=$(ps -C keepalived --no-header | wc -l)
TIME=$(date +%Y-%m-%d\ %H:%M:%S)
if [ ${checknginx} -eq 0 ];then
   service nginx restart 
   sleep 3
fi
checknginx_two=$(ps -C nginx --no-header | wc -l) 
if [ ${checknginx_two} -eq 0 ];then
   killall -TERM keepalived
fi

  4.2状态变化的时候的触发的脚本

  cat /etc/keepalived/script/notify.sh

#!/bin/bash
status=${1}
hostip=${2}
vip=${3}
TIME=$(date +%Y-%m-%d\ %H:%M:%S)
HOST_NAME=$(hostname)
subject="${HOST_NAME} to be ${status}: ${vip} floating"
send_user="xxxxx"
send_contant="${TIME} ${HOST_NAME}[${hostip}] 主机keepalived的VIP:${vip} 状态改变为${status},请检查相关服务。"
python /etc/keepalived/script/send_mail.py "${send_user}" "${subject}" "${send_contant}"

  4.3 notify.sh中触发的发送邮件的python脚本

这个脚本最下面需要修改 用户名和密码,邮件服务器和收件人等相关信息

cat /etc/keepalived/script/send_mail.py

#!/usr/bin/env python 
# -*- coding:utf-8 -*-
"""
纯文本文件发送
"""
import sys
import smtplib
from email.header import Header
from email.mime.text import MIMEText 
from abc import abstractmethod
class  Mail(object):
    """dohost, user_name, pwd, context, Subject, To, filename, file_path, port, nick_name, mail_adressring for  Mail"""
    def __init__(self, host, user_name, pwd, context, Subject, To, port, nick_name, mail_adress):
        """
        :param host: 邮件服务器地址
        :param user_name: 邮件登陆名
        :param pwd: 邮箱登陆密码
        :param context: 邮箱正文
        :param Subject: 邮箱主题
        :param To: 收件人
        :param From: 发件人
        """
        self.host=host
        self.user_name=user_name
        self.pwd=pwd
        self.context=context
        self.Subject=Subject
        self.To=To
        self.port=port
        self.nick_name=nick_name
        self.mail_adress=mail_adress    
    @abstractmethod
    def send(self,**kwargs):
        """
        send mail to account 
        :param file:
        :return:
        """
        pass
class TextMail(Mail):
    """
    只有文本信息的邮件
    """
    def __init__(self,**kwargs):
        super(TextMail,self).__init__(**kwargs)
        self.mail_type='TEXT'
    @abstractmethod
    def send(self):
        #print("send_start")
        server=smtplib.SMTP(self.host,self.port)
        server.set_debuglevel(0)
        server.login(self.user_name,self.pwd)
        msg=MIMEText(self.context,'html','utf-8')
        msg['From']='{0}<{1}>'.format(self.nick_name,self.mail_adress,'utf-8')
        msg['Subject']=Header(self.Subject,'utf-8').encode()
        msg['To']=','.join(self.To)
        try:
            server.sendmail(self.mail_adress,self.To,msg.as_string())
            print("mail has been successfully")
        except smtplib.SMTPException as e:
            print('邮件发送失败')
            print(e)
def send_mail(fromstmp,fromuser,frompwd,content,subject,touser):
    host=fromstmp
    fromuser=fromuser
    pwd=frompwd
    scontent=content
    subject=subject
    touser=touser
    nick_name="运维监控"    
    b=TextMail(host=host,user_name=fromuser,pwd=pwd,context=content,Subject=subject,To=touser,port=25,nick_name=nick_name,mail_adress=fromuser)
    b.send()
if __name__ == '__main__':
    """
    设置发送邮箱信息
    """
    fromuser="XXX"  #发送邮箱的 123456@qq.com
    frompwd="XXX"   #邮箱密码 xxxx
    fromstmp="XXX"  #邮件服务stmp smtp.qq.com
    touser = [str(sys.argv[1])]  #传过来的第一个参数
    subject = str(sys.argv[2])  #传过来的第二个参数
    content = str(sys.argv[3])  #传过来的第三个参数
    touser='xxx@126.com','xxxx@123.com' #收邮件的人
    send_mail(fromstmp,fromuser,frompwd,content,subject,touser)