ども。cloudpack の かっぱ (@inokara) です。
前回の続き
前回、無理やり CSV をパースすることなく haproxy-ruby と Sinatra と組み合わせて 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.socket
は root: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-ruby は HAProxy の 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)」