serfの設定をetcdで動的生成を試みた話

serfの設定をetcdで動的生成を試みた話 はてなブックマーク - serfの設定をetcdで動的生成を試みた話


以前、Etcd を使って Serf の設定ファイルを動的に生成できないかどうか、考えていた時期がありました。現在対象となったファイルはメンテしなくなったため、Gist 上に放流しています。

https://gist.github.com/zembutsu/c01c4a152c3ac4be8950

以下、自分のための、取り組みの切っ掛けであったり、考えを整理するためのメモ。

■ Etcd とは

Etcd は、GitHub 上の説明によりますと、”設定共有とサービス検出のための、高い可用性を持つキーバリュー・ストア” ( A highly-available key value store for shared configuration and service discovery ) とあります。最近であれば、CoreOS に始めから入ってる機能としての Etcd 、という方が認知されているのではないでしょうか。ちなみに Golang で書かれていますね、最近流行ってますね。

Etcd には様々な機能・役割があります(公式ページ参照)が、私が欲しかったのは、純粋に KVS としての機能です。いわゆる、Raft プロトコルにより、永続性を分散して担保することで、障害に強い仕組みが実装されています。

加えて重要なのは、HTTP インターフェースを通して、KVS の操作が可能な点、そして JSON 形式のデータを返すため、加工が比較的しやすい(わかりやすい)点です。

■ 動機:このスクリプトを使ってやりたかった事

目的は、Serf の設定ファイルを動的に生成したかったためと、「あるべき状態」を定義しておく場所が欲しかったためです。そこに Etcd の機能が役立ちそうでした。

検証当時は、Serf と監視ツールである ZABBIXと の連携を模索していました。Serf が ZABBIX を操作する時は、API を使って ZABBIX にリクエストします。この時、鍵となるのが ZABBIX がホスト情報を管理する「hostid」と呼ばれる一意の情報です(ホスト名や IP アドレスで管理されているわけではありません)。

hostid は当初、Serf タグ上でデータを記録させていました。しかし、この方法では問題がありました。対象ノードが消滅したりダウンすると、タグ情報を更新することができません。また、システム全体として、何らかの共通データを保管するには、Serf のタグ機能だけでは貧弱と思えました。

そこで考えた事が、

  • Serf のタグにあたる情報を、何らかのデータベースで管理したい

という事でした。

そして、検証を進めていた所、Etcd へのリクエスト結果は JSON を使って取得できる事がわかりました。Serf の設定ファイルは JSON 形式のものが読み込めます。そのため、環境が動的に変化(スケールアウトしたりスケールダウン)する場合でも、動的に設定ファイルを生成させたり、複数ノード上の設定ファイルやイベントハンドラが実行するスクリプトを、動的に変更させる事が出来そうだと気づきました。

現時点では、とりあえず Etcd からデータを取り出すところまでは出来ていますが、中身はシンプルそのものです。Etcd の HTTP インターフェースに対して ‘/serf/node名/’ に対するリクエストを行い、結果を Serf が理解できる形に整形する所までです。ノード群を統率・管理する仕組みは、別途作らなくてはいけません。

■ Etcd を使ってみた話

検証は、現在公開されている v.0.3.0 で行いました。環境は CentOS 6.5 です。将来的には、ここで記述した通りでは動かない可能性があります。

セットアップは、バイナリが配付されていますので、それを使用します。

$ curl -o etcd-v0.3.0-linux-amd64.tar.gz \
    -L https://github.com/coreos/etcd/releases/download/v0.3.0/etcd-v0.3.0-linux-amd64.tar.gz
$ tar xvfz etcd-v0.3.0-linux-amd64.tar.gz
# cp ./etcd-v0.3.0-linux-amd64/etcd /usr/bin/

バイナリファイルを展開し、適当なパスに etcd を奥だけで準備完了します。

Etcd を起動します。本来は、複数台の Etcd 環境でクラスタを組むのが正しいのですが、KVS の動作検証を行いたかったので、ここはあまり検証していません。単純に、1ホスト上で etcd を起動します。指定しているのはデータディレクトリと名前、いずれも任意のものです。

