自動化・省力化のためのSerf入門
Serfが必要とされる理由
複数のサーバ環境上で、一斉にセットアップ用やデプロイ用のコマンドを実行したり、バージョン番号の確認を行ったりするためには、どのような方法が最適でしょうか。管理対象が数台程度であれば、毎回手打ちでSSHログインを実行し、コマンドを実行する方法もありでしょう。
しかし、その作業が同じ手順の繰り返しである場合や、システムにおける作業対象が十数台~数百台まで増えたとしたらどうでしょう? 人の手で行うとなると、作業にかかる時間が増える上に、作業ミス発生のリスクも高まります。ミスを防ぐためには、チェックの仕組みも必要となります。たとえそれが単純な作業だったとしても、システム全体としては非常に面倒なものになりがちです。
このような問題を解決するためのツールとして、parallel-sshが挙げられます。parallel-sshは名称の通り、ある環境上から対象となるサーバ群に対してSSHで同時ログインを行い、指定したコマンドを自動実行するためのツールです。
ただし、parallel-sshは純粋に並列にSSHを処理するためのツールです。そのため、SSHでログインするための環境が必須であり、OSやセキュリティによる制約を受けがちです。また最近では、sshdが稼働していないLinuxコンテナへは適用し辛いといった状況も生じつつあります。
このような場面で活躍するツールがSerfです。Serfは、複数台のサーバ環境上で一斉処理を行うためのオーケストレーション機能を備えています。またSerfは、単純に処理を実行するだけではなく、Serfによって構成されるクラスタの状態変化、たとえばサーバの追加や離脱、あるいは障害発生状況をトリガとして、様々なコマンドを自動実行できます。
クラウド環境だけでなく、Linuxコンテナ環境の普及によって、サーバ環境そのものが動的に変わることが当たり前になりつつあります。サーバの増減というタイミングで、自動的に環境のセットアップやデプロイをしたり、設定ファイルを書き換えたりすることも、Serfを使えばシンプルに自動化することができます。
以降では、実際にSerfをセットアップし、クラスタ上でオーケストレーションを行うための方法を見ていきましょう。
Serfのセットアップとエージェントの起動
セットアップ
Serfのセットアップは非常にシンプルです。Serfでオーケストレーションを行いたいサーバ上で、実行用のバイナリファイルをパスの通った場所に置きます。以下はLinux上(64bit)でのセットアップ例です。シンプルなものなので、クラウドや構成管理ツールのプロビジョニング・スクリプト等に組み込む設定が便利です。また、WindowsやMac OS X、FreeBSD向けのバイナリも提供されています。
$ wget -O 0.6.4_linux_amd64.zip https://dl.bintray.com/mitchellh/serf/0.6.4_linux_amd64.zip $ unzip 0.6.4_linux_amd64.zip $ sudo cp ./serf /usr/bin/serf
正常にセットアップされたかどうかの確認のために、コマンド「serf version」を実行し、バージョン番号を表示してみましょう。
$ serf version Serf v0.6.4 Agent Protocol: 4 (Understands back to: 2)
エージェントの起動とSerfクラスタ形成
Serfを使ってオーケストレーションを行うためには、複数のサーバ上のserfエージェントが相互に通信するためのクラスタを構成する必要があります。そのためには、あるサーバでserfエージェントを起動した後、別のサーバ上で起動しているserfエージェントが、クラスタに参加(join)する命令を送る必要があります。
ここでは2台でSerfクラスタを構成してみます。まず、1台目のサーバ上でserfエージェントを起動するために「serf agent」とコンソール上で実行します。クラウドなど、複数のネットワーク・インターフェースを持つ環境では、次の例のように「-bind」オプションを使い、Serfが使用する環境を明示できます。
$ serf agent -bind=192.168.39.11 ==> Starting Serf agent... ==> Starting Serf agent RPC... ==> Serf agent running! Node name: 'node1.pocketstudio.net' Bind addr: '192.168.39.11:7946' RPC addr: '127.0.0.1:7373' Encrypted: false Snapshot: false Profile: lan ==> Log data will now stream in as it occurs: 2015/05/17 04:46:55 [INFO] agent: Serf agent starting 2015/05/17 04:46:55 [INFO] serf: EventMemberJoin: node1.pocketstudio.net 192.168.39.11 2015/05/17 04:46:56 [INFO] agent: Received event: member-join
次に、もう一台の環境からもSerfエージェントを起動します。今度は「-join」オプションを使い、先ほど起動した環境のIPアドレスを指定します。
$ serf agent -bind=192.168.39.12 -join=192.168.39.11
クラスタ形成に成功すると、画面上に「agent: Received event: member-join」というメッセージが表示されます。より詳細な情報を見るためには「serf members」コマンドを実行します。どちらのサーバで実行しても、次のようなメンバー情報が表示されます。
$ serf members node1.pocketstudio.net 192.168.39.11:7946 alive node2.pocketstudio.net 192.168.39.12:7946 alive
さて、これでオーケストレーションの準備が完了しました。Serfのサーバを増やす場合は、同じように「-join」を使ってIPアドレスを指定します。IPアドレスは1台目のものである必要はありません。既存のクラスタに参加しているIPアドレスであれば、どれでも使えます。これは、Serfがクライアント・サーバ型ではなく、全てが対等な関係でクラスタを構成しているためです。
Serfがユニークなのは、「中央にあるサーバ」という概念が存在しない点です。クラスタに参加するメンバーであれば、誰でも命令を送ることができます。そのため、クラウドやコンテナのように、刻々とインフラが変化する環境においても、柔軟な自動処理を行うことができるのです。それでは、実際にコマンドを実行してみましょう。
オーケストレーション機能を使う
複数台のサーバ上で同時に処理を行うオーケストレーションのためには、イベント・ハンドラ(event handler)を定義します。イベント・ハンドラとは、Serfクラスタ上のイベント発生に応じてスクリプトやコマンドを実行するための仕組みです。このイベントには、2種類あります。1つは、任意のタイミングで実行できるもの。もう1つは、Serfクラスタ上のメンバー情報に関するもので、システムによって自動発生するものです。
リモートSSH風のイベント・ハンドラを作成するには
任意のタイミングで、複数のサーバやコンテナ上で任意のコマンドを実行するための設定をしてみましょう。コマンドの処理結果を取得するには「query」というSerfイベントを指定します。ここでは例として、「ssh」という名称のqueryイベント時、サーバ内で「/bin/bash」を実行するものとします。
このイベント・ハンドラを指定するには、コマンドを実行したい対象サーバ上で設定を行います。Serfエージェント起動時のオプションで、次のように「-event-handler」を指定します。
$ serf agent -event-handler=query:ssh=/bin/bash
このように指定したイベント・ハンドラを実行するには、コマンドライン上で「serf query」コマンドを使います。先ほど定義したsshイベントで「uptime」コマンドを実行するには、次のようにします。
$ serf query ssh uptime Query 'ssh' dispatched Ack from 'node1.pocketstudio.net' Ack from 'node2.pocketstudio.net' Response from 'node2.pocketstudio.net': 05:25:34 up 21:31, 1 user, load average: 0.00, 0.00, 0.00 Total Acks: 2 Total Responses: 1
ここでは2台のサーバのうち1台のみイベント・ハンドラを定義していたので、結果が表示されるのは1台だけです。もう1台でも同様にイベント・ハンドラを指定すると、同じように結果を確認することができます。
ここでは注意しておくべきは、Serf実行時の権限であらゆるコマンドが実行できてしまう点です。セキュリティに考慮する必要がある環境では、/bin/bashを直接指定するのではなく、特定のコマンドのみをイベント・ハンドラとして定義するような考慮をお勧めします。
その他のイベントを指定するには
ここまでは、シンプルにコマンドを実行する方法を紹介しました。他にも、Serfを使えばクラスタの状態変化に応じてコマンドを自動実行することができます。自動実行できるイベントを以下の表に示します。
イベント | 発生条件 |
---|---|
member-join | クラスタにメンバーが新規参加した時に発生 |
member-leave | クラスタからメンバーが離脱した時に発生(正常終了時) |
member-failed | メンバーの異常終了や通信不能状態が生じた時に発生 |
member-update | クラスタのタグ情報を更新時に発生 |
member-reap | クラスタのメンバー離脱から24時間後、対象メンバー情報の削除時に発生 |
イベントの詳細な指定方法については、Serfのイベント・ハンドラのページが参考になります。また、拙作のブログでもイベントの詳細を扱っていますので、興味がありましたらご覧ください。
まとめと次回の予定について
複数台のサーバ環境上において、Serfを使えば様々な作業を効率的に行うことができます。しかし、自動的な処理にはSerfを使ったクラスタ参加状態をトリガとする必要があり、サーバの中のプロセスやサービス稼働状況は考慮されていません。このSerfの弱点をカバーするのが、Consulです。次回は、今回のSerfの応用としてConsulを使ったオーケストレーション機能をご紹介します。
※本稿は、2015年7月現在のSerf v0.6.4に対して確認を行っています。
【参考文献】
- Serf(アクセス:2015/07)
- Event Handlers(アクセス:2015/07)
- 【Serf】イベントハンドラを整理してみる(アクセス:2015/07)
- Serf Documentation(アクセス:2015/07)