お金をかけずにサーバーの勉強をしよう

NGiNXの障害を keepalivedで検知してサーバー切り替え

2024年2月9日

メニューへ戻る

サーバーは生きていてもアプリケーションの死亡で切り替えるぞ!

2つのサーバーで 1つの IPアドレスを共有 (keepalived)」ではクラスタシステムのサーバーが死んだ時に仮想IPアドレスが生きているサーバーに切り替わる実験をしました。

でも実際の運用ではいつもそのように綺麗な(?)障害ばかりではありません。

サーバーは元気に動いているのにサービスは提供されていない…そんなケースも良くあります。

システムが存在している目的はサービスの提供ですから、サーバーがいくら元気でもサービスが提供されていないのでは全く意味がありません。

ここでは障害のケースの観点で、サーバー自体の障害からもう一歩踏み込んで、アプリケーションの障害を扱ってみようと思います。

keepalivedにはスクリプト実行した結果、エラーのリターンコードを得たらば仮想IPアドレスの切り替えを行う機能があります。

これを使って NGiNXで WEBサービスを提供しているシステムでの冗長化の例を実験してみます。


1.環境

以下の環境でやります。

実際のサーバーは「2つのサーバーで 1つの IPアドレスを共有 (keepalived)」で作った [keep1]サーバーと [keep2]サーバーを再利用します。


2.NGiNXインストール

NGiNXの環境構築については「NGiNXサーバーを作る」に書いています。

準備作業として [keep1]サーバーと [keep2]サーバーに NGiNXをインストールします。

subro@keep1:~$ sudo apt install nginx

これで問題なくインストールできるはずなので、[keep2]サーバーでも同じことをします。

NGiNXがどの IPアドレスで待ち受けているのか見てみます。

[80/tcp] がバインドされているのは [0.0.0.0](IPアドレス全部)ですので、仮想IPアドレスにも対応できそうです。

subro@keep1:~$ ss -l4t
State    Recv-Q    Send-Q   Local Address:Port      Peer Address:Port   Process
LISTEN   0         511            0.0.0.0:http          0.0.0.0:*
LISTEN   0         4096     127.0.0.53%lo:domain         0.0.0.0:*
LISTEN   0         128            0.0.0.0:ssh            0.0.0.0:*

WEBサービスとして提供されるトップページである [/var/www/html/index.html]ファイルは以下の内容にしました。

<!DOCTYPE html>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<HTML>
<BODY>
これは keep1 です。
</BODY>
</HTML>

[keep2]サーバーでも同じ様に作ります。
「keep1です」を「keep2です」に変えるのを忘れずに。

