[ 言語選択: English ]

1. 作業の概要

このチュートリアルはkeepalivedを利用し、ロードバランサー高可用性(HA, High Availability) の2つの機能を体験する内容になっています。

ポイントとなる技術要素に VRRP があります。 VRRPを利用することによって、複数台で1つのIPアドレスを共有し、1台が停止しても他のマシンがIPアドレスを引き継ぎ処理を継続します。

また、Keepalivedはパケットを転送する役割も担います。 今回は 192.168.100.0/24 という実験用のネットワークを構築し、このネットワークに配置されたWebサーバーにアクセスするサービスを構築します。

次にARPテーブルについても作業の中で参照してもらいます。

## ARPテーブル確認用のコマンド
$ ip neigh

## ARPテーブルを削除するコマンド
$ sudo ip neigh flush all

作業ではThinkPad上と、sshでリモートログインしたAPU/APU2上での作業が発生します。

どちらのホストにログインしているか混乱しないようにターミナル(SHELL)を扱うこと。

1.1. 全体図

tutorial apu keepalived.20231124 sccp keepalived overview

1.2. 構築済みのサーバー

今回は以下のサーバーを利用します。

2. APU/APU2によるKeepalivedの実行

APU/APU2はPC Engines社製のx86系CPUを搭載した小型サーバーです。

ディスプレイを接続することはできません。 操作はネットワーク越しにSSHなどでリモートログインするか、シリアル通信(RS-232-C)によって操作を行います。

SSHで操作する際のID/パスワードは、各機器に貼付されている付箋を確認してください。 初期化されているAPU/APU2の初期パスワードは次のようになっているはずです。

  • ID: ubuntu

  • パスワード: secret

## 192.168.100.210にリモートログインする場合の例
$ ssh ubuntu@192.168.100.210

2.1. APU/APU2のIPアドレス等の設定値

APU/APU2のeth0(enp1s0)、eth1(enp2s0)にはDHCPサーバー経由で自動的に固定IPが割り当てられるよう設定しています。

tutorial apu keepalived.20230119 cable

それぞれのネットワークにイーサネット・ケーブルを使用し、正しく接続してください。

一般的にAPU/APU2をUSBシリアルケーブルで接続したLinux端末には次のコマンドでアクセスできます。

$ sudo screen /dev/ttyUSB0 115200

各APUのIPアドレスと設定に必要な情報は以下のとおりです。

ホスト名 IPアドレス enp1s0側 VRRP:virtual_router_id (XXX) VRRP:auth_pass (YYY) VRRP:virtual_ip_address VRRP:virtual_server (末尾ZZZ) VPP:priority (WW)

u109lb10

192.168.100.210

100

abc012

192.168.100.220/24 dev enp1s0

192.168.100.220

10

u109lb11

192.168.100.211

110

def345

192.168.100.221/24 dev enp1s0

192.168.100.221

11

u109lb12

192.168.100.212

110

def345

192.168.100.221/24 dev enp1s0

192.168.100.221

12

u109lb13

192.168.100.213

120

ghi678

192.168.100.223/24 dev enp1s0

192.168.100.223

13

u109lb14

192.168.100.214

120

ghi678

192.168.100.223/24 dev enp1s0

192.168.100.223

14

これらの情報は後で利用します。

2.2. 動作を観察する上で必要な情報

正常に稼動すると、3つの仮想IPによってサービスが開始され、それぞれ参加ホスト、稼動確認用URLは次のようになります。

仮想IPアドレス (FQDN) 参加ホスト 稼動確認用URL

192.168.100.220 (u109lb20.fcsjst.u-aizu.ac.jp)

u109lb10

https://inovtst9.u-aizu.ac.jp/192.168.100.220/

192.168.100.221 (u109lb21.fcsjst.u-aizu.ac.jp)

u109lb11 u109lb12

https://inovtst9.u-aizu.ac.jp/192.168.100.221/

192.168.100.223 (u109lb23.fcsjst.u-aizu.ac.jp)

