[CentOS6][IPVS+Keepalived] LVS(NAT)のロードバランサをVRRP方式で冗長化する


Create: 2014/10/10
LastUpdate: 2014/10/11

LVS を Keepalived の VRRP方式で冗長化してみます。
Keepalived を VRRP方式で冗長化する方法については以下のサイトが参考になります。

シナリオ 


ここでは、次の機能をもったLVSサーバを構築して冗長化してみます。
  1. web01、web02 にヘルスチェックを行いHTTPを負荷分散する。(IPVS+Keepalivedで実装)
  2. web01、web02 へDNATして、192.168.1.0/24 側から SSH できるようにする。(iptablesで実装)
  3. web01、web02 が、192.168.1.0/24側 にアクセスできるようにIPマスカレードする。(iptablesで実装)
下図のようなLVS01とLVS02のアクティブ/スタンバイ構成とし、通常時はLVS01を使用します。
赤字で示したIPアドレスは仮想IPです。web01、web02 の利用者は仮想IPを使用します。



障害時は、仮想IPをLVS02 付け替えて、LVS02を使用します。
web01、web02の利用者が、この仮想IPを使用していれば、LVS01 ダウンの影響をなるべくうけずに、LVS02経由でweb01、web02 を利用できるようにします。
障害の検知と仮想IPの付け替えは、Keepalived が自動的に行います。



IPVS+Keepalived の設定


今回は、keepalived.conf を以下のようにし、LVS01 と LVS02 は同じ設定にします。
赤字部分が、VRRPで冗長化する設定です。
virtual_server では、ヘルスチェックと負荷分散の設定をしています。LVS(NAT)でweb01、web02にヘルスチェックして負荷分散する手順については、「 [CentOS6][IPVS+Keepalived] 異なるサブネットでWEBサーバの負荷分散(NAT)」 を参考にしてください。
! 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 LVS
}

vrrp_instance VI_EXT {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 101
    nopreempt
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.90/24 dev eth0
        192.168.1.93/24 dev eth0
        192.168.1.94/24 dev eth0
    }
}

vrrp_instance VI_INT {
    state BACKUP
    interface eth1
    virtual_router_id 52
    priority 101
    nopreempt
    advert_int 1
    authentication {
      auth_type PASS
      auth_pass 1111
    }
    virtual_ipaddress {
      10.0.0.90/24 dev eth1
    }
}

vrrp_sync_group VG {
  group {
    VI_EXT
    VI_INT
  }
}

virtual_server 192.168.1.90 80 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    !nat_mask 255.255.255.0
    !persistence_timeout 50
    protocol TCP

    real_server 10.0.0.93 80 {
        weight 10
        inhibit_on_failure
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            !nb_get_retry 3
            !delay_before_retry 3
        }
    }

    real_server 10.0.0.94 80 {
        weight 10
        inhibit_on_failure
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            !nb_get_retry 3
            !delay_before_retry 3
        }
    }
}

vrrp_instance の VI_EXT では、 eth0 のVRRPと仮想IPアドレスを設定しています。
vrrp_instance の VI_INT では、と eth1 のVRRPと仮想IPアドレスを設定しています。
vrrp_sync_group で VI_EXT と VI_INT をまとめて、eth0 もしくは eth1 のどちらかが切れた場合でも、両方のインスタンスが同時に切り替わるようにしています。
つまりLVS01 の eth0 または eth1 がダウンしたら、LVS02 に切り替わります。
state BACKUP と nopreempt を指定すると、すでにマスターが稼働していた場合、自分のプライオリティ設定が相手よりも高くてもマスターへ昇格しないようになります。
つまり、LVS01 と LVS02 は、先に起動したほうがマスターになります。また、LVS01がダウンして LVS02がマスターに昇格後、LVS01 を正常にアップしても LVS01 はマスターに昇格しません。

IPマスカレードとDNAT の設定