WEBブラウザで [http://keep1] を見に行くとこうなります。
keep1の画面1

WEBブラウザで [http://keep2] を見に行くとこうなります。
keep2の画面1

NGiNXの設定は以上で OKです。


3.NGiNXの死活監視スクリプト

次に NGiNXがちゃんとホームページを提供しているかを確認するシェルスクリプトを作ります。
こういうのを死活監視と言います。

何をしてサービスを提供している(活きている)かの判断が難しいですが、

ということにしましょう。

シェルスクリプト [check_nginx.sh] の内容はこうなりました。

subro@keep1:~$ cat check_nginx.sh
#!/bin/bash

RESULT=`curl -s http://192.168.1.151`  ← curlコマンドで[keep1]サーバーのIPアドレス[192.168.1.151]にアクセスする。

if [ $? != 0 ]; then
    exit 1  ← アクセスに失敗してcurlコマンドがエラーで終わったら、このスクリプトは1を返して終了する。
fi

COUNT=`echo $RESULT | grep -c keep`  ← 戻ってきたHTMLに[keep]が何行あるかを数えている。

if [ $COUNT == 1 ]; then  ← 1行だったら、このスクリプトは0を返して終了する。。
    exit 0
fi

exit 1  ← そうじゃなかったら、このスクリプトは1を返して終了する。

このスクリプトに実行権限を付けるのを忘れずに。

subro@keep1:~$ chmod 755 check_nginx.sh

subro@keep1:~$ ls -l check_nginx.sh
-rwxr-xr-x 1 subro subro 172  7月  8 11:20 check_nginx.sh

[keep2]サーバーにも同じスクリプトを作りますが、curlコマンドでアクセスする先は [192.168.1.152] に変えておきます。

※シェルスクリプトのオーナー/グループはセキュリティ対策として、変なユーザーに変更されないように設定しないといけないんですが、ここでは端折っています。
keepalivedの起動時にちゃんとチェックされて、ダメな場合は注意されます。
(動きますけど)



4.keepalivedの切り替えの仕組み

keepalivedがアプリケーションプログラム監視結果をどうやって切り替え動作に繋げているかを説明します。

keepalivedで構成されるクラスタの 1つ 1つは [priority]という数値を持っています。

クラスタ内でこの [priority]値が一番大きいものが仮想IPアドレスを取得することになっています。
牙が鋭い方が勝つ!!」と同じ原理です。(謎)

ここの例では [keep1]サーバーの [priority]値が [101] で、[keep2]サーバーが [100] です。
よって、普段は [keep1]サーバーが MASTERになります。

この [priority]値はクラスタの稼働中に変化し、アプリケーションの稼働確認も [priorit]値を変える要因となります。

これから keepalivedの設定ファイルを書き換えていきますが、現時点での [priority]値は以下の図のようになります。
クラスタシステムの図1

上で作ったシェルスクリプトを設定して、keepalivedが定期的に実行するようにします。

[keep1]サーバーと [keep2]サーバーともに [/usr/local/etc/keepalived/keepalived.conf]ファイルに以下の通りピンク部分を足していますが、ここでちょっと細工があります。

subro@keep1:/usr/local/etc/keepalived$ cat keepalived.conf
vrrp_script check_nginx {
    script '/home/subro/check_nginx.sh'
    interval 5
    timeout 3
    weight 10
    rise 1
    fall 1
    user subro
}
vrrp_instance keepalive_vi {
    state MASTER
    interface ens32
    virtual_router_id 51
    priority 101
    virtual_ipaddress {
        192.168.1.153/24
    }
    track_script {
        check_nginx
    }
}

[vrrp_scrip check_nginx {}]セクションの中に [weight 10] という箇所があります。

ここの意味なんですが、「このスクリプトが正常終了(リターンコードが 0)なら [priority]値に +10します。」という意味なのです。

これは [keep2]サーバーでも同じなので、図で表すとこんな感じになります。
クラスタシステムの図2

その結果、サーバー起動時には、[keep1]サーバーの [priority]値が [111]、[keep2]サーバーの [priority]値が [110] となりますので、依然として [keep1]サーバーが MASTERになります。

設定ファイルの内容を反映させるため、[keep1]サーバー [keep2]サーバーの両方で keepalivedを再起動します。

subro@keep1:~$ sudo systemctl restart snap.keepalived.daemon

再起動後は想定通り [keep1]サーバーが MASTERになっているようで、仮想IPアドレスの紐づけも [keep1]サーバーで行われています。

subro@keep1:~$ ip -br -4 address
lo               UNKNOWN        127.0.0.1/8
ens32            UP             192.168.1.151/24 192.168.1.153/24
subro@keep2:~$ ip -br -4 address
lo               UNKNOWN        127.0.0.1/8
ens32            UP             192.168.1.152/24

WEBブラウザで仮想IPアドレス相手に [http://192.168.1.153] でアクセスするとこれが出ました。
想定通りです。
keep1の画面2

では、ここで [keep1]サーバーの NGiNXサービスを停止してみます。

subro@keep1:~$ sudo systemctl stop nginx

[keep1]サーバーの syslogを見ると [priority]値が [111] から [101]になったと書いてあります。

subro@keep1:~$ tail /var/log/syslog
Jul  8 14:17:01 keep1 CRON[2781]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Jul  8 14:23:44 keep1 systemd[1]: Stopping A high performance web server and a reverse proxy server...
Jul  8 14:23:44 keep1 systemd[1]: nginx.service: Deactivated successfully.
Jul  8 14:23:44 keep1 systemd[1]: Stopped A high performance web server and a reverse proxy server.
Jul  8 14:23:47 keep1 Keepalived_vrrp[1068]: Script `check_nginx` now returning 1
Jul  8 14:23:47 keep1 Keepalived_vrrp[1068]: VRRP_Script(check_nginx) failed (exited with status 1)
Jul  8 14:23:47 keep1 Keepalived_vrrp[1068]: (keepalive_vi) Changing effective priority from 111 to 101
Jul  8 14:23:49 keep1 Keepalived_vrrp[1068]: (keepalive_vi) Master received advert from 192.168.1.152 with higher priority 110, ours 101
Jul  8 14:23:49 keep1 Keepalived_vrrp[1068]: (keepalive_vi) Entering BACKUP STATE

[keep2]サーバーの syslogには、[keep1]サーバー [192.168.1.151] から、自分の [110] よりも低い [101] が通知されたことが書いてあります。

subro@keep2:~$ tail /var/log/syslog
Jul  8 14:17:01 keep2 CRON[2771]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Jul  8 14:23:47 keep2 Keepalived_vrrp[1102]: (keepalive_vi) received lower priority (101) advert from 192.168.1.151 - discarding
Jul  8 14:23:49 keep2 Keepalived_vrrp[1102]: message repeated 2 times: [ (keepalive_vi) received lower priority (101) advert from 192.168.1.151 - discarding]
Jul  8 14:23:49 keep2 Keepalived_vrrp[1102]: (keepalive_vi) Entering MASTER STATE

図で表すとこんな風です。
クラスタシステムの図3

WEBブラウザで仮想IPアドレス相手に [http://192.168.1.153] でアクセスするとこれが出ました。
これも想定通りです。
keep2の画面2

[keep1]サーバーで NGiNXを立ち上げ直します。
今度は逆の事が起こっていることが分かります。

subro@keep1:~$ sudo systemctl start nginx

subro@keep1:~$ stail /var/log/syslog
Jul  8 15:10:41 keep1 systemd[1]: Starting A high performance web server and a reverse proxy server...
Jul  8 15:10:41 keep1 systemd[1]: Started A high performance web server and a reverse proxy server.
Jul  8 15:10:43 keep1 Keepalived_vrrp[1068]: Script `check_nginx` now returning 0
Jul  8 15:10:43 keep1 Keepalived_vrrp[1068]: VRRP_Script(check_nginx) succeeded
Jul  8 15:10:43 keep1 Keepalived_vrrp[1068]: (keepalive_vi) Changing effective priority from 101 to 111
Jul  8 15:10:44 keep1 Keepalived_vrrp[1068]: (keepalive_vi) received lower priority (110) advert from 192.168.1.152 - discarding
Jul  8 15:10:46 keep1 Keepalived_vrrp[1068]: message repeated 2 times: [ (keepalive_vi) received lower priority (110) advert from 192.168.1.152 - discarding]
Jul  8 15:10:47 keep1 Keepalived_vrrp[1068]: (keepalive_vi) Entering MASTER STATE

subro@keep2:~$ tail /var/log/syslog
Jul  8 15:10:47 keep2 Keepalived_vrrp[1102]: (keepalive_vi) Master received advert from 192.168.1.151 with higher priority 111, ours 110
Jul  8 15:10:47 keep2 Keepalived_vrrp[1102]: (keepalive_vi) Entering BACKUP STATE

WEBブラウザで仮想IPアドレス相手に [http://192.168.1.153] でアクセスするとこれが出ました。
やっぱりこれも想定通りです。
keep1の画面3

サーバーは動いているけど、NGiNXの生死を契機に仮想IPアドレスが行ったり来たりしていますね。

言うなれば、keepalivedの監視とは、単に [priority]値を上げ下げするだけ、そういう仕組みと考えて良いようです。


==========
この実験ではホームページの内容が違うので、[http://192.168.1.153] にアクセスした時に気付きますが、「同じ内容だったら気づくかな?」ってことです。

監視は複数のものを登録でき、サーバーがどのような状態になったらサービス提供続行不能状態とするかは設計者次第で如何様にも決められます。

逆に言えばその設計が結構難しいのではないかと思います。


この [priority]値の増減というやり方は keepalived独自のもので、他の製品ではまた違ったポリシーで実装が行われているのではないでしょうか。

それでも、クラスタリングソフトウェアの考え方に通底しているものは同じですので、この環境を作れるようになれば、仕事で商用ソフトを使うことになっても「keepalivedでは牙が強い方が勝つんだったな」と応用を効かせられると思います。


画像が無いけど、まだ続いているようです。

キリングバイツ(23) (ヒーローズコミックス わいるど) [ 村田真哉 ]

価格:792円
(2024/2/9 20:34時点)
感想(0件)


Amazonだと画像あり。
2024年2月28日発売だそうですよ。