又拍雲之 Keepalived 高可用部署

在聊 Keepalived 之前,我們需要先簡單瞭解一下 VRRP。VRRP(Virtual Router Redundancy Protocol)即虛擬路由冗餘協議,是專門爲了解決靜態路由的高可用而設計的。

簡單說下它的工作原理:虛擬路由器由多個路由器組成,每個路由器都有各自的 IP 和共同的 VRID(0-255),其中一個 VRRP 路由器通過競選成爲 MASTER,就會接管 VIP(虛擬漂移IP),對外提供路由服務,其他成爲 BACKUP。MASTER 以 IP 組播形式發送 VRRP 協議包,與 BACKUP 保持心跳連接,若 MASTER 不可用,或 BACKUP 接收不到 VRRP 協議包,則 BACKUP 通過競選產生新的 MASTER,並繼續對外提供路由服務,從而實現高可用。

Keepalived 簡介

Keepalived 是一款基於 VRRP 協議的高可用軟件,藉助它可以讓多臺服務器能像路由器一樣做 VIP 虛擬地址的冗餘轉移,從而提升後端服務器的高可靠性。Keepalived 由一臺主服務器和多臺備份服務器組成集羣,在主服務器和備份服務器上部署相同的服務配置,並使用一個虛擬 IP 地址對外提供服務。當主服務器出現故障時,虛擬 IP 地址會自動漂移到備份服務器。

Keepalived+bfd 配置

VRRP v2 之前的版本雖然配置簡單,但只能提供秒級以上的檢測。這在十幾年前是可用的,但已經不適合現在的環境了。幸運的是,VRRP v2.0.5 加入了對 BFD 的支持。

雙向轉發檢測 BFD(Bidirectional Forwarding Detection)用於快速檢測系統之間的通信故障,並在出現故障時通知上層應用。

BFD 提供了一個與介質和協議無關的快速故障檢測機制,它具有以下優點:

  • 對網絡設備間任意類型的雙向轉發路徑提供快速、輕負荷的故障檢測。

  • 用單一的機制對任何介質、任何協議層進行實時檢測,並支持不同的檢測時間與開銷。

因此 VRRP v2 + BFD 得以實現毫秒級的檢測。我們可以選用新版本編譯測試 BFD,示例如下:

yum install -y libnl-devel
./configure --prefix=/opt/keepalived --enable-bfd  --with-init=system
! Configuration File for keepalived

global_defs {
   process_names keepalived_bfd
   bfd_process_name bfdp
   router_id LVS_UPYUN
}

bfd_instance bfdp {
     neighbor_ip 10.0.2.8 # 對端的服務器心跳ip
     source_ip 10.0.2.4   # 本地的服務器心跳ip
}

vrrp_instance VI_1 {
...
    track_bfd{
         bfdp weight 40  # 多跑一個bfd進程來監控心跳
    }
}

Keepalived+VRRP v3配置

隨着時間的推移,Keepalived 也支持了 VRRP v3 的協議。相較於之前版本的協議,VRRP v3 版本有以下改進:

  • 支持的網絡類型不同。VRRP v3 適用於 IPv4 和 IPv6 兩種網絡,而 VRRP v2 僅適用於 IPv4 網絡。

  • 認證功能不同。VRRP v3 不支持認證功能,而 VRRP v2 支持認證功能。VRRP v2 版本保留報文的認證字段,是爲了兼容早期版本,因爲 VRRP 認證並不能提高安全性。

  • 發送通告報文的時間間隔的單位不同。VRRP v2 中缺省單位爲 1 秒,VRRP v3 缺省單位爲 100 釐秒。

由於 VRRP v3 協議的改進,其不需要 BFD 也能實現 30ms 內的心跳檢測和故障轉移。那實踐中具體是如何配置的,我們重點來看一下。

! Configuration File for keepalived

global_defs {
   router_id SLB-SAD
   script_user root
   enable_script_security
   # 檢查vrrp報文中的所有地址比較耗時。默認是跳過檢查
   vrrp_skip_check_adv_addr
   # 重點是啓用vrrp3
   vrrp_version 3
}

vrrp_script chk_upyun {
   # 除了心跳檢測外,還可以調用腳本做業務上的健康檢測
   script       "/etc/keepalived/bin/check_vip.sh"
   interval 1   # check every 1 seconds
   fall   1     # require 2 failures for failures
   rise   1     # require 1 sucesses for ok
   # weight 值爲負數時,當腳本檢測失敗時,Master節點的權值將是“priority“值與“weight”值之差
   weight -30   
}