u109lb13 u109lb14

https://inovtst9.u-aizu.ac.jp/192.168.100.223/

またMACアドレスはそれぞれ次のようになっています。

ホスト (IPアドレス) enp1s0のMACアドレス

u109lb10 (192.168.100.210)

00:0d:b9:41:e5:40

u109lb11 (192.168.100.211)

00:0d:b9:41:e0:7c

u109lb12 (192.168.100.212)

00:0d:b9:33:12:a4

u109lb13 (192.168.100.213)

00:0d:b9:33:12:90

u109lb14 (192.168.100.214)

00:0d:b9:4a:7c:40

- (192.168.100.150)

b8:27:eb:b3:bb:e1

- (192.168.100.151)

b8:27:eb:92:a5:e2

2.3. APU/APU2へのkeepalivedの導入と設定

まずAPU/APU2にリモートログインした状態であることを確認し、次の操作を行います。

2.3.1. パッケージのインストール

keepalivedパッケージをインストールします。

$ sudo apt update
$ sudo apt dist-upgrade -y
$ sudo apt install -y keepalived

2.3.2. 設定ファイルの配置と変更

次に設定ファイル(keepalived.conf)を次のリンクからダウンロードしてください。

これを /etc/keepalived/keepalived.conf ファイルとして配置します。

ファイル中で xxx と書かれている部分は、前述の表などを確認し書き換えてください。 (4箇所)

なおリモートホスト上にファイルを作成する場合には、次のような方法が考えられます。

  1. リモートホスト上で、wgetコマンドなどを使いダウンロードを行う

  2. teeコマンドやcatコマンドを利用し、ファイルの内容をコピーする

  3. ローカル(ThinkPad)にダウンロードしたファイルを、scpコマンドなどで転送する

2.3.3. keepalivedサービスの起動

全ての箇所を変更した後は、次のコマンドで設定を反映させます。

$ sudo systemctl restart keepalived.service

これによってkeepalivedデーモン(daemon)が起動しているはずです。

2.3.4. 稼動確認

前述の表から稼動確認用URLを確認し、自分に割り当てられた仮想IPにWebブラウザや、curlコマンドからアクセスし、応答することを確認してください。

2.3.5. APU/APU2を再起動してみる

Webブラウザなどで、稼動確認用のURLをリロードしながら、APU/APU2を再起動します。

処理が引き継がれている様子を確認してください。

2.3.6. Webサーバーのネットワークケーブルを外してみる

Webサーバーにつながっているネットワークケーブルを、スイッチの側から外して動作が変化することを確認してください。

2.3.7. ip neigh コマンドによる確認

ホストのARPテーブルを確認するために次のコマンドを実行します。

$ ip neigh
  1. 上記のコマンドを実行し、仮想IP に対応するMACアドレスを確認すること

  2. (1.)で確認したMACアドレスを持つ他のIPアドレスを探すこと

  3. 下記のコマンドからARPテーブルを削除した後、再度(1.), (2.)を実施すること

  4. Webブラウザなどで、仮想IP と Webサーバー にアクセスした後に、再度(1.), (2.)を実施すること

$ sudo ip neigh flush all

3. DRモードで動作するHAクラスターの動きについて

サービス用の仮想IPアドレスが2つのノード間で、どのように引き継がれるのか観察します。

3.1. クライアントPC(ThinkPad)上での確認

以下の作業はThinkPad上で実施してください。

3.1.1. VRRPパケットの内容確認

まずThinkPad上のターミナルで次のようにVRRPがどのようなメッセージを送信しているか確認します。

自分が利用しているNICのデバイス名は、ip addr コマンドで確認してください。

## NICがenp0s25で定義されている例
$ sudo tcpdump -i enp0s25 -n vrrp

## NICがenp0s31f6で定義されている場合
$ sudo tcpdump -i enp0s31f6 -n vrrp

下記のような出力が得られますが、MACアドレスが含まれていないので、どちらのAPU/APU2から通信が行われたか分かりません。

