2015.03.09

Consul を利用したオーケストレーションの検討


いくつかのシステム運用に関わっている D.M. です。運用改善に向けた調査をしていた際に、サービス検知&ヘルスチェック&オーケストレーションツールとして非常に高機能な Consul の導入を検討をしたのでご紹介します。




Consulとは?


公式サイト: http://www.consul.io/

Consul は、サービス検出と設定のためのプロダクトです。各サーバ内のエージェントによってサービス(Webサーバやデータベース)の状態を監視し、サービスの新規追加や問題発生時に、KVS を通して各サーバ間で情報を共有し、設定を変更などの処理を実行することができます。

Consul は Vagrant や Serf を管理している Hashicorp 社により2014年に発表されました。すでにデータセンターをまたぐ大規模な環境で利用実績があるようです。

英語を日本語的に発音すると読み方はコンスルになります。

どのような問題を解決するか?


よく挙げられるユースケースは以下のようなものです。

・ Web サーバに障害が発生。アクセスできない。
⇒ 該当のサーバのサービスへアクセスが行かないようにバランサーからの切り離す。またはウェブアプリケーションのメンテナンスモードを有効にする。

・DB Master に障害が発生。書き込み処理ができない。
⇒ DB Slave の最新のものをMasterに変更。各Webサーバからの書き込み処理を新Masterに向け直す。

・Webサーバの負荷が一定以上まで上昇した。
⇒ 負荷分散させるために新たにWebサーバを追加。バランサーへの追加と監視項目の設定を行う。

上記のような運用フェーズにおける問題発生時には、いずれもクラスタ内のサーバの状態を検知し、各サーバのサービスの設定を変更することが必要です。クラウド環境に移行し、サーバの生成と破壊を繰り返す運用が一般化してきたことで、IPアドレス自体も普遍ではなく変化しやすい状況になってきています。Consul ではクラスタ内のサーバが増えた段階で IP アドレスやサービスの情報を共有し自動的に管理できる状態にするサービスディスカバリの仕組みと、動的に設定変更を伝播させるオーケストレーションの仕組みが備わっています。

Consul クラスタ内では何が動いているのか?


Consul エージェントがデーモンとして動作しています。エージェントにはクライアントモードとサーバモード( + KVS )があります。

エージェント


Consul クラスタの各サーバで実行されるデーモンで、 Consul の本体です。 Consul クラスタでは、その中のサーバすべてに Consul をインストールする必要があります。全てのエージェントは、DNS または HTTP の API があり、外からサーバの状態を取得できるようになっています。

サーバとクライアント


Consul エージェントはサーバとクライアントのどちらかの状態で動作します。Consul クラスタはサーバとクライアントによって形成されます。
クライアントは、主に自分自身のサーバのサービスのヘルスチェックを行います。 Web サーバや DB の状態をチェックしてサーバと共有します。クライアント自体は情報を保持せずステートレスな状態で動きます。
サーバは、クライアントとは異なり、KVS で各サービスの状態を保持しています。各サーバのエージェントはサービスのヘルスチェックを行い、状態を Consul サーバの KVS を通じて共有しています。 Consul サーバは1台でも動作しますが、 KVS にてデータを保持するため 3~5台での冗長構成での運用が推奨されています。

既存のプロダクトとの違い


Serf と Consul の違い


Serf は Consul と同じ HashiCorp 社によるプロダクトです。Serf にもヘルスチェック機構がありますが、エージェントが生きているかどうかだけを確認できる機能のみであるため、サービス( Web サーバや DB )の状態を確認することができません。一方 Consul は、各サービス生存確認を任意の方法で行うことができます。
ただ Consul は内部的に Serf を利用していますので Consul は Serf で足りなかった機能を拡張しているとも捉えることが出来ます。

既存の監視システムとの違い


Nagios , Zabbix など中央集権型の監視システムの仕組みに比べて、 Consul は Sense と同様各サーバのエージェントが自分自身のサービスの状態を監視するタイプのものです。そのため、大規模環境において中央の管理サーバに負荷が集中する問題を解消しています。また Sense は RabbitMQ サーバが単一障害点になるため独自に冗長化を行う工夫が必要でしたが、Consul は Gosship プロトコルや Consensus プロトコルを利用し耐障害性を考慮した仕組みを持っているため、通常の設定で冗長化を実現できる点が優れています。
また Nagios など既存の監視サーバから値を参照して Consul と連携して監視することも可能となっています。

検証環境の準備


検証環境にサーバ1台、クライアント1台を立ち上げてみます。

