More than 1 year has passed since last update.

こんにちは、ソリューションアーキテクト部の金杉です! :smiley_cat:

IDCフロンティアでは、主に中のエンジニアさんたちが執筆するエンジニアブログがあります!そして、私も、先月やっと自分のエンジニアブログデビューを果たしました! :joy: そして今回の記事は、前回の記事の第二部になります〜

テーマ

前回のエンジニアブログでは、IDCFクラウドCentOS6の仮想マシンでkeepalivedを使ったLVSを構築しました。LVSの主な二つの機能を振り返ってみると、

 1. バランシングしているサーバーのヘルスチェック :heavy_check_mark:
 2. VRRPを用いたロードバランサーの冗長化 :dancers:

などがありますね。機能1は前回のブログで紹介させて頂いたので、今回は機能2の部分、VRRPを用いてLVSを冗長構成にしてみたいと思います。そしてバランシングするサーバーの特徴に基づいた、2種類の構築方法を紹介します!

キャプチャ1.PNG
    :point_up:今回構築する構成

仮想マシンの準備

CentOS 6.6の仮想マシンで構築をします。バランシングするリアルサーバー(WebやDBなど)2台とバーチャルサーバー(LVS)2台、計4台の仮想マシンを以下のスペックで作成します。「台数」選 択の部分で、:four:を選択すると一気に作れてしまいます :notes:

 マシンタイプ             Light.S1
 イメージ               CentOS 6.6 64-bit
 ボリューム              そのまま
 SSH Key                作成
 仮想マシン台数            4
 ネットワークインターフェース     そのまま
 詳細情報・仮想マシン名        LB, LB-backup, Real1, Real2
 詳細情報・プライベートIPアドレス   自動設定

仮想マシンは、それぞれSSHできるように「IPアドレス」の設定をしておいてください。
もしリアルサーバーが公開用であれば、80番ポートのファイアウォールだけあけておいて、ポートフォワードルールは記入しないでください。後ほど新しいルールを記入します。

詳しくは、めちゃ楽ガイドをご参照ください!

今回の構成

今回は、Figure 1のような構成になります。仮想ルーターの下にLB(マスターロードバランサー)、LB-backup(バックアップロードバランサー)、Real1、Real2(リアルサーバー)が同じセグメントに設置されています。仮想ルーターのIPアドレスが公開用のIPアドレスになります。

一方、LBがバランシングする時の様子がFigure 2になります。LVSを冗長化することが今回の目的なので、LVSはLBとLB-backupの二台になります。LB-backupは、LBが万が一落ちてしまった場合バックアップとして動作する役割を持っています。中身はLBとほぼ同じです。

キャプチャ.PNG    キャプチャ9.PNG

普段、マスターロードバランサーとバックアップロードバランサーはセットになっていて、仮想的に1台のロードバランサーとして動作します。マスターに問題が発生した時、バックアップがマスターに昇格し、処理を代行します。このように、同じLANで複数台のルーターを1つに束ねる仕組みをVRRP(Virtual Router Redundancy Protocol)と呼び、自動的な切り替えをフェイルオーバーと言います。

Figure 2で見ると、LBとLB-backupは仮想的に1台のロードバランサーとして扱われます。なので、リクエストを一括で受けとるため、VIP(Virtual IP)と言う複数台のLVSを代表する仮想的なIPアドレスが必要となります。VIPを使うことによって、サービスへのリクエストはVIP宛となり、SSHなどのLVS単体へのリクエストは、サーバーの実IP宛のままで大丈夫です。イメージしやすくするには、VRRPによって束ねられているロードバランサー達を1つの仮想ロードバランサーと見て、そしてVIPはその仮想ロードバランサーのIPアドレスと想像すると良いかもしれません。

この肝心なVRRPですが、インフラの環境によってはサポートされていない場合が多いです。ですがIDCFクラウドではVRRPが使用できて、そしてVIPを取得する方法が、なんと二つもあります :star: 共通の手順が多いのですが、構築される環境の特徴に応じて「Step1. VIPの取得」の部分を手順1手順2に分けて紹介します。

