管理下のWebサーバが止まったら、速やかに管理者の携帯端末へメールで通知する。そんな死活監視システムを、無償のソフトウェア・ツールとバッチ・ファイルを組み合わせて簡単かつ手軽に実現しよう。
サーバ管理者が行うべき作業はいくつもあるが、その中でも特に重要なのが「予期せぬサーバの停止」の検出とその対処だろう。いうまでもなくサーバが停止していることが分かったら、なるべく早く復旧に向けて対応しなければならない。そのためには、普段からサーバを継続的に監視しておき、停止などの異常があれば速やかに検出して、管理者に知らせる必要がある。
社内設置のサーバであれば特段の監視体制を用意せずとも、その異常に気付きやすい。距離的にもネットワーク的にも「身近」であり、また周りのスタッフが異常を知らせてくれることもあるからだ。だが、ホスティングやデータセンターのような遠隔地に設置されたサーバは、ある程度きっちりと監視していないと、停止などの異常事態に気付きにくい。
そこで本稿では、ホスティングなどで運用しているWebサーバを対象に、実際に筆者が構築・運用している簡易な死活監視の例を紹介する。これは無償のソフトウェア・ツールとバッチ・ファイルを組み合わせて自動化したもので、Windows PCさえあれば実現できる簡単で手軽なものだ。本格的なプログラミングの技術は不要である。もちろん専門企業による有償の死活監視システムに比べれば網羅的でも本格的でも厳重でもないが、それでもサーバの停止から数分で筆者の携帯電話に通知が届くため、大いに役立っている。
手軽な死活監視といえば、すぐ思い付くのはpingコマンドだろう。サーバやNAS、ルータ、無線LANアクセス・ポイントなどネットワークに接続された機器の場合、何かトラブルが認められたら、まずはそのサーバにpingを送ってみて応答があるかどうか確認するのが常套手段だ。
では、インターネット上の公開サーバに対しても、pingを使って確認する方法は通用するのだろうか? 以下は筆者が管理している公開Webサーバにpingを送ってみた結果である。
C:¥temp>ping locationsmart.org
locationsmart.org [112.78.119.239]に ping を送信しています 32 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
112.78.119.239 の ping 統計:
パケット数: 送信 = 4、受信 = 0、損失 = 4 (100% の損失)、
C:¥temp>
このとき、このlocationsmart.orgは明らかに正しく稼働していたが(Webブラウザでは正しくアクセスできたため)、何度pingを送っても100%応答がなかった。だがこれは正常な反応である。というのも、サーバ側でpingコマンドのパケットをそもそも受信しないようにファイアウォールでブロックしているからだ。セキュリティの観点から「不要なサービスは止めておく」ことはインターネット・サーバでは当然であり、不正なpingパケットを使ったDoS攻撃などもあるため、pingに応答しないように設定していることは珍しいことではない。
となると、監視対象のサービス(ここではWebサービス)が稼働しているかどうかを判断するには、サイトそのものにアクセスして応答を確認すべきだ。理屈としては、対象のWebページの読み出しを定期的に自動実行して、エラーが生じたり読み出し内容がおかしかったりすればアラートを上げればよさそうだ。
問題は、どのようなツールで定期的なページ読み出しを自動化するのか、という点だ。Webブラウザによってはさまざまな処理を自動化できるらしいが、それにはJavaScriptなどのスクリプト言語を駆使する必要があるようで、正直なところハードルが高い。それよりはWebページを読み出せるコマンドライン・ツールなどを用意して、使い慣れた(!)バッチ・ファイルから呼び出すようにすれば簡単そうだ。
ここでは無償利用できる「Wget for Windows」を使ってみよう。これは、HTTP/HTTPS/FTPでリモートのファイルを取得するツール「GNU Wget」のWindows向け実装の1つである。Windows 2000〜Windows 7で利用できるとのことだが、筆者が試した限りではWindows 8.1 Preview版でも動作した。
インストールするには、まず上記ページの「Download」にあるアーカイブ・ファイル一覧のうち、「Complete package, except sources」の「Setup」というリンクをクリックして、「wget-<バージョン番号>-setup.exe」というインストーラをダウンロードする。これを実行してウィザードの指示どおりにインストールする。このとき、「Select Destination Location」という画面でWgetのインストール・パスが表示されるのでメモしておく。
ここで設定を1つ加える。実行時にいちいちWgetのありかをフル・パスで指定するのは面倒なのでWgetをインストールしたパスを実行ファイル検索パスに登録しよう。それには、コントロール・パネルの[システムとセキュリティ]−[システム]を開き、左メニューから[システムの詳細設定]をクリックして「システムのプロパティ」の[詳細設定]タブが表示されたら、[環境変数]ボタンをクリックする。「環境変数」ダイアログが表示されたら、「システム環境変数」にある[PATH]をダブルクリックし、その「変数値」の先頭に、先ほどメモしたWgetのパスに「\bin;」を加えた文字列を挿入する(実行ファイルwget.exeはbinフォルダに格納されているため)。デフォルトでは、挿入すべき文字列は次のようになる。
あとは[OK]ボタンをクリックしていって各ダイアログを閉じれば、パスの設定は完了だ。
さっそくWgetでWebページを読み出してみよう。コマンド・プロンプトを開いて「wget <WebページのURL>」と実行すると、次のようにWebページのHTMLファイル(ここではindex.php)がダウンロードされるはずである。ちなみにオプション一覧は「wget --help」で表示される。
C:¥temp>wget http://locationsmart.org/index.php
SYSTEM_WGETRC = c:/progra~1/wget/etc/wgetrc
syswgetrc = C:¥Program Files (x86)¥GnuWin32/etc/wgetrc
--2013-07-10 15:26:15-- http://locationsmart.org/index.php
locationsmart.org をDNSに問いあわせています... 112.78.119.239
locationsmart.org|112.78.119.239|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK ……「200」はHTTPの戻り値
長さ: 6667 (6.5K) [text/html]
`index.php' に保存中
100%[======================================>] 6,667 --.-K/s 時間 0.007s
2013-07-10 15:26:15 (959 KB/s) - `index.php' へ保存完了 [6667/6667] ……ダウンロードされたファイル
C:¥temp >
以上は正常に読み出せた場合の応答だが、何か障害が発生したときにはどのような応答が返されるのだろうか? いくつかの障害を想定してWgetを実行したときの応答を下表にまとめてみた。
障害の種類 | 試したWgetのコマンドライン | Wgetの戻り値 | Wgetの出力メッセージ(一部) | ダウンロードされたファイル |
---|---|---|---|---|
Webサーバが応答しない | wget http://<正しいドメイン>:81/<正しいパス>/index.php | 1 | locationsmart.org|112.78.119.239|:81 に接続しています... 失敗しました: Connection timed out. | (生成されない) |
Webページがなくなった | wget <存在しない「indexxxx.php」へのURL> | 1 | HTTP による接続要求を送信しました、応答を待っています... 404 Not Found | (生成されない) |
Webページが書き換わった | wget <別のindex.phpへのURL> | 0 | HTTP による接続要求を送信しました、応答を待っています... 200 OK | index.php(内容は、正しいindex.phpと異なる) |
DNSサーバが誤った名前解決の結果(IPアドレス)を返す | wget <別ドメインにあるindex.phpへのURL> | 0 | HTTP による接続要求を送信しました、応答を待っています... 200 OK | index.php(内容は、正しいindex.phpと異なる) |
正常な場合 | wget <正しい「indexxxx.php」へのURL> | 0 | HTTP による接続要求を送信しました、応答を待っています... 200 OK | 正しいindex.php |
障害発生を想定してWgetを実行した結果 公開サーバを実際に落としたりページを削除したりするのは気軽にできないので、正しくないURLを指定することで各種障害をエミュレートしてみた。 |
「Wgetの戻り値」とは、Wgetコマンドが返す終了コードの数値である。一般的なコマンドでは、正常終了すれば0を返し、何らかのエラーがあると0以外の値(1以上の値)を返すようになっている。バッチ・ファイルなら、「if errorlevel <数値>」文で判定したり、「%errorlevel%」変数で参照したりできる。
Wgetの場合、正常終了した場合だけでなく、正しくないアクセスの場合でも0が返されることがある。上表のように対象のWebページの内容が書き換えられたり、DNSサーバによる名前解決が間違っていたりした場合でも、Wgetは指定URLから何らかのHTMLファイルのダウンロードに成功すれば「0」を返すからだ(この挙動自体はまったく真っ当であり、Wgetが悪いわけではない)。
このように、Wgetの戻り値だけでは障害の有無を判定できず、ダウンロードされたHTMLファイルの内容も調べざるを得ないことが分かった。とはいえ、HTMLファイルすなわちWebページの内容はたいてい、コンテンツ更新などによってころころと変わってしまうため、ファイル全体を何らかのリファレンスと比較・照合することは難しい。となれば、Webページの中で滅多に変わらない個所、例えばヘッダーやフッターの中に、そのページ/サイトでユニークな文字列が含まれているかどうか判定するのが簡単そうだ(もちろん完全ではないけれど)。
HTMLのようなテキストのファイルに特定の文字列が含まれているかどうか判定するには、Windows OS標準コマンドのfindが使える。
type index.php | find /I ">新着マップなど、最新情報発信中!</p>"
このコマンドラインを実行すると、ダウンロードされたindex.phpに「>新着マップなど、最新情報発信中!</p>」という文字列が含まれていれば(ヒットすれば)、戻り値「0」が返される(含まれていなければ「1」が返される)。ちなみに「/I」オプションは英字の大文字/小文字の違いを無視するという指定である。
ところが実際に試すと、検索文字列に日本語が含まれている場合、まったくヒットしない。そこでtypeコマンドでindex.phpを表示したところ、日本語がすべて文字化けしていた。
C:¥temp>type index.php
<!DOCTYPE html>
……中略
<div id="logoLocasma"><a href="/"><img src="/image/logo40@2x.png" alt="
繝ュ繧ア繧ケ繝・繝槭ャ繝励Λ繧、繝悶Λ繝ェ縺ク"></a></div> ……文字化けしている
<div class="linkHelp"><a href="/help/007maplib/"><img src="/image/icon_h
atena-hlptop.png" alt="繝倥Ν繝励・繝シ繧ク縺ク"></a></div> ……ここも文字化けしている
……後略
いまどきのWebページはUTF-8でエンコードされていることが多いが、Windows OS標準のコマンドはたいていUTF-8に対応していない。そのためtypeコマンドもfindコマンドも、UTF-8で記述されたindex.phpの日本語を正しく取り扱えず、検索にヒットしなかったのだ。
ならば、index.phpの文字コードを、これらのコマンドが対応しているShift JISへ変換してから検索すればよい。文字コードの変換には、無償で利用できるnkfコマンドが便利だ。
上記のTIPSの「操作方法」に記載の通り、nkfコマンドのインストール・アーカイブから「\vc2005\win32(98,Me,NT,2000,XP,Vista,7)Windows-31J\nkf32.exe」を取り出して「nkf.exe」にリネーム後、実行パスに含まれるフォルダに保存しておく。nkfコマンドでUTF-8からShift JISに変換してからfindコマンドで検索するには、次のように実行する(ちなみにオプション一覧は「nkf --help」で表示される)。
C:¥temp>nkf -W8 -s index.php | find /I ">新着マップなど、最新情報発信中!</p>"
<p style="font-size:80%;margin-bottom:5px;">新着マップなど、最新情報発信中!</p> ……検索にヒットすると、その文字列を含む行が表示される
C:¥temp>
この検索にヒットしなかった(戻り値が「1」以上だった)場合は、次のように一律に「障害発生中」と判定すればよいだろう。
nkf -W8 -s index.php | find /I ">新着マップなど、最新情報発信中!</p>"
if errorlevel 1 goto TROUBLE
{正常と判定されたときの処理}
goto END
:TROUBLE
{障害発生中と判定されたときの処理}
Copyright© Digital Advantage Corp. All Rights Reserved.