1. 程式人生 > >使用Keepalived構建LVS高可用集群

使用Keepalived構建LVS高可用集群

local 郵件 address info ddr usr pin eth1 oop

LVS的DR模型配置+Keepalive部署


介紹

下圖為DR模型的通信過程,圖中的IP不要被撲結構中的IP迷惑,圖裏只是為了說明DR的通信原理,應用到本例中的拓撲上其工作原理不變。

技術分享圖片

拓撲結構

服務器 IP地址 角色
Srv01 172.16.42.100
VIP: 172.16.42.111
LVS+Keepalive
Srv02 172.16.42.101
VIP: 192.168.100.1
LVS+Keepalive
Srv03 172.16.42.102
VIP: 172.16.42.111
Nginx
Srv04 172.16.42.103
VIP: 172.16.42.111
Nginx

另外,我這4臺主機都是2個網卡, 其中有ens33是172.16.42.0/24這個網絡,ens34是192.168.100.0/24網絡,這個網絡在本例中沒有用,請忽略。

設置後端服務器

ARP的內核參數

由於LVS服務器和後端服務器的網卡上都配置了VIP,那麽當客戶端聯系VIP的時候肯定是和LVS服務器的VIP進行通信,然後由LVS服務器基於規則進行調度,我們知道2層通信是基於MAC地址的,那麽首次通信時客戶端可能並不知道LVS服務器的MAC地址,那麽就需要進行ARP廣播來解析出VIP所在的服務器的MAC地址,那麽顯然對客戶端進行ARP應答的只能是LVS服務器不能是後端服務器,所以我們就要在後端上修改內核參數來禁止ARP應答和宣告。那麽有2個內核參數表示這兩個設置:

arp_ignore:表示接收到ARP廣播時的響應級別,默認值為0

  • 0,默認值,表示響應所有,只要對方查詢的IP配置在我自己這臺主機上且無論ARP請求從哪個網卡進來,該主機都會響應

  • 1,收到該ARP請求的網卡IP與ARP請求的IP一致,該主機才響應

arp_announce:定義將自己的地址向外通告的級別,默認是0

  • 0,表示將本機所有的MAC地址都向外通告

  • 1,多網卡主機且都配置了IP地址,那麽該主機接入到網絡時,無論哪個網卡接入到網絡,該網卡都會向外宣告自己所有的MAC地址,所以1表示如果IP不在這個接口上,就避免向外通告,但是不保證一定不會下外通告。

  • 2,僅向網卡IP直連的網絡進行通告

為什麽會有這些級別呢?因為主機可以有多個網卡,每個網卡都對應一個網段,默認情況下這個多網卡主機只要接入網絡它就會把自己所在的所有網絡地址都向外進行通告。

所以對於後端服務器,也就是本例子中的Nginx,我們應該在lo上配置子接口,且設置arp_ignore為1,arp_announce為2。

設置後端服務器

後端服務器的所有操作都是一樣,我這裏就演示一臺。首先要保證2臺後端服務器都安裝了Nginx,我用Nginx只是為了後端提供一個Web服務而已,你使用Tomcat也是一樣的。

通過這個命令查看當前服務器設置sysctl -a | egrep "arp_ignore|arp_announce"

技術分享圖片

可以看到這裏每個網卡都有這2個參數還有一個All也有,那應該配置在哪裏呢?all表示全局,理論上來說在all上配置就可以,但是為了保險我們在ens33上也配置。

記住arp_announce配置為2;apr_ignore配置為1。

sysctl -w net.ipv4.conf.all.arp_announce=2
sysctl -w net.ipv4.conf.ens33.arp_announce=2

我使用sysctl -w來修改只是臨時生效,重啟就沒有了,為了永久有效請修改/etc/sysctl.conf文件。

技術分享圖片

