LVS環境構築

はじめに

centos5.6で、LVS環境を構築する。
環境構成は、以下の通り。LVSはNATではなく、DSRで稼働させる。

                         -------------
      -------------------|client(AWS)|
      |                  -------------
  Global IP1               Global IP2
  ~~~~~~~~~~
   Internet
  ~~~~~~~~~~
      |
  --------
  |router|
  --------
      |
      -------------------------------------------------------------
      |                   |             |            |            |
      ---VIP:192.168.1.30--             |            |            |
      |                   |             |            |            |
192.168.1.22        192.168.1.23  192.168.1.20  192.168.1.21  192.168.1.18
  --------            --------      --------     --------      --------
  | LVS1 | -- VRRP -- | LVS2 |      | web1 |     | web2 |      | sorry |
  --------            --------      --------     --------      --------

web/sorryサーバには、それぞれ以下の文字列を表示するページを用意しておく。
web1 : test1
web2 : test2
sorry: sorry
また、web1,2のヘルスチェック用に /health.cgi ページを用意しておく(status code 200を返すだけ)。

LVS1,2 環境構築

パッケージインストール

LVS1,2サーバに、それぞれパッケージをインストール


# rpm -ivh /usr/local/src/ipvsadm-1.24-6.x86_64.rpm
# rpm -ivh /usr/local/src/keepalived-1.2.1-5.x86_64.rpm

ip_foward設定

LVSからwebサーバへのIPv4転送を有効にするため、net.ipv4.ip_forward パラメータを変更(0 -> 1)し、設定反映する。


# vim /etc/sysctl.conf
 - net.ipv4.ip_forward = 0
 + net.ipv4.ip_forward = 1

# sysctl -p

rp_filter設定

今回構築している環境では、Interfaceが1つのみなので、rp_filterは有効(1)にしたままにしている。

もし、Interfaceが追加されて、外(eth1)/内(eth0)の2枚環境になるようであれば、
以下の設定をすれば良いと思う。


# vim /etc/sysctl.conf
 + net.ipv4.conf.eth0.rp_filter = 0

# sysctl -p

keepalived.conf設定

LVSの冗長性を確保するためのkeepalivedを利用する。
keepalivedのパラメータ設定として、keepalived.confを設定する。
ここでは、メール通知設定などは省略する。
※本番運用であれば欠かせないと思いますが。
各パラメータの意味は、下記サイトや「24時間365日 サーバ/インフラを支える技術」などを参考に。
LVSを使ったブローカーの構築:「keepalived.conf」についての説明
本家サイトのUserGuide

virtual_server_group HTTP100 {
  192.168.1.30 80
}

virtual_server group HTTP100 {
  delay_loop   3
  lvs_sched    lc
  lvs_method   DR
  protocol     TCP

  virtualhost  www.example.org

  sorry_server 192.168.1.18  80

  # web1
  real_server  192.168.1.20 80 {
    weight 1
    inhibit_on_failure

    # health check
    HTTP_GET {
      url {
        path /health.cgi
        status_code 200
      }
      connect_timeout 3
    }
  }
  # web2
  real_server 192.168.1.21 80 {
    weight 1
    inhibit_on_failure

    # health check
    HTTP_GET {
      url {
        path /health.cgi
        status_code 200
      }
      connect_timeout 3
    }
  }

}

# VRRP
vrrp_instance VI {
  state BACKUP
  interface eth0
  garp_master_delay 5
  virtual_router_id 1
  priority 101
  nopreempt
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass himitsu
  }
  virtual_ipaddress {
    192.168.1.30/24  dev eth0
  }
}
virtual_server_group HTTP100 {
  192.168.1.30  80
}

virtual_server group HTTP100 {
  delay_loop   3
  lvs_sched    lc
  lvs_method   DR
  protocol     TCP

  virtualhost  www.example.org

  sorry_server 192.168.1.18  80

  # web1
  real_server  192.168.1.20 80 {
    weight 1
    inhibit_on_failure

    # health check
    HTTP_GET {
      url {
        path /health.cgi
        status_code 200
      }
      connect_timeout 3
    }
  }
  # web2
  real_server  192.168.1.21 80 {
    weight 1
    inhibit_on_failure
    HTTP_GET {
      url {
        path /health.cgi
        status_code 200
      }
      connect_timeout    3
    }
  }

}

# VRRP
vrrp_instance VI {
  state BACKUP
  interface eth0
  garp_master_delay 5
  virtual_router_id 1
  priority 100
  nopreempt
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass himitsu
  }
  virtual_ipaddress {
    192.168.1.30/24  dev eth0
  }
}

web1,2、sorry 環境構築

iptables設定

webサーバ側では、VRRPで指定した仮想IP(192.168.1.30)は直接持たず、
iptablesによるアドレス変換(DNAT)で処理させる。


# iptables -t nat -L
 Chain PREROUTING (policy ACCEPT)
 target prot opt source destination
 
 Chain POSTROUTING (policy ACCEPT)
 target prot opt source destination
 
 Chain OUTPUT (policy ACCEPT)
 target prot opt source destination
#

# iptables -t nat -A PREROUTING -d 192.168.1.30 -j REDIRECT
# /etc/init.d/iptables save

# iptables -t nat -L
 Chain PREROUTING (policy ACCEPT)
 target prot opt source destination
 REDIRECT all -- anywhere 192.168.1.30
 
 Chain POSTROUTING (policy ACCEPT)
 target prot opt source destination
 
 Chain OUTPUT (policy ACCEPT)
 target prot opt source destination
#