インストール


go で書かれており、バイナリのインストールにより Linux 環境であれば特に下準備無く動作します。インストールは3コマンドで可能です。私の環境は古めの開発機で CentOS の 5.4 というかなり古い環境ですが問題なく動作しています。

$ cd /usr/local/src
$ wget https://dl.bintray.com/mitchellh/consul/0.5.0_linux_amd64.zip -O consul_0.5.0_linux_amd64.zip
$ unzip consul_0.5.0_linux_amd64.zip
$ mv consul /usr/local/sbin


ログの出し方


初めて使うと何が動いているのかさっぱりわからないので、必ずログを出す設定をしましょう。起動時に syslog に出すオプションが利用できます。(config ファイルにて “enable_syslog”:true,“log_level”:”debug”,“syslog_facility”:”local0″ ) また、標準出力にも出てきますので、 リダイレクションで書き出しておきましょう。

#ファイル編集
$ vi /etc/syslog.conf
#末尾に記述
local0.* /var/log/consul.log
$ service syslog restart


Config ファイルの利用による起動


Consul の起動オプションは起動時に指定することもできますが、ファイルで書くことも出来ます。設定ファイルは .json で記述できます。 設定ディレクトリを指定すると自動的にディレクトリ内のjsonをすべて読み込んでくれます。

$ mkdir /etc/consul.d/
$ vi /etc/consul.d/consul-config.json
{
“datacenter”: “jiken-dc”,
“data_dir”: “/etc/consul.d/data”,
“node_name”: “consul-server”,
“server”: true,
“client_addr”:”127.0.0.1″,
“enable_syslog”:true,
“log_level”:”debug”,
“syslog_facility”:”local0″,
“bind_addr”:”192.168.0.1″
}
$ nohup ./consul agent -bootstrap -config-dir=/etc/consul.d >> /etc/consul.d/consul.log &


datacenter : データセンター名です。
data_dir : 全てのエージェントに必要なデータを保存するディレクトリです。サーバモードの場合はこのディレクトリでデータを永続化して保存します。
node_name : 任意のノード名称です。クラスタ内でユニークである必要があります。
server : サーバモードで動作するかどうかを示します。
bind_addr : Consul クラスタ内ののアドレス。他のノードからアクセスされます。
enable_syslog : ログの出力の ON OFF です。
log_level : ログのレベルです。
syslog_facility : ログの出力先です。

これでサーバモードで1つのエージェントが立ち上がりました。はじめの1台目の場合のみ bootstrap を指定します。その後2代目以降に立ち上げるエージェントは join オプションでサーバモードのエージェントを指定して起動します。

# 2台目のサーバにて起動
$ nohup consul agent -config-dir=/etc/consul.d -join=192.168.0.1 >> /etc/consul.d/consul.log &


オーケストレーション用途の検討


Consul にはノード間の状態を把握するサービスディスカバリ+ヘルスチェックの機構とオーケストレーションの機構がありますが、ここではオーケストレーションについて考察していきます。 Consul には、例えば consul exec を利用するとクラスタ内の全ノードに同一のコマンドを発行できますし、 consul watch では特定の KVS の値や consul event の監視し任意の処理を発火することができます。

Apache の設定ファイルを編集したというときに、複数のサーバに配布する手段としてどのようなものがあるでしょうか?既存でもツールが数多くあるため、その役割の境界を決めることが非常に難しい状況にありますが、そのなかでもConsulの出番を探ってみようと思います。

[運用開始前] 新規サーバの構築


まっさらの状態では Consul はまだ出番がありません。この場合 Chef 、Ansible などのプロビジョニングツールが行うことが一般的であると思います。各種ソフトウェアのインストールと設定、そして Consul の初期設定もここで行うことができそうです。

[運用開始前] [運用中] アプリケーションのソースコード配置


Capistrano でリポジトリから最新状態を取得して各サーバへ配布する方法があります。ここは Consul によるデプロイも可能です。後に考察します。

[運用中] 構成の変更(異常検知後の対応、サーバ追加対応など)


ここは Consul の得意分野です。 Consul がクラスタの状態を検知し Ansible を実行して自動的に再構成することができます。

Consul によるデプロイ時の負荷軽減


上記の「アプリケーションのソースコード配置」では Capistrano を挙げましたが、 Consul を利用してデプロイイベントを発火し、各サーバ内で自身のアプリケーションの状態を最新のものに更新することもできます。

中央のサーバからデプロイする場合の問題点