03:34:36.650572 IP 192.168.100.210 > 224.0.0.18: VRRPv2, Advertisement, vrid 100, prio 100, authtype simple, intvl 1s, length 20
03:34:36.949668 IP 192.168.100.211 > 224.0.0.18: VRRPv2, Advertisement, vrid 110, prio 100, authtype simple, intvl 1s, length 20

wiresharkを利用してどちらのAPU/APU2からパケットが発信されているか確認すること。

wiresharkは次の要領で起動できます。

$ wireshark

3.1.2. VRRPパケットの確認のポイント

  • MACアドレス (mac address)

  • 仮想ルーターID (virtual_router_id)

  • パスワード (abc012等)

パケットを観察しながら、Webサーバーのイーサネットケーブルを抜くなどして、動作が変化することを確認してください。

3.2. APU/APU上での動作確認

3.2.1. 仮想IPアドレスの割り当て状況を確認

APU/APU2上で ip コマンドを利用し、割り当てられているネットワーク(IP)アドレスを確認します。

$ ip addr

ペアになっているAPU/APU2のいずれか一方だけで、仮想IPアドレスが割り当てられています。

ARPテーブルについても、どのようになっているか確認すること。

4. WiresharkによるVRRPの動作確認

グループでパケットをモニターするためには、一般的なスイッチングハブは適さないため、ポートミラー、フラディングモード、などの機能を備えた特殊なハブを準備する必要があります。

いずれにしても全体の帯域がポート1つ分に制限されるため、大量のデータ送信が行われるとパケットがドロップされてしまう可能性がある点にも注意が必要です。

ここではWiresharkによるパケットのモニターが終ったものとして説明を行います。 説明に使用した際のファイルは次のURLからダウンロードが可能です。

ダウンロードしたファイルはそのままwiresharkで閲覧が可能です。

$ wireshark tutorial-apu-keepalived.20230126_sccp_02.pcapng.gz

起動したらフィルターに vrrp を指定します。全て小文字である必要があるので気をつけてください。 もし間違った入力をすると背景が赤色になるため、気がつくと思います。

tutorial apu keepalived.Screenshot 2023 02 02 14 27 47 wireshark vrrp

4.1. VRRPの基本動作 (L2レベル)

まず2台でkeepalivedが稼動すると、自分がマスターノードであるかどうか確認するために2つのノードからパケットがブローキャストされます。

そしてしばらくすると通信が安定し、片側のノードだけから定期的にブロードキャストパケットが送信され続けています。

フィルターにはいくつかのVRRPノードが存在するため、特定のグループの通信をみるために、次のようにパスワードが"def345"である通信のみを表示します。

vrrp and vrrp.auth_string == ghi678

途中で、パケットの送信元が 192.168.100.214 から 192.168.100.213 に変化したところが分かると思います。

tutorial apu keepalived.Screenshot 2023 02 02 14 40 23 wireshark vrrp switch vip

この例では、約3.5秒ほどの時間が経過したタイミングで 192.168.100.213 からパケットが送信され、その後、仮想IPが引き継がれています。

4.2. HTTPプロトコルの挙動 (L7レベル)

仮想IPが切り替わった21秒後半から25秒過ぎまでの動作を確認します。

フィルターに ip.addr == 192.168.100.223 と入力し、仮想IP 192.168.100.223 の通信のみを表示させます。

tutorial apu keepalived.Screenshot 2023 02 02 14 45 36 wireshark http log

25秒直前から、26秒手前の間で通信を試みたものの通信が成立せずにパケットの再送が行われています。(背景が黒い部分)

4.2.1. No.2601 と No.2682 の通信相手を確認する

いままでの情報から推測すると、No.2601の通信が開始した時点では、192.168.100.214 のノードがダウンしている可能性があり、No.2682で[SYN,ACK]パケットによって反応した相手は別ノードかもしれません。

それぞれの表示は次のようになっています。

No.2601の送信先のMACアドレスは、PCEngine_4a:7c:40 (192.168.100.214) となっています。

