これまではSerfの基本的な使い方や、Serfで構成されたイベントハンドラの動きを見てきました。今回はSerfに関する連載のまとめです。複数の仮想サーバ上にも応用可能なように、Dockerコンテナでの活用方法をご紹介します。また、より詳細な設定方法についての理解も進めていきます。
Dockerコンテナ群をSerfで管理する方法
DockerはLinuxコンテナを簡単に起動・管理するためのツールです。Dockerの魅力は、単純にコンテナを操作できる点だけではありません。公開レポジトリであるDockerHubを使ったコンテナの共有や、Dockerfile
と言う設定ファイルを使った構成管理の自動化などの利点があります。
コンテナ管理問題を解決するSerf
コンテナを多く立ちあげた時に発生するのは、沢山のコンテナを効率的に操作するのかという課題です。例えばコンテナ内のプロセス稼働状況や、設定ファイルの確認を行いたい場合を考えてみます。Dockerではsshdを稼働させなくとも、ホストOS側からdocker exec
コマンドを実行することにより、任意のコマンドを実行することができます。
docker exec
は、小回りの利く便利なコマンドです。しかし、操作対象のコンテナが1つや2つではなく、3つ・4つ・5つ……と数が増えると都度docker exec
を実行するのは手間になりがちです。また、操作対象が増えると、コンテナに対して適切な管理が必要になります(このコンテナの役割は何か? 何のアプリケーションを動かすのか? 誰が管理しているのか?)。
この問題を解決するために、テキストファイルやExcelなど、何らかの管理表を作成するのは1つの方法と言えます。とは言え、コンテナを簡単に立ち上げ、消せるのがDockerの利点です。これではコンテナ管理が面倒になり、本末転倒です。
そこで登場するのが、Serfを使ってコンテナ群を管理する方法です。Serfエージェントがクラスタを構成できるのは物理・仮想サーバ間だけでなく、コンテナとも通信することが可能です。Serfを使うことによって、次のような利点があります。
- メンバー管理の自動化
Serfがコンテナのホスト名とIPアドレスを自動的に管理するため、コンテナの起動・停止時に人手で管理する必要がありません。
- タグ機能でコンテナの役割を明確化
Serfはエージェントにタグを動的に付与でき、コンテナの役割や管理担当者の情報を動的に付与できます。
- イベントハンドラでコンテナ内の一斉操作
コンテナにログインすることなく任意のコマンドを一斉に実行できます。開発環境やテスト環境を問わず、有用な機能です。
いずれも手動でも行えますが、Serfであれば正確かつ迅速に行うことができます。しかも、これまでの連載で見て来たように、Serfそのものを使うために覚えることは少ないため、低い学習コストで高い効率性を得られるようになります。
図1は1つのホスト上で複数のコンテナを管理するイメージです。この図ではホストOS側・コンテナ群どちらもSerfでクラスタを構成しています。もちろん、ホスト側が不要であれば、コンテナ群だけでクラスタを構成することもできます。IPアドレスはコンテナ間の通信で使うためのものです。ホストOS側は172.17.42.1
で固定されているため、Serfエージェント起動時のクラスタへのジョイン先をこの172.17.42.1
にしておくと便利です。
自動的にSerfクラスタを構成するDockerfile
Dockerでコンテナを起動・停止するたびに、ホスト側のSerfエージェントに自動追加・削除する方法を見ていきましょう。Serfのセットアップを自動的に行うコンテナイメージを作成しておき、そのイメージを使ってコンテナを起動し、自動的にSerfのクラスタに参加するものです。また、コンテナ内にログインしなくても操作できるように、イベントハンドラでbash
を実行させてみます。
前提として、ホスト側では予めSerfエージェントがserf agent
等のコマンドで起動しているものとします。この時、Docker上のコンテナと通信時に使用する172.17.42.1
をバインドしている必要があります(通常は起動したままで自動的に認識しますが、serf agent -bind=172.17.42.1
として明示することもできます)。
自動的にSerfを起動するためにはDockerfile
を用います。Dockerには、コンテナ内部のOS設定やミドルウェア・アプリケーションを自動的に設定するための仕組みがあります。これはChefやPuppet・Ansibleのような構成管理ツールの機能を実現します。これを使う場合は、Dockerfile
という名称のテキスト形式のファイルを作成し、中にどのような環境を構築するか定義します。
作業用のディレクトリを作成し、そこに移動したあと、以下のDockerfile
を作成します。内容はcentos
のコンテナイメージの使用を明示し、wget
とunzip
パッケージの取得を行っています。それからserfのアーカイブを取得・展開し、バイナリをコピーの後、自動的にserfを起動するものです。
次に、このDockerfile
を元にdocker build
コマンドを使い、イメージのビルドを行います。次の例ではserf-centos
というタグを付けていますが、<ユーザ名>/serf-centos
など、任意のタグ名を使うことができます。
画面上にSuccessfully
と表示されれば、正常にserf-centos
という名称のコンテナイメージが作成できました。次は、このコンテナイメージを使って起動します。docker run
コマンドを使い、コンテナをデーモンとして立ち上げてみます。
コンテナが正常に稼働しているかどうかは、docker ps
コマンドで確認することができます。ここでは自動的にSerfクラスタを形成しているか確認するためにserf members
コマンドを実行してみます。正常であれば、次のようにホスト側と起動したコンテナのホスト名・IPアドレスの情報を確認することができます。
同時に複数台の起動も試してみましょう。先ほど同様docker run -d serf-centos
を数回実行した後、serf members
コマンドを実行します。次のように、やはり自動的に追加されていることが確認できます。
コンテナ内をserf queryを使って同時操作
Serfのイベントハンドラssh
を使い、コンテナにログインすることなく、コンテナ内で一斉にコマンドを実行してみます。引き続きホストOS上で作業を行います。ここで実行するのは、前回の連載で使用したserf query
コマンドを使用します。任意のコマンドを実行するにはserf event
またはserf query
を使う方法がありますが、ここでは結果を実行した画面に表示させたいためquery
形式を定義していました。結果を知る必要がなければevent
形式でも構いません。
例として、コマンドserf ssh uptime
を実行してみます。正常に処理されると、次のように各コンテナ内部でuptime
が実行され、その結果が表示されます。それぞれのコンテナ内では、イベントssh
が発生すると、/bin/bash
と引数としてのコマンドを実行した結果が表示されます。
ほかにもps
コマンドでプロセスの状況を知ることもできます。
これはあくまで一例ですので、cat
やyum
コマンドだけでなく、様々なコマンドを実行することができます。また、イベントハンドラの例として/bin/bash
を指定しました。しかしroot権限で何でも実行できてしまうため、インターネット上の共用環境など、セキュリティ上で好ましくない場合、特定のコマンドのみ実行可能なイベントハンドラを作っておくことを強く推奨します。
メンバー管理とタグ
Serfはエージェントのメンバー毎にタグを付ける機能があります。コンテナを複数起動している場合、そのコンテナの役割や目的を記録するために、タグの機能を使えます。タグの情報はserf members
コマンドで参照できるだけではなく、イベントハンドラ内でも変数として利用できます。そのため、タグ機能を応用すると、イベントハンドラ内で特定のタグを持つコンテナやサーバのみコマンドを実行させる使い方もあります。
タグを指定するにはserf tags -set <key>=<value>
の形式でコマンドを実行します。コマンドの実行は、ホストOS、コンテナ内どちらでも構いません。以下はrole=admin
というタグを設定し、serf members
コマンドで見た結果です。
タグの削除はserf tag -delete <key>
の形式で指定します。また、エージェント起動時にタグを指定することも可能です。
Serfの詳細設定
Serfエージェントの様々な設定は、serf
コマンドの引数で指定する方法と、外部の設定ファイルを使って定義する方法があります。ここでは、より細かな設定方法と合わせて、使い方を見ていきます。
外部の設定ファイルを使う方法
Serfを同じ設定で起動・停止したい場合や、複数のSerf動作環境で同じ設定を適用したい場合は、外部ファイルの利用が手軽です。ファイルは次のようなJSON形式で定義します。
このJSON形式のファイルを作成した後、Serf起動時に-config-file=
オプションを指定します。
JSON形式の場合は、Serfの設定変更と反映が簡単になります。エージェント起動後でも設定変更したい場合は、対象のJSONファイルを修正後、kill -1 <serfのPID>
を実行します。
Serfの便利オプション
Serfには様々なオプションが用意されています。ここでは、その中でも主に使う主要なものを紹介していきます。なお説明は「JSONファイルでの指定名 ( -コマンドラインのオプション )」の形式です。
node_name
(-node)
Serfクラスタ内の自分のノード名称を指定するもので、serf members
コマンド実行時に表示されます。省略時は自分自身のホスト名が利用されます。なお、Serfクラスタ内でノード名称の重複はできないため、設定ファイルをコピーして流用する時は注意が必要です。
- 設定ファイル:"node_name": "dev01"
- コマンドライン:serf agent -node=dev01
bind
(-bind)
Serfエージェントが内部の通信で利用するIPアドレスを指定します。通常は指定する必要はありませんが、サーバが複数のインターフェースを持っている場合、どのIPアドレスを使うか明示するために使います。
- 設定ファイル:"bind": "192.168.39.3"
- コマンドライン:serf agent -bind=192.168.39.3
interface
(-iface)
Serfが利用する標準インターフェース名を指定します。複数のインターフェースを持っている環境で多用します。
- 設定ファイル:"interface": "eth1"
- コマンドライン:serf agent -iface=eth1
badvertise
(-advertise)
Serfクラスタ内の自分のIPアドレスを指定します。bind
の指定に似ていますが、こちらはインターフェースが複数のIPアドレスを持っている場合や、NATの環境で明示したい時に使います。
- 設定ファイル:"advertise": "192.168.39.1"
- コマンドライン:serf agent -advertise=192.168.39.1
discover
(-discover)
マルチキャストDNS(mDNS)がネットワーク内で利用可能な場合にオプションを指定すると、serf join
で参加するクラスタを明示しなくても自動的にクラスタを形成します。この引数として指定したクラスタ名と一致する場合に自動参加します。
- 設定ファイル:"discover": "development"
- コマンドライン:serf agent -discover=development
encrypt_key
(-encrypt)
Serfで暗号化したネットワーク通信を行う場合に使う秘密鍵を指定します。予めserf keygen
コマンドで生成した文字列を引数として使います。暗号化してクラスタを形成すると、ここで指定した鍵が一致しないとクラスタに参加できません。
- 設定ファイル:"encrypt_key": "<文字列>"
- コマンドライン:serf agent -encrypt=<文字列>
log_level
(-log-level)
Serfエージェント起動後に標準出力されるログの粒度を指定します。種類には情報が多い順にtrace、debug、info、warn、errを選べます。デフォルトはinfoです。
- 設定ファイル: "log_level": "debug"
- コマンドライン: serf agent -log-level=debug
start_join
(-join)
Serfエージェント起動時、どのSerfエージェントと通信を開始してクラスタを形成するか明示します。
- 設定ファイル:"start_join": "192.168.39.1"
- コマンドライン:serf agent -join=192.168.39.1
その他にも設定用のオプションがあります。詳細はSerfのConfigurationページが参考になります。
まとめ
Dockerを使ったコンテナ環境に対しても、Serfを使えばコンテナにログインすることなくコマンドの実行が可能です。また複数のコンテナに対しても同時に実行できます。これはコンテナだけでなく、複数のサーバ環境にも応用できます。皆さんの環境なり現場で作業の効率化・正確さが必要な場面があれば、Serfのことを思い出して使っていただければと思っています。Serfそのものは単なるツールにしかすぎませんが、イベントハンドラを工夫することで、十徳ナイフのように有用なものへと活用できるでしょう。
参考情報