現在在說以為什麽arp_announce配置為2,我這個主機有2個網卡,每個網卡所連接的是不同網段。我要使用的是ens33上面這個172.16.42.0/24這個網段,且VIP也是這個網段,當我把ens33的apr_announce配置為2 的時候,這就意味著當這個ens33接入網絡時它不會對外宣告ens34的網絡設置,也不會對外宣告lo的網絡設置(因為我們要在lo上配置一個子接口,該接口的IP就是VIP),下面配置apr_ignore

sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.ens33.arp_ignore=1

技術分享圖片

下面設置lo的子接口,這裏為什麽要32位呢?因為要把廣播地址設置為自己,這樣它的廣播就不會廣播到其他地方。

ifconfig lo:0 172.16.42.111 netmask 255.255.255.255 broadcast 172.16.42.111 up

技術分享圖片

下面我們在Srv01上ping一下這個地址,發現沒有人應答,所以ping不通。

技術分享圖片

接下來添加一條路由,其目的是由於後端服務器是直接應答客戶端請求的,所以就需要確保應答是其源IP一定是VIP(因為客戶端請求的就是VIP),但是當LVS修改完數據包發送給後端服務器時,使用的是後端服務器的真實IP地址進行通信的,而網絡通信是請求入棧是哪個接口,響應出棧還走哪個接口,這就勢必導致後端服務器會使用自己的真實IP而不是VIP對客戶端響應,這肯定是不對的,所以我們要通過這一條路由設置讓ens33網卡收到數據包後轉發給lo:0這個子接口,這樣響應出棧的時候就會經過lo:0,這樣也就會把響應報文的源IP設置為VIP了。

route add -host 172.16.42.111 dev lo:0

這條命令的含義是如果目標地址是172.16.42.111就要送到lo:0,這樣就保證了入棧經過lo:0,那麽出棧自然會經過。如果你不理解,那麽就要好好看看最上面的圖,二層通信是使用mac地址,而此時後端服務器收到這個數據包的時候,IP報文中源IP是客戶端的IP,而目標IP則是VIP,只是數據鏈路層報文mac地址信息被LVS替換了。

技術分享圖片

之後啟動後端服務的Nginx服務,兩臺後端服務器上都做上面的修改。

安裝keepalive

之間通過yum安裝即可yum install -y keepalived。我這裏使用的是阿裏雲的源,它默認就在裏面,如下圖:

技術分享圖片

在2個節點都安裝。

文件 說明
/usr/sbin/keepalived 二進制程序
/etc/keepalived/keepalived.conf 配置文件
/usr/lib/systemd/system/keepalived.service 服務文件

Keepalive配置文件說明


# 全局配置
global_defs {
   # 郵件通知信息
   notification_email {
     # 定義收件人
     [email protected]
   }
   # 定義發件人
   notification_email_from [email protected]
   # SMTP服務器地址
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   # 路由器標識,一般不用改,也可以寫成每個主機自己的主機名
   router_id LVS_DEVEL
   # VRRP的ipv4和ipv6的廣播地址,配置了VIP的網卡向這個地址廣播來宣告自己的配置信息,下面是默認值
   vrrp_mcast_group4 224.0.0.18
   vrrp_mcast_group6 ff02::12
}

# 定義用於實例執行的腳本內容,比如可以在線降低優先級,用於強制切換
vrrp_script SCRIPT_NAME {
  
}

