keepalived
VRRP: Virtual Routing Redundent Protocol
VRRPv2 VRRPv3
備份組中:有一個主,master,多個從, slave
master:
選舉協(xié)議:
一主多從:
備份組:
master, slave
在一個物理設(shè)備上,可以配置多個組,靠組ID區(qū)別不同的組
在同一個組內(nèi):
--enable-vrrp
--disable-snmp
vrrp_instance: 定義虛擬路由
MASTER|BACKUP
ipvsadm -A -t IP:port -s
keepalived:
ipvs --> HA
ipvs: --> VIP
vrrp:
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 2
# check every 2 seconds
weight -2
# if failed, decrease 2 of the priority
fall 2
# require 2 failures for failures
rise 1
# require 1 sucesses for ok
}
vrrp_script chk_name {
script ""
inerval #
weight #
fall 2
rise 1
}
track_script {
chk_schedown
}
標題:vip added to HA1
正文:日期 時間,HA1 's STATE from MASTER to BACKUP.
LAN客戶端判定哪個路由器應該為其到達目標主機的下一跳網(wǎng)關(guān)的方式有動態(tài)及靜態(tài)決策兩種方式,其中,覺的動態(tài)路由發(fā)現(xiàn)方式有如下幾種:
1、Proxy ARP —— 客戶端使用ARP協(xié)議獲取其想要到達的目標,而后,由某路由以其MAC地址響應此ARP請求;
2、Routing Protocol —— 客戶端監(jiān)聽動態(tài)路由更新(如通過RIP或OSPF協(xié)議)并以之重建自己的路由表;
3、ICMP IRDP (Router Discovery Protocol) 客戶端 —— 客戶端主機運行一個ICMP路由發(fā)現(xiàn)客戶端程序;
動態(tài)路由發(fā)現(xiàn)協(xié)議的不足之處在于它會導致在客戶端引起一定的配置和處理方面的開銷,并且,如果路由器故障,切換至其它路由器的過程會比較慢。解決此類問題的一個方案是為客戶端靜態(tài)配置默認路由設(shè)備,這大大簡化了客戶端的處理過程,但也會帶來單點故障類的問題。默認網(wǎng)關(guān)故障時,LAN客戶端僅能實現(xiàn)本地通信。
VRRP可以通過在一組路由器(一個VRRP組)之間共享一個虛擬IP(VIP)解決靜態(tài)配置的問題,此時僅需要客戶端以VIP作為其默認網(wǎng)關(guān)即可。
圖1顯示了一個基本的VLAN拓撲,其中,Router A、B、C共同組成一個VRRP組,其VIP為10.0.0.1,配置在路由器A的物理接口上,因此A為master路由器,B和C為backup路由器。VRRP組中,master(路由器A)負責負責轉(zhuǎn)發(fā)發(fā)往VIP地址的報文,客戶端1、2、3都以此VIP作為其默認網(wǎng)關(guān)。一旦master故障,backup路由器B和C中具有最高優(yōu)先級的路由器將成為master并接管VIP地址,而當原來的master路由器A重新上線時,其將重新成為master路由器。
VRRP是一個“選舉”協(xié)議,它能夠動態(tài)地將一個虛擬路由器的責任指定至同一個VRRP組中的其它路由器上,從而消除了靜態(tài)路由配置的單點故障。
VRRP術(shù)語:
VRRP虛擬路由(VRRP router):
VRRP的優(yōu)勢:
冗余:可以使用多個路由器設(shè)備作為LAN客戶端的默認網(wǎng)關(guān),大大降低了默認網(wǎng)關(guān)成為單點故障的可能性;
負載共享:允許來自LAN客戶端的流量由多個路由器設(shè)備所共享;
多VRRP組:在一個路由器物理接口上可配置多達255個VRRP組;
多IP地址:基于接口別名在同一個物理接口上配置多個IP地址,從而支持在同一個物理接口上接入多個子網(wǎng);
搶占:在master故障時允許優(yōu)先級更高的backup成為master;
通告協(xié)議:使用IANA所指定的組播地址224.0.0.18進行VRRP通告;
VRRP追蹤:基于接口狀態(tài)來改變其VRRP優(yōu)先級來確定最佳的VRRP路由器成為master;
配置keepalived為實現(xiàn)haproxy高可用的配置文件示例:
! Configuration File for keepalived
global_defs {
notification_email {
linuxedu@foxmail.com
Amd5@126.com
}
notification_email_from kanotify@magedu.com
smtp_connect_timeout 3
smtp_server 127.0.0.1
router_id LVS_DEVEL
}
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 1
weight 2
}
vrrp_script chk_mantaince_down {
script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
interval 1
weight 2
}
vrrp_instance VI_1 {
interface eth0
state MASTER # BACKUP for slave routers
priority 101 # 100 for BACKUP
virtual_router_id 51
garp_master_delay 1
authentication {
auth_type PASS
auth_pass password
}
track_interface {
eth0
}
virtual_ipaddress {
172.16.100.1/16 dev eth0 label eth0:0
}
track_script {
chk_haproxy
chk_mantaince_down
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
注意:
1、上面的state為當前節(jié)點的起始狀態(tài),通常在master/slave的雙節(jié)點模型中,其一個默認為MASTER,而別一個默認為BACKUP。
2、priority為當關(guān)節(jié)點在當前虛擬路由器中的優(yōu)先級,master的優(yōu)先級應該大于slave的;
下面是一個notify.sh腳本的簡單示例:
#!/bin/bash
# Author: Amd5 <linuxedu@foxmail.com>
# description: An example of notify script
#
vip=172.16.100.1
c>
Notify() {
mailsubject="`hostname` to be $1: $vip floating"
mailbody="`date '+%F %H:%M:%S'`: vrrp transition, `hostname` changed to be $1"
echo $mailbody | mail -s "$mailsubject" $contact
}
case "$1" in
master)
notify master
/etc/rc.d/init.d/haproxy start
exit 0
;;
backup)
notify backup
/etc/rc.d/init.d/haproxy restart
exit 0
;;
fault)
notify fault
exit 0
;;
*)
echo 'Usage: `basename $0` {master|backup|fault}'
exit 1
;;
esac
配置keepalived為實現(xiàn)haproxy高可用的雙主模型配置文件示例:
說明:其基本實現(xiàn)思想為創(chuàng)建兩個虛擬路由器,并以兩個節(jié)點互為主從。
! Configuration File for keepalived
global_defs {
notification_email {
linuxedu@foxmail.com
Amd5@126.com
}
notification_email_from kanotify@magedu.com
smtp_connect_timeout 3
smtp_server 127.0.0.1
router_id LVS_DEVEL
}
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 1
weight 2
}
vrrp_script chk_mantaince_down {
script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
interval 1
weight 2
}
vrrp_instance VI_1 {
interface eth0
state MASTER # BACKUP for slave routers
priority 101 # 100 for BACKUP
virtual_router_id 51
garp_master_delay 1
authentication {
auth_type PASS
auth_pass password
}
track_interface {
eth0
}
virtual_ipaddress {
172.16.100.1/16 dev eth0 label eth0:0
}
track_script {
chk_haproxy
chk_mantaince_down
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
vrrp_instance VI_2 {
interface eth0
state BACKUP # BACKUP for slave routers
priority 100 # 100 for BACKUP
virtual_router_id 52
garp_master_delay 1
authentication {
auth_type PASS
auth_pass password
}
track_interface {
eth0
}
virtual_ipaddress {
172.16.100.2/16 dev eth0 label eth0:1
}
track_script {
chk_haproxy
chk_mantaince_down
}
}
說明:
1、對于VI_1和VI_2來說,兩個節(jié)點要互為主從關(guān)系;
LVS + keepalived的實現(xiàn):
! Configuration File for keepalived
global_defs {
notification_email {
linuxedu@foxmail.com
Amd5@126.com
}
notification_email_from kanotify@magedu.com
smtp_connect_timeout 3
smtp_server 127.0.0.1
router_id LVS_DEVEL
}
vrrp_script chk_schedown {
script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
interval 2
weight -2
}
vrrp_instance VI_1 {
interface eth0
state MASTER
priority 101
virtual_router_id 51
garp_master_delay 1
authentication {
auth_type PASS
auth_pass password
}
track_interface {
eth0
}
virtual_ipaddress {
172.16.100.1/16 dev eth0 label eth0:0
}
track_script {
chk_schedown
}
}
virtual_server 172.16.100.1 80 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 50
protocol TCP
# sorry_server 192.168.200.200 1358
real_server 172.16.100.11 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
real_server 172.16.100.12 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
如果要使用TCP_CHECK檢測各realserver的健康狀態(tài),那么,上面關(guān)于realserver部分的定義也可以替換為如下內(nèi)容:
virtual_server 172.16.100.1 80 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 300
protocol TCP
sorry_server 127.0.0.1 80
real_server 172.16.100.11 80 {
weight 1
TCP_CHECK {
tcp_port 80
connect_timeout 3
}
}
real_server 172.16.100.12 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
說明:其中的sorry_server是用于定義所有realserver均出現(xiàn)故障時所用的服務器。
keepalived通知腳本進階示例:
下面的腳本可以接受選項,其中:
-s, --service SERVICE,...:指定服務腳本名稱,當狀態(tài)切換時可自動啟動、重啟或關(guān)閉此服務;
-a, --address VIP: 指定相關(guān)虛擬路由器的VIP地址;
-m, --mode {mm|mb}:指定虛擬路由的模型,mm表示主主,mb表示主備;它們表示相對于同一種服務而方,其VIP的工作類型;
-n, --notify {master|backup|fault}:指定通知的類型,即vrrp角色切換的目標角色;
-h, --help:獲取腳本的使用幫助;
#!/bin/bash
# Author: Amd5 <linuxedu@foxmail.com>
# description: An example of notify script
# Usage: notify.sh -m|--mode {mm|mb} -s|--service SERVICE1,... -a|--address VIP -n|--notify {master|backup|falut} -h|--help
#c>
helpflag=0
serviceflag=0
modeflag=0
addressflag=0
notifyflag=0
c>
Usage() {
echo "Usage: notify.sh [-m|--mode {mm|mb}] [-s|--service SERVICE1,...] <-a|--address VIP> <-n|--notify {master|backup|falut}>"
echo "Usage: notify.sh -h|--help"
}
ParseOptions() {
local I=1;
if [ $# -gt 0 ]; then
while [ $I -le $# ]; do
case $1 in
-s|--service)
[ $# -lt 2 ] && return 3
serviceflag=1
services=(`echo $2|awk -F"," '{for(i=1;i<=NF;i++) print $i}'`)
shift 2 ;;
-h|--help)
helpflag=1
return 0
shift
;;
-a|--address)
[ $# -lt 2 ] && return 3
addressflag=1
vip=$2
shift 2
;;
-m|--mode)
[ $# -lt 2 ] && return 3
mode=$2
shift 2
;;
-n|--notify)
[ $# -lt 2 ] && return 3
notifyflag=1
notify=$2
shift 2
;;
*)
echo "Wrong options..."
Usage
return 7
;;
esac
done
return 0
fi
}
#workspace=$(dirname $0)
RestartService() {
if [ ${#@} -gt 0 ]; then
for I in $@; do
if [ -x /etc/rc.d/init.d/$I ]; then
/etc/rc.d/init.d/$I restart
else
echo "$I is not a valid service..."
fi
done
fi
}
StopService() {
if [ ${#@} -gt 0 ]; then
for I in $@; do
if [ -x /etc/rc.d/init.d/$I ]; then
/etc/rc.d/init.d/$I stop
else
echo "$I is not a valid service..."
fi
done
fi
}
Notify() {
mailsubject="`hostname` to be $1: $vip floating"
mailbody="`date '+%F %H:%M:%S'`, vrrp transition, `hostname` changed to be $1."
echo $mailbody | mail -s "$mailsubject" $contact
}
# Main Function
ParseOptions $@
[ $? -ne 0 ] && Usage && exit 5
[ $helpflag -eq 1 ] && Usage && exit 0
if [ $addressflag -ne 1 -o $notifyflag -ne 1 ]; then
Usage
exit 2
fi
mode=${mode:-mb}
case $notify in
'master')
if [ $serviceflag -eq 1 ]; then
RestartService ${services[*]}
fi
Notify master
;;
'backup')
if [ $serviceflag -eq 1 ]; then
if [ "$mode" == 'mb' ]; then
StopService ${services[*]}
else
RestartService ${services[*]}
fi
fi
Notify backup
;;
'fault')
Notify fault
;;
*)
Usage
exit 4
;;
esac
在keepalived.conf配置文件中,其調(diào)用方法如下所示:
notify_master "/etc/keepalived/notify.sh -n master -a 172.16.100.1"
notify_backup "/etc/keepalived/notify.sh -n backup -a 172.16.100.1"
notify_fault "/etc/keepalived/notify.sh -n fault -a 172.16.100.1"