# etcd -peer-addr 127.0.0.1:7001 -addr 127.0.0.1:4001 \
    -data-dir /opt/etcd -name machine1

次に KVS の操作を行います。操作を行うには3つの方法あります。

  • 直接 JSON のリクエストを Port 4001 に対して行う
  • 専用のコマンドラインツール etcdctl を使う
  • ブラウザでダッシュボード http://127.0.0.1:4001/mod/dashboard/ にアクセスする

左図のようなダッシュボードを使えば、比較的簡単に作業ができますが、ここでは etcdctl を試します。

単純に登録するだけであれば、’set’ を使ったリクエストを行いますす。

# etcdctl set mykey "this is etcd"
this is etcd

値を取得するには ‘get’ です。

# etcdctl get mykey
this is etcd

ここで登録済みの情報は、HTTP 経由、すなわち curl 等を通して他のアプリケーションでも取得できるようになります。エンドポイントは ‘ /v1/keys/ ‘ 以下に、キー名が入ります。以下はキー名 ‘meykey’ に対する値を取得するものです。’value’ の所にデータが入ります。

$ curl -s -L http://127.0.0.1:4001/v2/keys/mykey | jq -a '.'
{
  "node": {
    "createdIndex": 65,
    "modifiedIndex": 65,
    "value": "this is etcd",
    "key": "/mykey"
  },
  "action": "get"
}

■ serf-etcdconf.pl

事前準備として「手動で」、KVS の /serf/manager 配下にデータを置きました(手動なのです、この部分はイケてませんね…)。’/serf/’ は、Serf 向けの設定を置く場所と定義し、’manager’ は対象ノードのロールを想定しています。

また、 階層構造の key=value が、serf の外部設定ファイル(JSON) の書式と一致するように配置します。また、扱えるデータは key=value 形式なので、event_hander や join といった array として扱うべきデータは、別途ネストしてデータを取得・変換する仕組みを行っています。

取得したデータは、JSON 形式で取得すると以下のように表示されます。

$ curl -s -L http://127.0.0.1:4001/v2/keys/serf/manager | jq -a '.'
{
  "node": {
    "createdIndex": 2,
    "modifiedIndex": 2,
    "nodes": [
      {
        "createdIndex": 4,
        "modifiedIndex": 4,
        "value": "192.168.39.3",
        "key": "/serf/manager/bind"
      },
      {
        "createdIndex": 12,
        "modifiedIndex": 12,
        "dir": true,
        "key": "/serf/manager/event_handlers"
      },
      {
        "createdIndex": 7,
        "modifiedIndex": 7,
        "dir": true,
        "key": "/serf/manager/keys"
      },
      {
        "createdIndex": 3,
        "modifiedIndex": 3,
        "value": "manager",
        "key": "/serf/manager/node_name"
      }
    ],
    "dir": true,
    "key": "/serf/manager"
  },
  "action": "get"
}

この中のデータで欲しいのは、「key」と「value」の組み合わせです。不要なデータの削除や整形を serf-etcdconf.pl が行います。処理を実行すると、以下の様に出力されます。

$ perl serf-etcdconf.pl | jq '.'
{
  "bind": "192.168.39.3",
  "event_handlers": [
    "test2",
    "test2",
    "test3",
    "aaa"
  ],
  "node_name": "manager",
  "keys": {
    "role": "develop",
    "network": "local",
    "test": "develop"
  }
}

このように serf の設定ファイルを取得する事が出来ました。設定ファイルを作成する方法としては、scp や rsync を使う事も考えられます。しかし、この Etcd を使う方法であれば、ノード自身が任意のタイミングで設定ファイルを能動的に取得できます。また、scp であれば SSH に関連するアカウントの設定やセキュリティについて考慮する必要があります。しかし Etcd 経由であれば、HTTP を使って取得出来ますので、比較的に手軽な運用ができるのではないでしょうか。