Capistrano 、または一般的に行われる中央の管理サーバから各サーバへに rsync 等でファイルを配布するスタイルのデプロイは、以下のような問題点があります。

・デプロイする台数が10台以上になると、 rsync の順次実行のため時間がかかる。
・デプロイ中に中央の管理サーバがダウンしてしまうと、デプロイができない状態となる。

これは rsync を駆使したシェルスクリプトだけでなく Capistrano を利用した場合ても同様です。
この問題を軽減するためには、中央のサーバから各サーバへ配布する Push 型デプロイではなく、各サーバのほうからデプロイ対象物を取得しに行く Pull 型のデプロイを行う必要があります。この点については以下の事例が大変詳しいです。

「Consulと連携するpull型デプロイツール stretcher 」
http://tech.kayac.com/archive/10_stretcher.html

Consul によるデプロイを試してみる


stretcher のようなかっこいいツールではないのですが、簡易的に既存のファイル反映の仕組みを Consul を利用して修正してみます。以下の流れで処理が行われます。

■ 既存の方法
1. ファイルの更新
2. 中央のサーバにてデプロイ実行(各サービスのサーバにファイルを rsync )

■ Consul を利用する方法
1. ファイルの更新
2. 中央のサーバにて consul event deploy イベント発火
3. 各サーバからデプロイ実行(該当ファイルを rsync する)

watches を追加して event を監視する


consul-server にて httpd-vhost.conf を更新した際に、手動で event を発火して consul-cli 側でファイルを取得して反映します。ファイルの変更を検知する方法もありますが、実際の運用では反映を手動で叩くことが多いので、特に凝ったことはせずに単純に反映することにしています。

■consul-server(サーバ)

vi /etc/consul.d/consul-config.json
{
“datacenter”: “jiken-dc”,
“data_dir”: “/etc/consul.d/data”,
“node_name”: “consul-server”,
“server”: true,
“client_addr”:”127.0.0.1″,
“enable_syslog”:true,
“log_level”:”debug”,
“syslog_facility”:”local0″,
“bind_addr”:”192.168.0.1″
}
$ nohup ./consul agent -bootstrap -config-dir=/etc/consul.d >> /etc/consul.d/consul.log &


■consul-cli (クライアント)

$ vi /etc/consul.d/consul-config.json
{
“datacenter”: “jiken-dc”,
“data_dir”: “/etc/consul.d/data”,
“node_name”: “consul-cli”,
“server”: false,
“enable_syslog”:true,
“log_level”:”debug”,
“syslog_facility”:”local0″,
“watches”:[
{
“type”:”event”,
“name”:”deploy”,
“handler”:”/etc/consul.d/deploy.sh”
}
]
}
$ nohup consul agent -config-dir=/etc/consul.d -join=192.168.0.1 >> /etc/consul.d/consul.log &


今回はデプロイについては既存のスクリプトを利用しただの rsync です(全然カッコよくありません)。ただしサーバからクライアントに向けて行う流れとは逆で、クライアントからサーバに向けて取得を実行しているのがポイントです。

vi /etc/consul.d/deploy.sh
# consul-server -> consul-cli の処理を consul-cli 側で叩く
rsync -avz consul-server:/etc/deploy/httpd_conf/httpd-vhost.conf /etc/httpd/conf/extra/
# 再起動
/etc/init.d/httpd configtest && /etc/init.d/httpd graceful


consul-server にてイベント発火するときはコマンドを叩きます。

$ consul event -name deploy
Event ID: 0a0dac59-45c7-bc96-3e4b-98bce18d017e



各サーバからConsulのKVSにファイルを取りに行く方法


今回のように小さな更新を反映する場合、 rsync 以外では Consul の KVS を利用する方法が、個人的には有用であると考えていました。ただ現状の課題として KVS へのファイルアップロードに一手間必要な点と、 KVS の容量に 512 KB の制限があるため少しファイルが大きくなると問題になりそうな点があり、まだ発展の余地アリという印象があります。ただ他の仕組みに依存せずに構築できる点が非常に優れていますので今後の発展をウォッチしていきたいと思います。

この方法は以下のブログで詳しく扱われています。
「Consulクラスタ内でファイル共有する Fileconsul というツールをつくってみた」
http://fstn.hateblo.jp/entry/2014/09/22/231519

最後に


障害検知における再構成以外にも Consul が導入可能な新しいユースケースは今後増えていく可能性があります。現段階でまだ0.5.0ということもあり、今後バージョンアップに伴う新しい機能が発表されると思いますので、またその際に新たに検討していく予定です。




次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆さんのご応募をお待ちしています。