tutorial apu keepalived.Screenshot 2023 02 02 14 45 36 wireshark http no2601

No.2682の送信元のMACアドレスは、Raspberry_92:a5:e2 (192.168.100.151) になっています。

tutorial apu keepalived.Screenshot 2023 02 02 14 45 36 wireshark http no2682

続いて、このNo.2601の通信を別の角度から確認します。

Wiresharkには関係のないデータを除き、特定の通信のみを抽出する TCP Stream 機能があるので、これを利用します。

tutorial apu keepalived.Screenshot 2023 02 02 15 17 53 wireshark tcpflow

49878番ポートと80番ポートの通信内容を確認することができるようになりました。

4.2.2. No.2680、No.2681の再送パケット

背景が黒になっている行を確認すると、次のような情報が確認できます。 No.2601, No.2680, No.2681 のパケットのIPアドレスやTCPレベルでの通信内容に変更はありません。

  1. No.2680では、送信先(Dst)が、PCEngine_33:12:90 (192.168.100.213) となっています。

  2. No.2681では、送信元(Src)が、PCEngine_33:12:90 (192.168.100.213) 、送信先(Dst)が、Raspberry_92:a5:e2 (192.168.100.151) となっています。

元々の、No.2601のパケットが届かなかったことを察知した、192.168.100.4ノードは、改めて同じ内容のパケットを 192.168.100.213 宛てに送り直しています。

そして、仮想IPを獲得した192.168.100.213が反応し、Webサーバー(Raspberry Pi, 192.168.100.151) がパケットを受け取るように再送信します。

通信を開始しようとする都度、仮想IPが動作するAPUからWebサーバーへのパケット再送が発生している(背景が黒)ことも分かると思います。

5. Keepalivedによるロードバランサーの実装

ロードバランサの機能は定期的なWebサーバーの稼動状況を確認することで実現されています。

Wiresharkを利用して定期的にKeepalivedがWebサーバー(192.168.100.150, 192.168.100.151)の死活監視を行っている様子をみてみましょう。

5.1. Wiresharkによるパケットの観察

保存している、あるいは新規に取得したパケット群から次のようなパケットをみてみましょう。

この例で使用している通信は次のファイルに保存されています。

http and ip.addr == 192.168.100.150

見難ければTCP Stream機能を利用するなど工夫してください。

tutorial apu keepalived.wireshark lbping

この通信から、192.168.100.212(APU/APU2)から192.168.100.151(Raspberry Pi, Webサーバー)に向けて通信が発生しています。

この時のUser-AgentはKeepAliveClientとなっていて、定期的にKeepalivedは仮想IPに紐つく実サーバーと通信を行っています。

設定ファイルを確認します。

virtual_server 192.168.100.ZZZ 80 {
  delay_loop 1
  lb_algo rr
  lb_kind DR
  protocol TCP
  real_server 192.168.100.150 80 {
    weight 1
    inhibit_on_failure
    HTTP_GET {
      url {
        path /index.html
        status_code 200
      }
      connect_timeout 1
      nb_get_retry 1
      delay_before_retry 1
    }
  }
  ...
}

delay_loop 1により1秒間隔で、real_serverへ稼動状況を確認します。

5.2. 片側のWebサーバーが停止した場合

192.168.100.151のイーサネットケーブルを抜いた時の挙動を確認しましょう。

wiresharkのフィルターを次のように設定します。

ip.addr == 192.168.100.151

イーサネットケーブルを抜くと、通信が一方通行になり、発信元(Source)を192.168.100.151とする返信がまったくなくなります。

tutorial apu keepalived.wireshark lbcableout

この例ではNo.2293からNo.3740まで、192.168.100.151の返信が確認できていません。

5.3. Webサーバー復帰後の通信回復処理

指定された時間間隔でKeepalivedはreal_serverに通信が可能か確認し続けています。