バランシング対象がWeb等といった、トラフィックが仮想ルーター経由でくる場合→手順1
バランシング対象がDB等といった、トラフィックが内部サーバー経由でくる場合→手順2

手順がわかれる主な理由は、IDCFクラウドの仕様にあります。とても簡単な話ですが、仮想マシンが直接外部と通信する場合、仮想ルーターを経由するので、ポートフォワードを設定する必要があります。ポートフォワードをする場合はAPIでIPアドレスを取得する必要があり、具体的な方法は手順1で紹介されています。一方、リアルサーバーが内部サーバーのみと通信する場合、ポートフォワードは必要ありません。この場合、LVSの構築は比較的簡単で、その方法が手順2で紹介されています。

Step1. VIPの取得

共通手順

使用できるIPアドレスの確認
VIPとして使うIPアドレスの確認をします。IDCFクラウドのポータル画面より、左メニューバー「ネットワーク」、ターゲットのネットワーク名、「IPアドレス一覧」をクリックします。

ip.png
              :point_up:IPアドレス一覧の画面

手順1の場合
ここに表示されている仮想マシンやルーターに割当済みのIPアドレスと、「割当範囲外」のIPアドレスを除いたすべてのIPアドレスがVIPとして割当可能です。VIPはDHCPで取得することも可能ですが、今回は10.5.0.100を指定して使おうと思います。【手順1】の部分へお進みください。

手順2の場合
「割当範囲外」のIPアドレスがすべてVIPとして指定できるのですが、「利用不可」と書かれている最後の10個のIPアドレスだけはIDCFクラウド側で使用するため割当はできません。なので、この例では「利用不可」の10.5.7.235〜10.5.7.254を除いた範囲で選びましょう!特に決まりはないですが、今回は10.5.4.100を使います。では、【手順2】の部分へお進みください。

【手順1】仮想ルーター経由トラフィック用のLVS

トラフィックが仮想ルーターからくる場合は、下の図のような構成になります。Webなどの公開用サーバーをバランシングする時は、基本このような構成を取ります。リクエストは仮想ルーターを通過したら、直接ロードバランサーのVIP宛に届きます。そしてバランシング処理が済んだあと、再度このVIPよりリアルサーバーへ転送されます。

キャプチャ2.PNG
  :point_up:仮想ルーター経由トラフィック用のLVS

VIPの取得はAPI経由で行います。APIはハードルが高そうに見えますが、何回か使ううちにAPIのファンになっていく方が多いです(笑)。実際私もそうでした! :neckbeard: IDCFクラウドではCloudStackのAPIがそのまま使えるので、なじみがある方もいらっしゃるかもしれませんね!IPアドレスの値は、先ほど確認した10.5.0.100をスタティックで付与します。APIに関しては、API Referencesをご参照ください!

コマンドラインツールのインストール
APIを利用するにあたって、コマンドラインツールのインストールが必要になります。インストールするサーバーは、同じアカウント内のどのサーバーでもかまいません。APIのGetting Started ガイドに沿って「簡単な使い方:Step4」までを実行して頂いても良いですし、以前上野が説明した「IDCFクラウド APIを利用した仮想マシンの作成からSSH接続まで」の「Step3」まで実行することでも実装できます。

APIでVIPを取得
いよいよ準備はOKです。VIPをマスターロードバランサーLBのNICに追加する作業を行います。

# 仮想マシンのid一覧を表示
[root@LB ~]# cloudstack-api listVirtualMachines -t displayname,id
+-------------+--------------------------------------+
| displayname |                  id                  |
+-------------+--------------------------------------+
| LB          | a2fa6425-aacc-4aba-bb84-e486a41e1c9e |
| LB-backup   | bb4095f1-c6b1-4646-8e89-762cd26a53d2 |
| Web1        | 785020c1-4d3b-4bb4-84c4-c9abe8da9ccb |
| Web2        | ea2f2045-64b5-4f70-9201-e0a6aa9c81c5 |
+-------------+--------------------------------------+