# 一個vrrp_instance就是定義一個虛擬路由器的,實例名稱
vrrp_instance VI_1 {
    # 定義初始狀態,可以是MASTER或者BACKUP
    state MASTER
    # 工作接口,通告選舉使用哪個接口進行
    interface ens33
    # 虛擬路由ID,如果是一組虛擬路由就定義一個ID,如果是多組就要定義多個,而且這個虛擬
    # ID還是虛擬MAC最後一段地址的信息,取值範圍0-255
    virtual_router_id 51
    # 使用哪個虛擬MAC地址
    use_vmac XX:XX:XX:XX:XX
    # 監控本機上的哪個網卡,網卡一旦故障則需要把VIP轉移出去
    track_interface {
        eth0
        ens33
    }
    # 如果你上面定義了MASTER,這裏的優先級就需要定義的比其他的高
    priority 100
    # 通告頻率,單位為秒
    advert_int 1
    # 通信認證機制,這裏是明文認證還有一種是加密認證
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 設置虛擬VIP地址,一般就設置一個,在LVS中這個就是為LVS主機設置VIP的,這樣你就不用自己手動設置了
    virtual_ipaddress {
        # IP/掩碼 dev 配置在哪個網卡
        192.168.200.16/24 dev eth1
        # IP/掩碼 dev 配置在哪個網卡的哪個別名上
        192.168.200.17/24 dev label eth1:1
    }
    # 虛擬路由,在需要的情況下可以設置lvs主機 數據包在哪個網卡進來從哪個網卡出去
    virtual_routes {
        192.168.110.0/24 dev eth2
    }
    # 工作模式,nopreempt表示工作在非搶占模式,默認是搶占模式 preempt
    nopreempt|preempt
    # 如果是搶占默認則可以設置等多久再搶占,默認5分鐘
    preempt delay 300
    # 追蹤腳本,通常用於去執行上面的vrrp_script定義的腳本內容
    track_script {

    }
    # 三個指令,如果主機狀態變成Master|Backup|Fault之後會去執行的通知腳本,腳本要自己寫
    notify_master ""
    notify_backup ""
    notify_fault ""
}

