ども。cloudpackかっぱ (@inokara) です。

前回の続き

前回、無理やり CSV をパースすることなく haproxy-rubySinatra と組み合わせて HTTP 経由で JSON 返すようにすれば CSV パースの呪縛から一瞬で解き放たれたので Sinatra よりもさらに軽い(リソース的にも軽そうに感じる)感じで Web サーバーを上げることが出来ればよりイイのかなって思って Rack 使ってラッパーっぽいのを作ってみました。

HAProxy 側では

stats 有効

以下のように stats を有効にしておきましょう。

stats socket /var/run/haproxy.sock user root group wheel level admin
stats timeout 2m

上記のように設定すれば /var/run/haproxy.socketroot:wheel で作成され管理者レベルでの操作が可能になります。

念のため確認

$ sudo echo "show info" | sudo socat stdio /var/run/haproxy.sock
Name: HAProxy
Version: 1.5.9
Release_date: 2014/11/25
Nbproc: 1
Process_num: 1
Pid: 25459
Uptime: 0d 0h08m21s
Uptime_sec: 501
Memmax_MB: 0
Ulimit-n: 8226
Maxsock: 8226
Maxconn: 4096
Hard_maxconn: 4096
CurrConns: 2
CumConns: 19

(snip)

description:

俺の実装

haproxy-ruby をインストール

sudo gem install haproxy --no-ri --no-rdoc -V

haproxy-rubyHAProxy の stats を有効にした際の socket ファイル読み込んでパースしてハッシュで値を返す有難いツールです。詳しい使い方については README を見て頂くとして、現状はハッシュでのみ statistics な情報を返す状況です。

Rack アプリケーション

Rack は Rack でもサーバーラックではありません…
Rack アプリケーションは以下のようにシンプルに。

require 'haproxy'
require 'json'

haproxy = HAProxy.read_stats '/var/run/haproxy.sock'
$info =  haproxy.info
$stat =  haproxy.stats

class HaproxyInfo
  def call(env)
    [200, { 'Content-Type' => 'application/json' }, [ $info.to_json ]]
  end
end

class HaproxyStatistics
  def call(env)
    [200, { 'Content-Type' => 'application/json' }, [ $stat.to_json ]]
  end
end

更に config.ru を以下のように書いておきましょう。

require "./haproxy.rb"

use Rack::Reloader, 0
map '/info' do
  run HaproxyInfo.new
end

map '/stats' do
  run HaproxyStatistics.new
end

細かいコードの内容の説明については割愛させて頂きます(本人も見よう見まねな為)

rackup

準備が整ったら rackup でアプリケーションを起動しましょう。

sudo /usr/local/bin/rackup -p 8089 -o 0.0.0.0 &

実行すると以下のように出力されアプリケーションが起動します。

[2015-01-22 15:59:27] INFO  WEBrick 1.3.1
[2015-01-22 15:59:27] INFO  ruby 2.0.0 (2014-11-13) [x86_64-linux]
[2015-01-22 15:59:27] INFO  WEBrick::HTTPServer#start: pid=25530 port=8089

ヲヲ。

念のためポートが Listen しているかも確認しましょう。

$ netstat -an | grep 8089
tcp        0      0 0.0.0.0:8089                0.0.0.0:*                   LISTEN

確認

localhost にて確認

localhost にて確認。

$ curl -s localhost:8089/info | python -m json.tool
127.0.0.1 - - [22/Jan/2015:16:01:48 +0000] "GET /info HTTP/1.1" 200 - 0.0012
{
    "compressbpsin": "0",
    "compressbpsout": "0",
    "compressbpsratelim": "0",
    "connrate": "0",
    "connratelimit": "0",
    "cumconns": "39",
    "cumreq": "39",
    "cumsslconns": "0",
    "currconns": "2",
    "currsslconns": "0",
    "description:": null,
    "hard_maxconn": "4096",
    "idle_pct": "100",
    "maxconn": "4096",
    "maxconnrate": "1",
    "maxpipes": "0",
    "maxsessrate": "1",
    "maxsock": "8226",
    "maxsslconns": "0",
    "maxsslrate": "0",
    "memmax_mb": "0",
    "name": "HAProxy",
    "nbproc": "1",
    "node": "ip-xxx-xx-x-xxx",
    "pid": "25459",
    "pipesfree": "0",
    "pipesused": "0",
    "process_num": "1",
    "release_date": "2014/11/25",
    "run_queue": "1",
    "sessrate": "0",
    "sessratelimit": "0",
    "sslbackendkeyrate": "0",
    "sslbackendmaxkeyrate": "0",
    "sslcachelookups": "0",
    "sslcachemisses": "0",
    "sslfrontendkeyrate": "0",
    "sslfrontendmaxkeyrate": "0",
    "sslfrontendsessionreuse_pct": "0",
    "sslrate": "0",
    "sslratelimit": "0",
    "tasks": "11",
    "ulimit_n": "8226",
    "uptime": "0d 0h17m36s",
    "uptime_sec": "1056",
    "version": "1.5.9"
}