# 仮想マシンLBのNIC idを表示
[root@LB ~]# cloudstack-api listNics --virtualmachineid a2fa6425-aacc-4aba-bb84-e486a41e1c9e -t ipaddress,id
+------------+--------------------------------------+
| ipaddress  |                  id                  |
+------------+--------------------------------------+
| 10.5.0.133 | d555c213-3ede-4bb4-96bd-d1ce6c475852 |
+------------+--------------------------------------+

# 仮想マシンLBのNICにセカンダリIPアドレスを指定して割り当てる
[root@LB ~]# cloudstack-api addIpToNic --nicid d555c213-3ede-4bb4-96bd-d1ce6c475852 --ipaddress 10.5.0.100

# もう一度仮想マシンLBのNICの情報を表示
[root@LB ~]# cloudstack-api listNics --nicid d555c213-3ede-4bb4-96bd-d1ce6c475852 --virtualmachineid a2fa6425-aacc-4aba-bb84-e486a41e1c9e
{
  "listnicsresponse": {
    "count": 1,
    "nic": [
    {
      "gateway": "10.5.0.1",
      "id": "d555c213-3ede-4bb4-96bd-d1ce6c475852",
      "ipaddress": "10.5.0.133",
      "isdefault": true,
      "macaddress": "02:00:56:df:00:0f",
      "netmask": "255.255.252.0",
      "networkid": "15616765-d713-4ff3-bba3-a1c71a46d9bf",
      "secondaryip":
      {
        "id": "f2ff97fe-ecfd-4e01-ab34-9b17cbce16f9",
        "ipaddress": "10.5.0.100"
      }
    }
    ]
  }
}

APIでポートフォワードルールを記入

# 仮想ルーターのソースIPのidを表示
[root@LB ~]# cloudstack-api listPublicIpAddresses -t ipaddress,id
+----------------+--------------------------------------+
|   ipaddress    |                  id                  |
+----------------+--------------------------------------+
| 210.140.68.220 | 0c5cc05a-26d5-4539-9c7a-0f935291f71d |
+----------------+--------------------------------------+

# VIPを指定してポートフォワードルールを記入
[root@LB ~]# cloudstack-api createPortForwardingRule --ipaddressid 0c5cc05a-26d5-4539-9c7a-0f935291f71d --privateport 80 --protocol tcp --publicport 80 --virtualmachineid a2fa6425-aacc-4aba-bb84-e486a41e1c9e --vmguestip 10.5.0.100
{
  "createportforwardingruleresponse": {
    "jobid": "dfc3d84e-c9e6-47d3-9f50-4fc4b2c25493",
    "id": "dfc3d84e-c9e6-47d3-9f50-4fc4b2c25493"
  }
}

注意点
API経由で取得したsecondary IPの扱いには、2つ注意点がございます。
※東日本リージョンのみの注意点となります。

Secondary IPはポータルからの管理ができないので、ご自身での管理となります。なので誤って仮想マシンを削除してしまわないよう気を付けましょう! :scream:
Secondary IPをグローバルIPアドレスとスタティックNATした場合、APIでスタティックNATを解除してから仮想マシンを削除するようにしてください。スタティックNATの設定解除せず、そのまま仮想マシンを削除してしまうとシステム側からスタティックNATが削除できなくなってしまいます。 :scream:

【手順2】内部サーバー経由トラフィック用のLVS

トラフィックが内部サーバーからくる場合、下の図のような構成になります。DBなどの非公開用サーバーをバランシングするとき、よく取られる構成です。リクエストはWebサーバーなどの内部サーバーからロードバランサーのVIP宛に届きます。そしてバランシング処理が済んだあと、再度このVIPよりリアルサーバー1かリアルサーバー2へ転送されます。
キャプチャ3.PNG
  :point_up:内部サーバー経由トラフィック用のLVS