イーサネットケーブルを抜いている状態でWiresharkを起動しておき、イーサネットケーブルを元のようにスイッチと接続した後、通信がどれくらいの間隔で回復するか確認してください。

5.4. HAと仮想MACアドレスについて

LinuxではMACアドレスを変更すること自体は可能ですが、1つのNICに複数の仮想MACアドレスを与えることはできません。

仮想MACアドレスについては、商用OSでは可能な場合が多いと思います。

仮想MACアドレスを使用している場合には、物理的に接続しているスイッチのみがサービスノードの停止を把握し、LAN上の他の機器はHAの稼動状況によって影響を受けることはありません。

仮想MACアドレスが使用できない環境下では、LAN上の全ての機器が仮想IPアドレスに対応するMACアドレスを把握する必要があり、サービスノードの切り替えにより仮想IPアドレスに対応するMACアドレスが変更された事を知らせるARPメッセージを受信しなければなりません。

6. 参考情報

6.1. バックエンドWebサーバー側の設定項目

以下の設定は、あらかじめバックエンドのWebサーバー側で実施した内容を説明しています。

APU/APU2側では実施する必要がないので注意すること。

Oracleのドキュメントに詳細な説明があります。

6.1.1. 仮想IPアドレスの設定

/etc/network/interfacesファイルに次のような設定を加え、仮想IPアドレスがWebサーバー自身のIPだと認識しています。

192.168.100.150側の設定のみ掲載します。192.168.100.151側も同様の設定を行っています。

## /etc/network/interfaces.d/eth0.conf
auto eth0
iface eth0 inet static
  address 192.168.100.150
  netmask 255.255.255.0
## /etc/network/interfaces.d/eth0:1.conf
auto eth0:1
iface eth0:1 inet static
  address 192.168.100.220
  netmask 255.255.255.0
## /etc/network/interfaces.d/eth0:2.conf
auto eth0:2
iface eth0:2 inet static
  address 192.168.100.221
  netmask 255.255.255.0
## /etc/network/interfaces.d/eth0:3.conf
auto eth0:3
iface eth0:3 inet static
  address 192.168.100.223
  netmask 255.255.255.0

これらの設定を行った後、ip addrコマンドの出力は次のようになっています。

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:b3:bb:e1 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.150/24 brd 192.168.100.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.100.220/24 brd 192.168.100.255 scope global secondary eth0:1
       valid_lft forever preferred_lft forever
    inet 192.168.100.221/24 brd 192.168.100.255 scope global secondary eth0:2
       valid_lft forever preferred_lft forever
    inet 192.168.100.223/24 brd 192.168.100.255 scope global secondary eth0:3
       valid_lft forever preferred_lft forever

設定の方法によってはイーサネット・ケーブルを抜き差しによって仮想アドレスが復旧しない可能性があります。 これらの方法は安定して動作すると思うので参考にしてください。

6.1.2. ARPに仮想IPを返信しないよう設定を変更

仮想IPを所持しているのはAPU/APU2であると、他のシステムに認識してもらう必要があります。 Webサーバーが仮想IPに関する問い合わせを無視するように設定を変更します。

/etc/sysctl.confファイルで、次の設定を書き加えます。

net.ipv4.conf.eth0.arp_ignore=1
net.ipv4.conf.eth0.arp_announce=2

6.2. https://inovtst9.u-aizu.ac.jp/192.168.100.220/ などの設定状況

稼動確認用URLとして次の3つのリダイレクトを設定しています。

ゼミ室のネットワーク境界にある inovtst9.u-aizu.ac.jp 上の nginx に次のような設定を行っています。

    location /192.168.100.220/ {
        proxy_pass    http://192.168.100.220/;
    }
    location /192.168.100.221/ {
        proxy_pass    http://192.168.100.221/;
    }
    location /192.168.100.223/ {
        proxy_pass    http://192.168.100.223/;
    }

6.3. Ansible Playbook

LB(APU/APU2)とWebサーバー(Raspberry Pi1)の設定手順については、ansible playbookにまとめてGitHub上で公開しています。