一応、JSON ですね。

せっかくなので HAProxy のバックエンドとして

以下のように HAProxy を設定しておきましょう。

listen statistics 127.0.0.1:19190
  mode http
  server rackapp 127.0.0.1:8089

再起動してアクセスしてみましょう。

$ curl -s localhost:19190/info | python -m json.tool
127.0.0.1 - - [22/Jan/2015:16:09:54 +0000] "GET /info HTTP/1.1" 200 - 0.0012
{
    "compressbpsin": "0",
    "compressbpsout": "0",
    "compressbpsratelim": "0",
    "connrate": "0",
    "connratelimit": "0",
    "cumconns": "39",
    "cumreq": "39",
    "cumsslconns": "0",
    "currconns": "2",
    "currsslconns": "0",
    "description:": null,
    "hard_maxconn": "4096",
    "idle_pct": "100",
    "maxconn": "4096",
    "maxconnrate": "1",
    "maxpipes": "0",
    "maxsessrate": "1",
    "maxsock": "8226",
    "maxsslconns": "0",
    "maxsslrate": "0",
    "memmax_mb": "0",
    "name": "HAProxy",
    "nbproc": "1",
    "node": "ip-xxx-xx-x-xxx",
    "pid": "25459",
    "pipesfree": "0",
    "pipesused": "0",
    "process_num": "1",
    "release_date": "2014/11/25",
    "run_queue": "1",
    "sessrate": "0",
    "sessratelimit": "0",
    "sslbackendkeyrate": "0",
    "sslbackendmaxkeyrate": "0",
    "sslcachelookups": "0",
    "sslcachemisses": "0",
    "sslfrontendkeyrate": "0",
    "sslfrontendmaxkeyrate": "0",
    "sslfrontendsessionreuse_pct": "0",
    "sslrate": "0",
    "sslratelimit": "0",
    "tasks": "11",
    "ulimit_n": "8226",
    "uptime": "0d 0h17m36s",
    "uptime_sec": "1056",
    "version": "1.5.9"
}

一応、レスポンスは返してくれます。一応と書いたのは以下のようなエラーも一緒に出力されてしまいます…。なんでやろ。

$ [2015-01-22 16:09:54] ERROR Errno::ECONNRESET: Connection reset by peer
        /usr/share/ruby/2.0/webrick/httpserver.rb:80:in `eof?'
        /usr/share/ruby/2.0/webrick/httpserver.rb:80:in `run'
        /usr/share/ruby/2.0/webrick/server.rb:295:in `block in start_thread'

調べよかな。

ということで…

やったこと

  • haproxy-ruby のいいとこ取りで HAProxy の statistics な情報を JSON で返してくれるアプリケーションっぽいのを作った
  • Rack に初めて触ってみた(Sinatra の方が自分のような初心者にはやさしいような気がする)

今後やれそうなこと(やりたいこと)

  • パス、又はクエリで出力を絞り込む

感じたこと

  • 何かやる前(作る前)に Github とか確認すると思わぬ宝が見つかるかも

作ったと言っても…

作ったと言ってもエラー処理も無く to_json しているだけと言ったらそこまでで大変お恥ずかしい限りですが、JSON で情報が扱えることで他のツールとの連携はしやすくなるのではと考えています。

ということで、おやすみなさい。

元記事はこちらです。
HAProxy の statistics な情報を HTTP 経由の JSON で返す薄っぺらいラッパーを作ってみた(1)