vrrp_instance upyun_lb {
    strict_mode off
    advert_int 0.03
    state BACKUP
    interface eth3
    virtual_router_id 19
    priority 100
    # 當master和backup角色轉換時,觸發腳本做業務上的切換
    notify "/etc/keepalived/bin/change_state.sh"

    track_script {
        chk_upyun
    }
    
    virtual_ipaddress {
        192.168.147.19 label eth3:9
    }
}
# 這一段是可選的,如果和lvs規則就可以調用ipvsadm的轉發規則
include /etc/keepalived/virserver.conf

配置中用到了“check_vip.sh”和“change_state.sh”的兩個腳本,我們也來簡單看下。

check_vip.sh

上面配置中只是舉例說明,當 ping 丟包嚴重超過 80% 時,就認爲要切換主備關係了。大家也可以根據具體的業務場景做一些邏輯判斷,來實現主備切換,以達到高可用的目的。

#!/bin/sh
TMP="/tmp/bad"

GATEWAY=$(ip ro|awk '/default/{print $3}')
LOSS=$(ping -fc10 -s1 $GATEWAY | sed -r -n '/loss/s@.* (.*)%.*@\1@p')
if [ $LOSS -ge 80 ];then
        echo "${LOSS}% lost  #`date`" >> $TMP
fi

if [ -e $TMP ] ;then
        exit 1
fi

change_state.sh

當檢測到服務器的角色轉換時,這個腳本就會調用釘釘報警,並且調整業務上的一些操作。如 sysctl.conf 配置或者 iptables 上的規則,甚至可以配合 LVS 做一些負載均衡的部署。

#!/bin/bash
HOME="/etc/keepalived/"
LIP=`/sbin/ip addr | awk '/192.168./{gsub("/.*","");if($2!=""){print $2}}'|sort -u|head -n1`
VIP=$(awk '/virtual_ipaddress/{getline; print $1}' $HOME/keepalived.conf)
URL="https://oapi.dingtalk.com/robot/send?access_token=07xxxxxxxxxxxxx"
[ -z $LIP ] && LIP=$VIP
############################################################################
dingding(){
  curl $URL --connect-timeout 10 -H 'Content-Type: application/json' \
     -d '{"msgtype": "markdown", 
          "markdown": {
          "title": "數據中心報警",
          "text": "* 報警類別: '"$1"'\n* 報警機器: '"$2"'\n* 報警服務: '"$3"'\n* 報警內容: '"$4"'\n* 報警時間: '"$(date "+%Y-%m-%d %T")"'\n"
        }
      }'
}

ENDSTATE=$3
NAME=$2
TYPE=$1
dingding Keepalived $LIP Change_state "$ENDSTATE"

case $ENDSTATE in
        "BACKUP") # Perform action for transition to BACKUP state
                echo "--- I am  $ENDSTATE #`date`" >> /tmp/keepalived.log
                sed -r -i '/state/s#MASTER#BACKUP#g' $HOME/keepalived.conf
                sysctl -w \
                        net.ipv4.conf.all.arp_accept=1 \
                        net.ipv4.conf.all.arp_ignore=0 \
                        net.ipv4.conf.all.arp_announce=0  \
                        net.ipv4.ip_nonlocal_bind=1
                #$HOME/tunl start
                exit 0
              ;;
        "FAULT")  # Perform action for transition to FAULT state
                exit 0
              ;;
        "MASTER") # Perform action for transition to MASTER state
                echo "+++ I am  $ENDSTATE #`date`" >> /tmp/keepalived.log
                sed -r -i '/state/s#BACKUP#MASTER#g' $HOME/keepalived.conf
                sysctl -w \
                        net.ipv4.conf.all.arp_ignore=1 \
                        net.ipv4.conf.all.arp_accept=1 \
                        net.ipv4.conf.all.arp_announce=1  \
                        net.ipv4.ip_nonlocal_bind=1

                iptables -L -vn | grep -iqE "vrrp|112"
                [ $? = 0 ] || iptables -I INPUT -p vrrp -j ACCEPT
                iptables -L -vn | grep -iq "accept .*$VIP"
                [ $? = 0 ] || iptables -I INPUT -d $VIP -j ACCEPT
                exit 0
              ;;
        *)
                echo "Unknown state ${ENDSTATE} for VRRP ${TYPE} ${NAME}"
                exit 1
              ;;
esac

今天的分享就到這了,感謝大家。

推薦閱讀

詳解 SSL(三):SSL 證書該如何選擇?

紅利風口下,企業出海如何強勢突圍?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章