# 定義LVS集群服務,可以是IP+PORT;也可以是fwmark 數字,也就是防火墻規則
# 所以通過這裏就可以看出來keepalive天生就是為ipvs而設計的
virtual_server 10.10.10.2 1358 {
    delay_loop 6
    # 算法
    lb_algo rr|wrr|lc|wlc|lblc|sh|dh 
    # LVS的模式
    lb_kind NAT|DR|TUN
    # 子網掩碼,這個掩碼是VIP的掩碼
    net_mask 255.255.255.0
    # 持久連接超時時間
    persistence_timeout 50
    # 定義協議
    protocol TCP
    # 如果後端應用服務器都不可用,就會定向到那個服務器上
    sorry_server 192.168.200.200 1358
    
    # 後端應用服務器 IP PORT
    real_server 192.168.200.2 1358 {
        # 權重
        weight 1
        # 應用服務器UP或者DOWN,就執行那個腳本
        notify_up "這裏寫的是路徑,如果腳本後有參數,整體路徑+參數引起來"
        notify_down "/PATH/SCRIPTS.sh 參數"

        # MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET這些都是
        # 針對應用服務器做健康檢查的方法
        MISC_CHECK {}
        # 用於檢查SMTP服務器的
        SMTP_CHEKC {}
        
        # 如果應用服務器不是WEB服務器,就用TCP_CHECK檢查
        TCP_CHECK {
          # 向哪一個端口檢查,如果不指定默認使用上面定義的端口
          connect_port <PORT>
          # 向哪一個IP檢測,如果不指定默認使用上面定義的IP地址
          bindto <IP>
          # 連接超時時間
          connect_timeout 3
        }
        
        # 如果對方是HTTPS服務器就用SSL_GET方法去檢查,裏面配置的內容和HTTP_GET一樣
        SSL_GET {}
        
        # 使用HTTP_GET方法去檢查
        HTTP_GET {
            # 檢測URL
            url { 
              # 具體檢測哪一個URL
              path /testurl/test.jsp
              # 檢測內容的哈希值,也就是網頁的md5值
              digest 640205b7b0fc66c1ea91c463fac6334d
              # 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
              status_code 200
            }
            url { 
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url { 
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            # 向哪一個端口檢查,如果不指定默認使用上面定義的端口
            connect_port <PORT>
            # 向哪一個IP檢測,如果不指定默認使用上面定義的IP地址
            bindto <IP>
            # 連接超時時間
            connect_timeout 3
            # 嘗試次數
            nb_get_retry 3
            # 每次嘗試之間間隔幾秒
            delay_before_retry 3
        }
    }

    real_server 192.168.200.3 1358 {
        weight 1
        HTTP_GET {
            url { 
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            url { 
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

配置Srv01和Srv02

配置VRRP部分

Srv01上的keepalived.conf

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id srv01
}


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 {
        172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
    }
    preempt delay 60
}

Srv02上的keepalived.conf,唯一不同的就是state、priority以及router_id。

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id srv02
}


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 {
        172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
    }
    preempt delay 60
}

啟動2個節點,啟動後會自動配置ens33:0這個子接口的虛擬IP

技術分享圖片

在主節點上你通過systemctl status keepalived看不到它到底是什麽角色,不過在BACKUP節點上你可以看到,但是你在主節點日誌中cat /var/log/message裏可以看到Srv01進入到MASTER狀態,如下圖:

技術分享圖片

查看Srv02的狀態

技術分享圖片

那麽你通過停止Srv01上的keepalived服務就看到MASTER會被轉移到Srv02上。

使用該命令查看VRRP通告tcpdum -i ens33 -nn host 224.0.0.18,你在2臺主機都會看到相同的信息。

技術分享圖片

Srv01使用真實物理IP對該地址進行發送通告,那麽Srv02也會收到,如果Srv01宕機,那麽Srv02就會使用自己的物理IP向該地址發送通告,由於Srv01已經宕機那麽此時Srv02的優先級就是最高的,所以Srv02就變成了MASTER。

配置LVS部分

在keepalived.conf文件中增加下面的內容,2臺服務器增加的內容一致,所以這裏就寫一份。

virtual_server 172.16.42.111 80 {
    delay_loop 6
    lb_algo rr
    lb_kind DR
    nat_mask 255.255.255.0
    persistence_timeout 0
    protocol TCP

    sorry_server 192.168.200.200 1358

    # 後端應用服務器 IP PORT
    real_server 172.16.42.102 80 {
        weight 1
        # 應用服務器UP或者DOWN,就執行那個腳本
        notify_up "/usr/local/notify.sh 172.16.42.102 up"
        notify_down "/usr/local/notify.sh 172.16.42.102 down"
        HTTP_GET {
            # 檢測URL
            url { 
              path /index.html
              # 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 172.16.42.103 80 {
        weight 1
        # 應用服務器UP或者DOWN,就執行那個腳本
        notify_up "/usr/local/notify.sh 172.16.42.103 up"
        notify_down "/usr/local/notify.sh 172.16.42.103 down"
        HTTP_GET {
            # 檢測URL
            url { 
              path /index.html
              # 除了檢測哈希值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

這裏的notify_up|down腳本我寫的很簡單就是為了使用一下這個功能,內容如下:

#!/bin/bash
if [ $2 == "up" ]; then
 echo "Real server ${1} is UP" > /tmp/notify.txt
elif [ $2 == "down" ]; then
 echo "Real server ${1} is DOWN" > /tmp/notify.txt
fi

重啟Keepalived服務之後你就可以通過ipvsadm -Ln查看ipvs規則了,這些規則在2臺服務器上都會有,如下圖:

技術分享圖片

測試訪問

使用下面的命令快速訪問for i in {1..20}; do curl http://172.16.42.111/ | grep "Srv0" --color ; done

技術分享圖片

可以看到2臺服務器交替,因為我們使用的rr調度算法。

故障轉移測試

連續訪問VIP,然後停止Srv01上面的keepalived服務,這就意味著Srv01也就是失去了VIP,然後觀察請求情況以及是否觸發之前設定的腳本。

技術分享圖片

查看Srv02上面的日誌

技術分享圖片

總結

為了提供一個Nginx或者某種後端服務器的負載均衡功能,那麽我們需要一個LVS來做調度,但是一臺LVS存在單點故障,為了解決LVS單點故障我們使用Keepalived來組建一個LVS的高可用集群。

使用Keepalived構建LVS高可用集群