# /etc/init.d/iptables restart

LVS環境起動

LVS1,2でkeepalivedを起動し、動作確認を行う。
まずは、LVS1をmaster、LVS2をbackup環境として稼働させる。

keepalived起動
  • LVS1 作業

masterとなる LVS1 からkeepalivedを起動する。


# /etc/init.d/keepalived start
# tail /var/log/messages
 〜
 Keepalived_vrrp: VRRP_Instance(VI) Transition to MASTER STATE
 Keepalived_vrrp: VRRP_Instance(VI) Entering MASTER STATE
 Keepalived_vrrp: VRRP_Instance(VI) setting protocol VIPs.
 Keepalived_vrrp: VRRP_Instance(VI) Sending gratuitous ARPs on eth0 for 192.168.1.30
 Keepalived_vrrp: Netlink reflector reports IP 192.168.1.22 added
 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.1.22 added
 avahi-daemon[3291]: Registering new address record for 192.168.1.30 on eth0.
 Keepalived_vrrp: VRRP_Instance(VI) Sending gratuitous ARPs on eth0 for 192.168.1.30
#
MASTERとして起動し、仮想IPが設定されたことが分かる。
実際にipコマンドで仮想IPが設定されているか確認する。


# ip addr show dev eth0
 2: eth0: mtu 1500 qdisc pfifo_fast qlen 1000
  link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
  inet 192.168.1.22/24 brd 192.168.1.255 scope global eth0
  inet 192.168.1.30/24 scope global secondary eth0
#
仮想IP(192.168.1.30)が設定されている事が分かる。

  • LVS2 作業

次にbackupとなる LVS2 のkeepalivedを起動する。


# /etc/init.d/keepalived start
# tail /var/log/messages
 〜
 Keepalived_vrrp: VRRP_Instance(VI) Entering BACKUP STATE
 Keepalived_vrrp: VRRP sockpool: [ifindex(2), proto(112), fd(11,12)]
#
backupとして起動し、仮想IPが設定されたことが分かる。
ipコマンドで仮想IPが設定されて"いない"事を確認する。


# ip addr show dev eth0
 2: eth0: mtu 1500 qdisc pfifo_fast qlen 1000
  link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
  inet 192.168.1.23/24 brd 192.168.1.255 scope global eth0
#
仮想IP(192.168.1.30)が設定されて"いない"事が確認できた。

動作確認

ここまでで、LVS環境の構築ができたので、クライアント環境からHTTPリクエストを投げて
LVS環境を通し、分散/冗長されているか動作確認する。

パターン1:正常系

master経由で、web1,2にリクエストが振られ、クライアント環境へ意図した応答が変えるか確認。

 LVS1:master
 LVS2:backup
 web1:正常稼働
 web2:正常稼働
  • クライアントからのリクエス


# while(true); do curl -H 'Host: www.example.org' http://[Global IP1]; sleep 1; done
 test1
 test2
 test1
 test2
 〜
#
web1,2からそれぞれレスポンスが返る事が確認できた。

パターン2:異常系

lvs1で障害が発生し、LVS2がmasterとなった状態で、
web1,2にリクエストが振られ、クライアント環境へ意図した応答が変えるか確認。

 LVS1:障害!
 LVS2:master
 web1:正常稼働
 web2:正常稼働
  • クライアントからのリクエス


# while(true); do curl -H 'Host: www.example.org' http://[Global IP1]; sleep 1; done
 test1
 test2
 test1
 test2
 〜
#
web1,2からそれぞれレスポンスが返る事が確認できた。
ただし、LVS1のkeepalivedをダウンさせた際、クライアントからのリクエストが1度コネクションエラーとなった。

パターン3:異常系

web1で障害(apacheダウン)が発生した状態で、master経由で web2にリクエストが振られ、クライアント環境へ意図した応答が変えるか確認。

 LVS1:master
 LVS2:backup
 web1:障害!
 web2:正常稼働
  • クライアントからのリクエス


# while(true); do curl -H 'Host: www.example.org' http://[Global IP1]; sleep 1; done
 test2
 test2
 test2
 test2
 〜
#
web2からレスポンスが返る事が確認できた。

パターン4:異常系

web2で障害(apacheダウン)が発生した状態で、master経由で web2にリクエストが振られ、クライアント環境へ意図した応答が変えるか確認。

 LVS1:master
 LVS2:backup
 web1:正常稼働
 web2:障害!
  • クライアントからのリクエス


# while(true); do curl -H 'Host: www.example.org' http://[Global IP1]; sleep 1; done
 test1
 test1
 test1
 test1
 〜
#
web1からレスポンスが返る事が確認できた。

パターン5:異常系

web1,2で障害(apacheダウン)が発生した状態で、master経由で sorryにリクエストが振られ、クライアント環境へ意図した応答が変えるか確認。

 LVS1:master
 LVS2:backup
 web1:障害!
 web2:障害!
 sorry:正常稼働
  • クライアントからのリクエス


# while(true); do curl -H 'Host: www.example.org' http://[Global IP1]; sleep 1; done
 sorry
 sorry
 sorry
 sorry
 〜
#
sorry
からレスポンスが返る事が確認できた。

まとめ

LVS(DSR&VRRP)を利用することで、分散/冗長環境を構築することが確認できた。
非常に高価なハードウェアLBを用意せずとも、分散/冗長環境環境を用意できるメリットは大きい。

本番環境で稼働させる際は、細かいパラメータ設定、運用/障害対応手順の確立、
監視環境の用意などが必要となってくると思うので、また時間があればまとめていきたい。