IPマスカレードとDNATの設定は LVS01 と LVS02 に設定し、設定内容は同じにします。
iptables の設定手順は、「 [TIPS][CentOS 6] iptables で IPマスカレード と DNAT を設定する」 を参照してください。
10.0.0.0/24 側から見て出口となる eth0 に IPマスカレードを設定します。
192.168.1.93 宛ての通信は、10.0.0.93 (web01) に転送するように DNAT します。
192.168.1.94 宛ての通信は、10.0.0.94 (web02) に転送するように DNAT します。
LVS01 と LVS02 で iptables の設定を確認すると以下のとおり。
# service iptables status
テーブル: nat
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    DNAT       all  --  0.0.0.0/0            192.168.1.93        to:10.0.0.93
2    DNAT       all  --  0.0.0.0/0            192.168.1.94        to:10.0.0.94

Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    MASQUERADE  all  --  10.0.0.0/24          0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

web01 と web02 のデフォルトゲートウェイの設定


web01 と web02 はデフォルトゲートウェイを LVSサーバの仮想IP( 10.0.0.90 )にします。
仮想IPを指定することで、LVS01からLVS02に切り替わっても、設定変更なしで通信できるようにします。
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
0.0.0.0         10.0.0.90       0.0.0.0         UG    0      0        0 eth0


Keepalived 冗長化の動作確認


LVS01 をマスタにしたいので、LVS01 の keepalived を起動し、次に、LVS02 の keepalived を起動します。
# service keepalived start
LVS01 で IPVS の状態を確認します。Weightが 0 でなければヘルスチェックOKで、負荷分散が可能な状態です。
# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.90:80 rr
  -> 10.0.0.93:80                 Masq    10     0          0
  -> 10.0.0.94:80                 Masq    10     0          0

LVS01 の仮想IPアドレスを確認します。
Keppalived で設定する仮想IPアドレスは、ifconfig コマンドでは確認できないので ip コマンドを使用します。
LVS01 がマスタであれば、仮想IPアドレスを見ることができます。
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether fa:f3:b1:c6:82:41 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.91/24 brd 192.168.1.255 scope global eth0
    inet 192.168.1.90/24 scope global secondary eth0
    inet 192.168.1.93/24 scope global secondary eth0
    inet 192.168.1.94/24 scope global secondary eth0
    inet6 2001:c90:8023:a9d1:f8f3:b1ff:fec6:8241/64 scope global dynamic
       valid_lft 2591993sec preferred_lft 604793sec
    inet6 fe80::f8f3:b1ff:fec6:8241/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether b2:40:a2:1e:65:83 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.91/24 brd 10.0.0.255 scope global eth1
    inet 10.0.0.90/24 scope global secondary eth1
    inet6 fe80::b040:a2ff:fe1e:6583/64 scope link
       valid_lft forever preferred_lft forever

Keepalived のログが /var/log/messages に出力されるので、STATE を確認してみます。
LVS01で以下のようにコマンドを実行して、最終行が MASTER であれば、LVS01 がマスタです。
# egrep "Keepalived.* STATE" /var/log/messages | tail
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Transition to MASTER STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Group(VG) Syncing instances to MASTER state
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Transition to MASTER STATE
Oct 11 09:54:10 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering MASTER STATE
Oct 11 09:54:13 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering MASTER STATE

LVS02 も確認してみます。
以下の例では、IPVSは問題ありません。LVS02のヘルスチェックもOKです。
仮想IPアドレスは表示されず、ログの STATE からもLVS02 がバックアップであることが確認できます。
# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.90:80 rr
  -> 10.0.0.93:80                 Masq    10     0          0
  -> 10.0.0.94:80                 Masq    10     0          0
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 72:87:6b:c0:29:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.92/24 brd 192.168.1.255 scope global eth0
    inet6 2001:c90:8023:a9d1:7087:6bff:fec0:291f/64 scope global dynamic
       valid_lft 2591828sec preferred_lft 604628sec
    inet6 fe80::7087:6bff:fec0:291f/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 2a:93:94:eb:17:ae brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.92/24 brd 10.0.0.255 scope global eth1
    inet6 fe80::2893:94ff:feeb:17ae/64 scope link
       valid_lft forever preferred_lft forever