このように、一旦 Etcd に特化した形で作ってしまいましたが、Consul  にも対応する形で、書き直そうと思っています。あとは、Serf 設定の自動生成や、イベントハンドラの動的変更については、継続した課題として取り組みたいです。例えば、複数台にまたがる Serf の設定を、一斉に変更したい場合や、イベントハンドラのスクリプト展開/変更が出来るのではと考えています。さらに、Serf だけでなく、JSON を扱えるものであれば、色々管理が楽になるのでは・・と個人的に期待しています。

■ 参考文献

CoreOS etcd のクラスタとその応用性 – jedipunkz’ blog
http://jedipunkz.github.io/blog/2013/12/09/coreos-etcd-cluster/

Big Sky :: 分散環境情報サーバ etcd を使った設定共有の活用
http://mattn.kaoriya.net/software/etcd/20130821143439.htm

■ 補足資料(参考訳)

Etcd のリリース情報概要 v0.1.0 ~ v0.3.0
https://github.com/coreos/etcd/releases/

v0.1.0 2013年8月11日 etcd の初リリース

  • 主な機能
    Simple (シンプル) : crul を使って API を操作できる(HTTP+JSON)
    Secure (安全) : SSL クライアントを使った認証が可能
    Fast (高速) : インスタンス毎に 100 write/秒を実現
    Reliable (信頼性) : Raft を用いた分散処理
    Persistent (一貫性) : クラスタ障害時でも復旧できる
  • etcd プロジェクトは、それぞれ独立したプロジェクトからスタートした
    calavera … Go で書かれた動的なリバース・プロキシ
    – ruby で書かれた iconarajpfuentes2ranjib

v0.1.1 2013年8月 細かなバグ修正
v0.1.2 2013年10月10日 ダッシュボードの追加(遅延Chartと、Keyspaceブラウザ)と、バグ修正
v0.2.0-rc0 2013年10月 v2 API のプレビュー
v0.2.0-rc1 2013年11月 CAS による分散ロック、設定の多様化、ディレクトリの再帰的リクエスト等
v0.2.0-rc2 2013年12月 v2 レスポンスフォーマット採用により、クライアントの利便性向上
v0.2.0-rc3 2013年12月 バグ修正と機能追加

  • etcd
    – 新しいリーダ選出モジュール
    ロック用モジュール
    – heartbeat やリーダ選出のタイムアウトフラグ
    – dir パラメータの追加
    – ダッシュボードのバグ修正
  • etcdcctl
    – ‘–debug’ オプションで詳細表示
    – ‘ls –recursive’ で再帰的に表示
    – ‘–peers’ のサポート

v0.2.0-rc4 2013年12月 バグ修正
v0.2.0 2013年12月27日 新しい API やモジュールの採用、大幅な改良

  • 主な変更点
    – v2 API の提供開始、新しいエンドポイントは ‘/v2’
    – etcd が目指す一貫性と適切な分散システムを、開発者が簡単に利用出来るよう、シンプルな HTTP の提供、ロック機構、リーダー選出
  • etcdctl 改良
    – etcdctl の改良では、’exec-watch'(変更タイミングでコマンド実行) ‘etcdctl ls’ や、’-o extended’ による拡張表示
  • サービス検出

v0.3.0 2014年2月7日 クラスタ検出や、新しい API の提供、Windows サポート

  • 新機能
    Discovery API : peer 検出用の API によって、都度 ‘-peers’ を指定しなくて良い
  • その他の API 追加
    – v0.3 でも v2 API は使用可能だが、’CompareAndDelete’ と ‘prevNode’ を追加
  • ログ記録の改善
  • Windows のサポート
  • 機能変更
    – info ファイルは使用しないので撤去
    – スナップショットをデフォルトに変更
    – その他、ダッシュボードの改良等

今後のロードマップは、年内に v.1.0 を目指す模様。

etcd – The Road to 1.0
https://coreos.com/blog/etcd-The-Road-to-1.0/