コンテナ/クラウド環境におけるSerfを使った構成管理 3ページ
Serfによるクラスタの管理
Serfでは、「serf members」コマンドでクラスタに参加しているノードの情報を確認できる。たとえば以下の例では、「centos11」というノード(192.168.1.11)と、「centos10」というノード「192.168.1.10」がクラスタに参加していることが分かる。
$ serf members centos11 192.168.1.11:7946 alive centos10 192.168.1.10:7946 alive
なお、ここで表示される最後のカラムはそのノードの状態を示しており、「alive」はそのノードが正常稼動していることを意味している。また、クラスタに参加した後にSerfエージェントが正常終了されたノードについては「left」、何らかの問題でSerfエージェントとの通信ができなくなっているノードについては「failed」と表示される。
クラスタ内で何らかのイベントが発生した場合に実行されるイベントハンドラ
Serfでは、クラスタへのノードの加入や脱退、停止、状態の更新といったイベントの発生時に、あらかじめ指定しておいたコマンドを実行する機能が用意されている。実行するコマンドは、「node agent」コマンドの「-event-handler=<コマンド>」オプションで指定する。これはエージェントの起動時に指定しておく必要がある点に注意が必要だ。
たとえばイベントの実行時に「/etc/serf/handler.sh」というスクリプトを実行するには、エージェントの起動時に以下のようなオプションを追加すれば良い。
-event-handler=/etc/serf/handler.sh
コマンドの実行時には、「SERF_EVENT」という環境変数に発生したイベント名が格納されるので、スクリプト内ではこれをチェックして対応する処理を実行させることになる。イベント名としては表1のものが定義されている。
イベント名 | 説明 |
---|---|
member-join | クラスタに新たなメンバーが追加された |
member-leave | クラスタからメンバーが脱退した |
member-failed | クラスタのメンバーが反応しない |
member-update | クラスタメンバーの状態が更新された |
member-reap | クラスタのメンバーが反応せず、かつその後一定のタイムアウト時間が経過した |
user | ユーザー定義のイベント |
query | ユーザー定義のクエリ |
これを利用して、たとえばクラスタにメンバーが追加された場合に特定の処理を実行する、といったことが実現できる。
ユーザー定義イベント/クエリを使う
「ユーザー定義のイベント」は、ユーザーが任意のタイミングで発生させられるイベントだ。イベントを発生させるには、「serf event <イベント名> <ペイロード>」コマンドを使用する。この場合、実行されたコマンド(イベントハンドラ)では「SERF_USER_EVENT」環境変数で指定されたイベント名を参照でき、またペイロードとして指定されたデータは標準入力から取得できる。
また、ユーザー定義のイベントと似たものとして「ユーザー定義のクエリ」がある。こちらは「serf query <クエリ名> <ペイロード>」で発生させることができる。ユーザー定義のイベントと異なるのは、各ノード上での実行結果(標準出力への出力)が「serf query」コマンドの実行側で表示される点だ。
そのほか、クエリやイベントの実行時には環境変数経由で次のような情報を取得できる。
イベント名 | 説明 |
---|---|
SERF_EVENT | イベント種別 |
SERF_SELF_NAME | イベントハンドラを実行するノードの名前 |
SERF_SELF_ROLE | イベントハンドラを実行するノードのロール |
SERF_TAG_${TAG} | イベントハンドラを実行するノードに指定されたタグ |
SERF_USER_EVENT | ユーザーイベント名 |
SERF_USER_LTIME | イベント発生時のタイムスタンプ |
SERF_QUERY_NAME | ユーザークエリ名 |
SERF_QUERY_LTIME | クエリ発生時のタイムスタンプ |
たとえばイベントハンドラとして「/etc/serf/handler.sh」というシェルスクリプトを指定しておき、ここに次のような内容を記述しておけば、「yum_update」というクエリを実行することで各ノードで一斉に「yum update -y」コマンドを実行することができる。
#!/bin/sh # ↓クエリイベントによってイベントハンドラが実行されたかどうかをチェック if [ "$SERF_EVENT" == "query" ]; then # ↓クエリ名をチェック if [ "$SERF_QUERY_NAME" == "yum_update" ]; then # ↓条件に合致していればコマンドを実行 yum update -y fi fi
実際に「serf query」コマンドでこのクエリを実行した場合の出力結果は以下のようになる。
# serf query yum_update Query 'yum_update' dispatched Ack from 'centos10' Ack from 'centos11' Response from 'centos10': Loaded plugins: fastestmirror, priorities Loading mirror speeds from cached hostfile No packages marked for update Response from 'centos11': Loaded plugins: fastestmirror, priorities Loading mirror speeds from cached hostfile No packages marked for update Total Acks: 2 Total Responses: 2
ここでは、「Response from ‘centos10’」以下で「centos10」ホストでの実行結果が、「Response from ‘centos11’:」以下で「centos11」ホストでの実行結果が表示されている。
シンプルなツールだからこそ使い方に工夫が必要
Serfの備える機能はシンプルであるため、使う側で色々と工夫する必要があるが、その代わりさまざまな機能を実現できる。たとえばイベントハンドラ内でユーザーイベントに応じてサーバーの設定をリロード/変更/再起動するような記述を行うことで、クラスタ内のサーバーの設定をまとめて変更する、といった処理を実現できる。
また、バイナリファイル1つを配置するだけで利用できるため、コンテナとの相性も良い。すでに稼動しているホストのIPアドレスが分からない状態でも、簡単にクラスタにホストを追加できるというメリットもある。そのため特に有用なのが、SerfとDockerクラスタの組み合わせだ。そこで次回は、SerfとDockerクラスタを組み合わせ、さまざまな処理を自動化する例を紹介する。