このような構成の場合、VIPの取得はとても簡単です。VIPをあらかじめ決めておく事以外、特に設定の必要もありません!IPアドレスの値は、先ほど確認した10.5.4.100を使います。

注意点
VIPとして指定されたIPアドレスは、ポータルから管理ができないので、ご自身の管理となってしまいます。なのでIPアドレスが重複しないよう気を付けてください。 :scream:

Step2. keepalivedの準備

LVSの設定をしていきます。もし前回の記事に沿って設定されているかたは「LVSの設定」部分から続けて下さい。

必要なパッケージをダウンロード

[root@LB ~]# yum -y install ipvsadm keepalived

自動起動の設定

[root@LB ~]# chkconfig keepalived on
[root@LB ~]# chkconfig --list keepalived
keepalived  0:off  1:off  2:on  3:on  4:on  5:on  6:off

パケット転送の設定

[root@LB ~]# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1 (0から1へ変更)
[root@LB ~]# sysctl -p
net.ipv4.ip_forward = 1 (変更されていればOK)

LVSの設定
keepalivedはデフォルトでipvsadmをラップしているので、LVSの設定はkeepalivedのコンフィグを編集して行います。マスターとバックアップ両方のコンフィグを記入する必要がありますが、priorityの値:exclamation:だけは異なるように設定してください。

[root@LB ~]# vim /etc/keepalived/keepalived.conf
keepalived.conf
# vrrp_instance [お好きな名前]で複数設定が可能です
vrrp_instance VI_1 {
  # マスター、バックアップのいずれか
  state MASTER
  # 監視するインターフェース
  interface eth0
  # VRIDは任意の数値で良いが
  # 同じセグメントの他のVRIDとかぶらないように設定する
  # 例:仮想ルーターのVRIDや追加ネットワークのVRID
  virtual_router_id 1
  # マスターとバックアップで必ず違う値にする
  # 例:マスター:300、バックアップ1:200、バックアップ2:100
  priority 100
  # VRRP信号を送る間隔
  advert_int 1
  # VIPを指定、手順2の場合は10.5.4.100
  virtual_ipaddress {
    10.5.0.100 dev eth0
  }
}
# LVSの設定
virtual_server 10.5.0.100 80 {
  # ヘルスチェック間隔
  delay_loop 3
  # 分散方式はround robinを使う
  lb_algo rr
  # パケット転送の方法はdirect routing (DSR)
  lb_kind DR
  protocol TCP
  # リアルサーバのIPアドレスおよびヘルスチェックのポート番号
  # Webは80番や443番、MySQLは3306番など
  real_server 10.5.0.36 80 {
    weight 1
    # ヘルスチェック失敗時はweightをさげる
    inhibit_on_failure
    # ヘルスチェック方式
    # WebはHTTP_GETやSSL_GET、MySQLはTCP_CHECKなど
    HTTP_GET {
    # Webはurl、MySQLではconnect_port 3306など
    url {
    # ヘルスチェック用のページ
      path /healthchk.html
      status_code 200
    }
    connect_timeout 3
    # ヘルスチェック失敗時の間隔
    delay_before_retry 7
  }
}
# リアルサーバー2台目以降も同じ設定にする
  real_server 10.5.0.229 80 {
    weight 1
    inhibit_on_failure
    HTTP_GET {
      url {
        path /healthchk.html
        status_code 200
      }
      connect_timeout 3
      delay_before_retry 7
    }
  }
}

Step3. リアルサーバーの準備

手順1の場合はWebサーバー、手順2の場合はDBサーバーを例として準備します。ApacheやMySQLをインストールして、サービスをスタートすれば動作確認はとれます。Webサーバーに関しては、ヘルスチェック用のページも忘れず用意しておいてくださいね! :smiley_cat:

iptablesの記入
重要です。リアルサーバーがLVSのVIP宛のパケットを受け取ったとき、自分宛のパケットとして処理できるようにさせてあげる必要があります。

