イベントハンドラとは?
前回の記事で見たように、Serfエージェントをサーバ上で起動することで、簡単にネットワーク上にクラスタを構成できます。クラスタを構成後、Serfはネットワーク上で相互に死活監視するだけでなく、クラスタのメンバ管理(ホスト名・IPアドレス・タグ等を共有)を行えます。この監視状況やメンバの変化という「イベント」に応じて、シェルスクリプトやコマンドを実行する機能が「イベントハンドラ」です。
イベントハンドラは単純にコマンド実行するだけでなく、環境変数を通してSerfからスクリプトに様々なデータを渡せます。この仕組みを使い、コマンド実行時に動的に変わる引数(ホスト名・IPアドレス・タグ等)の指定や、動的に変わる環境に対する設定変更を行えます。
そのため、イベントハンドラの理解・習得が、Serfを使って自動化を進めるうえで欠かせません。とは言え、さほど難しい概念ではありませんので、身構えなくとも大丈夫です。
イベントは大きく2つに分類
Serfがイベントハンドラを実行するタイミングは、「イベント」の発生時です。イベントとはSerfクラスタ内で発生する出来事に対して定義します。イベントは(表1)のように2つに分類されます。1つは、クラスタ内のメンバ管理に関してシステムが自動的に発行するもので、もう1つはユーザが任意に発行するものです。
Serfが強力なのは、これらのイベント発生時、クラスタ内で瞬時かつ一斉にイベントハンドラを実行できる点です。従来の監視ツールでも、Serfのイベントハンドラと同様に一斉処理を行えるでしょう。しかし、監視サーバから監視対象のサーバやリソースを監視するため、障害発生から検出・対処までタイムラグが発生します。一方のSerfであれば、クラスタ全体に対して瞬時にイベントが伝わるため、各々のサーバ内で任意の処理を行えます。
表1 イベントの分類
メンバ管理 |
クラスタへのメンバ参加・離脱等のタイミングで自動的に発生するイベント |
member-join、member-leave、member-failed、member-update、member-leap |
カスタム |
ユーザが任意のタイミングで発生させるイベント |
user event、query |
イベントの種類
具体的にSerfが持つイベントの種類を見ていきます。Serfが「どの」タイミングで「何」を実行したいかを決めるのは、イベント種類の使い分けによります。
メンバ管理系イベント
「member-」で始まるイベントは、Serfによって構成されるクラスタ上において、メンバ変更のタイミングで自動発生します(図1)。
- 「member-join」
Serfクラスタに新しいメンバが参加(join)したタイミングで発生します。このとき、クラスタ全体に対して、新しいメンバがクラスタに参加したことが伝わります。具体的な使い方としては、クラスタ参加のタイミングでChefやPuppetなどの構成管理ツールを使う自動プロビジョニング処理に使えます。他には、パブリック・クラウド上に自動展開される仮想マシンのホスト名・IPアドレスの把握や、その情報を元に、監視設定の自動投入へ応用できます。
- 「member-update」
Serfエージェントが各々に対して設定できるタグを変更するときに発生します。このタグ機能は、「role=web」のように、任意のキー=バリューの組み合わせを設定できます。使い方としては、特定のタグの値に応じて、任意のコマンドの一斉実行や、プロビジョニング用スクリプトの実行に活用できます。
- 「member-leave」
Serfクラスタからノードが離脱(left)したタイミングで発生します。これは、Serfエージェントを「Ctrl+C」で中断するなど、正常に終了される場合です。明示的に停止したとSerfクラスタから判断されるため、以降はSerfクラスタからのヘルスチェックから除外されます。
- 「member-failed」
Serfクラスタとの通信が途絶した場合や、Serfエージェントが異常終了した場合に発生します。Serfクラスタからは一時的な障害とみなされるため、障害後も定期的なヘルスチェックが継続します。デフォルトでは、30秒です。この間隔は設定ファイル上でパラメータreconnect_interval
を使い、変更することができます。このイベントは、ロードバランサからの設定除外や、障害発生時の自動復旧コマンドの実行などに応用できます。また、member-leaveイベントとは違い、あくまで一時的な障害とみなされているため、エージェントとの通信が再開次第、クラスタに自動復帰します。
- 「member-leap」
member-leave
またはmember-failed
イベントによってクラスタから離脱後も、一定期間(標準では24時間)クラスタ内で情報が保持されます。この保持された情報を完全に削除するタイミングで発生するのが、このmember-leap
イベントです。クラスタに完全に離脱するとみなされるため、例えば、監視設定から永続的な設定削除に活用できます。
カスタムイベント
「user event」と「query」イベントは、どちらもユーザが任意のタイミングで発生できるイベントです(図2)。システムで自動発行されるイベントではありませんので、コマンドライン上でserf event <イベント名>
やserf query <イベント名>
のように実行します。
- 「user event」(ユーザイベント)
クラスタ上のサーバでコマンドを実行します。特定のサービスの再起動や、コマンドの実行をしたい場合に手軽に利用できます。
- 「query」(クエリ)
クラスタ上のサーバでコマンドを実行し、その実行結果を取得して標準出力に表示します。ユーザイベントと異なり、コマンドの処理結果を画面上で確認できます。サーバにログインすることなく、サーバ内の情報を取得できます。
カスタムイベントの特徴として、実行するサーバやPC上のSerfは、クラスタに参加している必要がありません。そのため、手元のPC上から-rpc-addr=
オプションを指定して、次のようにイベントを実行させることができます。複数台のサーバ上で一斉に処理を実行できるため、例えば障害発生後の一次対応をサーバにログインせず行うような応用が考えられます。
イベントハンドラの使い方
イベントハンドラを使うには、Serfエージェント起動時のオプションで、-event-handler=<コマンドスクリプト名>
の形式で指定します。より具体的な使い方と、イベントハンドラの自由度を高める環境変数の取り扱い方を見ていきます。
イベント発生毎に時刻を記録するには?
ここでは簡単な例として、イベント発生時にdate
コマンドの時刻を記録することを考えます。ファイル/tmp/serf.log
に書き出すには、次のように-event-handler=
オプションを使い、エージェントを起動します。
エージェント起動直後に/tmp/serf.log
を開くと、既に時刻が記録されていることが分かります。これは、エージェント自身をSerfクラスタとして認識するmember-join
イベントが発生したからです。
以降は、コマンドライン上でserf event check
のようにカスタムイベントを実行したり、クラスタへ他のエージェントを参加させたり離脱のタイミングで時刻が記録されます。
特定のイベント時のみ実行するには?
イベント発生毎に実行するだけでなく、特定のイベント時にだけ実行させることもできます。その場合は、エージェントを-event-handler=<イベント名>:<コマンドやスクリプト>
の形式で起動します。例えば、メンバ参加時(member-join)だけイベント発生時刻を記録したい場合は、次のようにして起動します。
この状態で再度serf event check
のようにユーザイベントを起動しても、テキストファイルには時刻は記録されません。そのかわり、member-join
イベント発生時は時刻が記録されることが分かります。
イベント名と時刻を記録するには?
時刻を記録するだけでなく、どのようなイベントが何時発生したかを確認できます。イベント名やノード名は、環境変数を通して取得します。ここではイベント名と時刻を記録するためのスクリプトevent.sh
を作成し、実行パーミッションを設定します。
エディタでファイルを編集し、次のように書き換えます。
それから、今度は次のようにevent.sh
をイベントハンドラとして実行します。
任意のイベントを発行したり、クラスタに新しくメンバが参加するイベントが発生したりすると、発生時の時刻やイベント名や付随する情報が記録されていることが分かります。
クエリを試すには?
イベントハンドラでquery
を指定し、ノード上から結果を取得したい場合は-event-handler=query=<コマンドまたはスクリプト名>
の形式でSerfエージェントを起動します。例えばuptime
コマンドを実行するクエリの指定は次のようにします。
このときに注意するのは、クエリを実行したいサーバすべてで-event-handler=
の指定が必要です。設定後、コマンドラインでserf query uptime
イベントを発生すると、次のように各サーバでuptime
コマンドを実行した結果が表示されます。
その他の環境変数と応用の仕方
Serfのイベント情報は、環境変数と標準出力を使って取得できます。これまで見て来たシェルスクリプトだけでなく、RubyやPerl・Pythonなどのスクリプトでも利用できます。そのため、環境変数SERF_EVENT
でイベント名を判別し、条件判定に応用することもできます。
主な環境変数は、以下の通りです。
SERF_EVENT
発生したイベント名です。ここにはmember-join
, member-leave
, member-failed
, member-update
, member-leap
, user
, query
が入ります。
SERF_SELF_NAME
イベントハンドラを実行する自分自身のホスト名です。
SERF_TAG_<タグ名>
<タグ名>で指定した値です。
SERF_USER_EVENT
ユーザイベントの名称が入ります。このときの環境変数SERF_EVENT
はuser
です。
SERF_QUERY_NAME
クエリの名称が入ります。このときの環境変数SERF_EVENT
はquery
です。
イベントハンドラと環境変数の関係を理解するには、GitHubで公開しているサンプルスクリプトが役に立ちます。serf-event.sh
を作成し、ログ出力レベルとデバッグモードにします。
起動後はSerfのクラスタに追加・削除したり、イベントを発行したりすることで、どのようにデータのやりとりしているか分かりやすいと思います。
まとめ
Serfには2種類のイベントがあり、それぞれのイベント発生のタイミングでイベントハンドラと呼ばれるスクリプトやコマンドを実行する方法を見てきました。
次回は、Serfをより細かく使いこなす方法を見ていきます。これまではコマンドライン上で、Serfの実行オプションを指定してきました。それだけでなく、一般的なツールと同様に、Serfは外部ファイルから設定を読み込む方法をご紹介します。
参考情報