# egrep "Keepalived.* STATE" /var/log/messages | tail
Oct 11 09:54:46 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 09:54:46 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE


LVS01 のeth1 をダウンして、LVS02 に切り替えてみます。
以下のようにして LVS01 の eth1 をダウンします。
# ifdown eth1
LVS01 の状態を確認してみると、eth1  DOWN して、仮想IPも削除されています。
Keepalived の STATE は "FAULT" と表示されます。
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether fa:f3:b1:c6:82:41 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.91/24 brd 192.168.1.255 scope global eth0
    inet6 2001:c90:8023:a9d1:f8f3:b1ff:fec6:8241/64 scope global dynamic
       valid_lft 2591856sec preferred_lft 604656sec
    inet6 fe80::f8f3:b1ff:fec6:8241/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
    link/ether b2:40:a2:1e:65:83 brd ff:ff:ff:ff:ff:ff
# egrep "Keepalived.* STATE" /var/log/messages | tail
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Transition to MASTER STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Transition to MASTER STATE
Oct 11 09:54:10 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering MASTER STATE
Oct 11 09:54:13 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering MASTER STATE
Oct 11 18:21:20 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering FAULT STATE
Oct 11 18:21:21 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering FAULT STATE

LVS02 の状態を見ると、仮想IPが追加されて、Keepalived  の STATE は "MASTER" になっています。
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 72:87:6b:c0:29:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.92/24 brd 192.168.1.255 scope global eth0
    inet 192.168.1.90/24 scope global secondary eth0
    inet 192.168.1.93/24 scope global secondary eth0
    inet 192.168.1.94/24 scope global secondary eth0
    inet6 2001:c90:8023:a9d1:7087:6bff:fec0:291f/64 scope global dynamic
       valid_lft 2591863sec preferred_lft 604663sec
    inet6 fe80::7087:6bff:fec0:291f/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 2a:93:94:eb:17:ae brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.92/24 brd 10.0.0.255 scope global eth1
    inet 10.0.0.90/24 scope global secondary eth1
    inet6 fe80::2893:94ff:feeb:17ae/64 scope link
       valid_lft forever preferred_lft forever
# egrep "Keepalived.* STATE" /var/log/messages | tail
Oct 11 09:54:46 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 09:54:46 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE
Oct 11 18:21:24 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Transition to MASTER STATE
Oct 11 18:21:24 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Transition to MASTER STATE
Oct 11 18:21:25 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering MASTER STATE
Oct 11 18:21:26 exlb02 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering MASTER STATE


LVS01 の eth1 を UP してみます。
# ifup eth1
LVS01 の状態は以下のとおり。eth1 は正常に戻りましたが、Keepalived の STATE は "BACKUP" です。
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether fa:f3:b1:c6:82:41 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.91/24 brd 192.168.1.255 scope global eth0
    inet6 2001:c90:8023:a9d1:f8f3:b1ff:fec6:8241/64 scope global dynamic
       valid_lft 2591893sec preferred_lft 604693sec
    inet6 fe80::f8f3:b1ff:fec6:8241/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether b2:40:a2:1e:65:83 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.91/24 brd 10.0.0.255 scope global eth1
    inet6 fe80::b040:a2ff:fe1e:6583/64 scope link
       valid_lft forever preferred_lft forever
# egrep "Keepalived.* STATE" /var/log/messages | tail
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 09:54:06 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Transition to MASTER STATE
Oct 11 09:54:09 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Transition to MASTER STATE
Oct 11 09:54:10 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering MASTER STATE
Oct 11 09:54:13 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering MASTER STATE
Oct 11 18:21:20 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering FAULT STATE
Oct 11 18:21:21 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering FAULT STATE
Oct 11 18:32:19 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_EXT) Entering BACKUP STATE
Oct 11 18:32:19 exlb01 Keepalived_vrrp[975]: VRRP_Instance(VI_INT) Entering BACKUP STATE