[root@Real1 ~]# iptables -t nat -A PREROUTING -d 10.5.0.100 -j REDIRECT
# -d 10.5.0.100 の部分でご自身のLVSのVIPを指定する
[root@Real1 ~]# service iptables save

Step4. keepalivedの起動

LVS冗長構成の設定とVIPの準備ができたので、keepalivedを起動して、様子を見てみましょう!:eyes:

keepalivedの起動

[root@LB ~]# service keepalived start

VIPの確認
マスター(LB)のほうでeth0に割り当てられているIPアドレスを見てみましょう。

[root@LB ~]# ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:00:56:df:00:0f brd ff:ff:ff:ff:ff:ff
inet 10.5.0.133/21 brd 10.5.7.255 scope global eth0
inet 10.5.0.100/32 scope global eth0
inet6 fe80::56ff:fedf:f/64 scope link
valid_lft forever preferred_lft forever

マスターのほうにVIPがついています。VIPは、実際にLVSとして動いているサーバーに付きます。なのでこの時点で同じコマンドをバックアップのほうで入力しても、VIPは表示されません。マスターが正常にLVSとして稼働しているからです。:v:

動作確認
動作確認の前に、LVS上でipvsadmコマンドを使ってバランシングの状態をマスター、バックアップ両方で確認してみましょう。

[root@LB ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.5.0.100:80 rr
-> 10.5.0.36:80                 Route   1      0          0
-> 10.5.0.229:80                Route   1      0          0
LVSのIPアドレスが見事VIPの10.5.0.100(手順2の場合10.5.4.100)になっています。ここでマスターを落としてみて、バックアップへフェイルオーバーするか確認してみます。

[root@LB ~]# service keepalived stop
keepalived を停止中:                                       [  OK  ]
[root@LB ~]# ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:00:56:df:00:0f brd ff:ff:ff:ff:ff:ff
inet 10.5.0.133/21 brd 10.5.7.255 scope global eth0
inet6 fe80::56ff:fedf:f/64 scope link
valid_lft forever preferred_lft forever

マスターでもう一度eth0に割り当てられているIPアドレスを見てみると、VIPが消えています。では、バックアップのほうを見てみましょう。

[root@LB-backup ~]# ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:00:0a:30:00:10 brd ff:ff:ff:ff:ff:ff
inet 10.5.0.195/21 brd 10.5.7.255 scope global eth0
inet 10.5.0.100/32 scope global eth0
inet6 fe80::aff:fe30:10/64 scope link
valid_lft forever preferred_lft forever

VIPが自動的にバックアップのNICに切り替わりました。冗長化は保たれていますね。:v:

[root@LB-backup ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.5.0.100:80 rr
-> 10.5.0.36:80                 Route   1      0          0
-> 10.5.0.229:80                Route   1      0          0

バランシング状態も大丈夫のようです。これでLVSが冗長化されていることがわかりました。ばっちりですね!:thumbsup:

終わりに

みなさん、LVSの冗長化はいかがでしたか?コンフィグの部分はさておき、VIPの取得が少し手間かもしれませんが、高価なロードバランサー2台分のお値段を考えると、全然お得ですよね!

もっとも魅力的なのはやはりクラウド環境で、VRRPを用いたLVSの冗長化が可能な仕様だと思っています。例の通り、IDCFクラウドはAPIさえクリアしてしまえば簡単にそれを実現できてしまいます。インフラのポイント、安定性と柔軟性においては文句なしです!:ok_woman:

もちろん、もし内部トラフィックのバランシングのためでしたら、特にAPIを使う必要もないです。IPアドレスを指定してkeepalived.confに記述するだけで大丈夫です。なので、ぜひ構築したい環境の必要に応じて、楽できるインフラ構築を目指しましょう!ありがとうございましたー:smile_cat:

<関連記事>
IDCFクラウドでkeepalivedを使ったLVS構築(1)