Glide Note

glidenote's blog

IRC BOTを作って仕事をさせるようにした

普段仕事中はIRCがコミュニケーションの中心で、私はWeeChatという CUIのIRCクライアントを使っていて、一日の7〜8割はターミナル上で過ごしてて、 全社員がIRC使ってるし、GitHubへのcommitログや、deployのログ、 NagiosのアラートもバンバンIRCに流れてくるのでIRCを見てる時間も結構ある。

サーバのラック番号とかmuninのグラフserver-status、Nagiosなどを確認するのに ターミナルから離れて、マウス使ってブラウザを操作して 探してたりすると集中が切れるので、IRC BOTを作って、URLを教えてくれるようにした。 URLをクリックすればブラウザが勝手に開いてくれる。

管理サーバが数百台でも、ブラウザのブックマークからmuninの一覧を出して、 該当サーバのURLを探すのも結構だるいし、そもそもキーボードから手を離すのは 最小限に抑えたい。

IRC BOTの作成にはcinchを利用して、 munin hogeとかstatus hogeみたいなのを発言するとbotが下記のように 必要な情報を教えてくれる。 業務バリバリの内容のためほとんど伏せてるので、何が表示されているか分かりにくいですが…

上の例が業務バリバリなので、コードが晒せないんですが、特定キーワードに反応するbotは cinchを利用すると簡単に作成出来て、たとえば下記のような感じで、瞬時に追い込みをかけてくれるbotはすぐに投入出来る。

ブラック企業ことわざを教えてくれるbotを 投入して業務を円滑に回したり、

その他、GitHubの応答が悪かったりした場合は、下記のような感じのbotを常駐させておいて、

status githubとか発言すると、GitHubのapiを叩いて状態を確認してくれる。

作ったIRC BOTはsupervisord経由で上げれば、簡単に常駐出来るし、 IRC BOTを通じてサーバに作業指示が出来るので、deploy hogebuild mogeとかで IRCからデプロイしたりやビルドを走らせたり、いろいろな使い方が想定出来ると思う。

IRC BOTが仕事をしてくれると、ターミナルから離れなくて済むので 自分の業務に集中出来ていろいろと捗る。

httpingとmuninでWebサーバのレスポンスをグラフ化した

Webサーバのレスポンスの計測をしたくて、Webサーバにはfluentdを導入済みなので、 Fluentd+GrowthForecastでやろうと思ったんですが、 Webサーバは全台muninでモニタリングしてて、muninとGrowthForecastでページが 分かれてしまうと視認性が下がるので、muninでグラフ化することにした。

munin自体はエンジニア以外の人も閲覧して、サーバの状態を判断しているので、 確認するページが複数にまたがるのもちょっと嫌だった。

計測にはzembutsuさんのpluginを利用することに。 導入に際してwarningとcriticalの値を設定出来るようにpull reqを出してmergeもしてもらった。

導入したサーバはCentOS4,CentOS5,CentOS6とSL6。

導入方法

httpingの導入

httpinのrpmは下記にあるので、それを利用

munin-plugin-httping_の導入

導入は下記のような感じ

1
2
3
4
cd /usr/share/munin/plugins/
sudo get --no-check-certificate https://raw.github.com/zembutsu/munin-plugin-httping_/master/httping_
chmod +x httping_
sudo ln -s /usr/share/munin/plugins/httping_ /etc/munin/plugins/httping_localhost

/etc/munin/plugin-conf.d/munin-node/etc/munin/plugin-conf.d/httpingなどに 設定ファイルを用意して下記のように設定。返ってくる値はmsecなので1000で1sec。

1
2
3
4
5
6
7
[httping_localhost]
    env.URL http://localhost/
    env.COUNT   5
    env.connect_warning 400
    env.connect_critical 700
    env.processing_warning 400
    env.processing_critical 1000

pluginが正常に動作するか確認

1
sudo munin-run httping_localhost

下記のような値が返ってくる

1
2
connect.value 0.478
processing.value 0.332

問題が無ければ、munin-nodeを再起動

1
sudo service munin-node restart

しばらくすると下記のようなグラフが出来上がる。

設定した閾値を超えるとちゃんとグラフの色が変わってくれるようになった。

localhostだけじゃなくて、宛先をapiサーバとかをしておけば、 Webサーバとapiサーバ間のレスポンス速度も計測出来て便利なはず。

TotalTerminalとiTerm2のカラースキーマをSolarizedにした

TotalTerminalというかTerminal.app上でコピペをすると改行が無くなる問題が結構発生して いろいろ調べて見たんですが、原因の特定も解決方法も分からなかったので、iTerm2に切り替え中。

TotalTerminalの設定を結構いじってて、iterm2のカラー設定をTotalTerminalと同じにカスタムするのが結構面倒だったので、 この際両方のカラースキーマをSolarizedに変更した。 というかターミナルにカラースキーマという概念があることを初めて知ったし、Solarizedはエディタ専用の配色だと勝手に思ってた…

導入方法は下記サイトのそのままなので割愛

Vim上だとSolarizedはあんまり好きなカラースキーマでなくて、molokaiを 常用してたんですが、ターミナルだと目が疲れなくてかなり良い。

ターミナルと合わせてvimでも、vim-colors-solarized.vimrcに下記をしたら結構良い感じに思えてきた。

vim画面ですが、左がsolarizedで、右がmolokai。

ターミナルの色が変わると新鮮な感じがして良い感じ。

調べて見るとdircolors用やtmux用のsolarizedがあってそれぞれ設定が出来る模様。

dircolorsに関してはすでにsolarized化されてて、昔自分で設定してたらしい

参考

FluentdからMongoDBにデータを文字列(string)から数値(integer)に変換して入れる

最近ようやく仕事でガッツリFluentdとMongoDBを触るようになってちょっとハマったことが あったので誰かの役に立つかも知れないので書いておく。

Fluentd界隈は開発が活発なので、数ヶ月後にはこの記事の情報も恐らく古くなっているのでご注意ください。

結論

書いてたら長くなってしまったので先に要点というか結論を書いておく。

  • apache => fluentd => MongoDB とapacheのアクセスログをMongoDBに入れたときにcodesizeといった数値が文字列(string)として入っていた
  • td-agent.confformatを自作すると、時間以外のフィールドが文字列(string)として扱われる
  • fluent-plugin-typecastを利用することでcodesizeといった特定のフィールドを、stringintegerなどの任意のデータ型に変換可能。今回の場合はsizecodeをintegerとして扱うように変換して解決した
  • MongoDBのAggregation Frameworkは大変便利

前段

MongoDBは2.2からAggregation Frameworkというのが 使えるようになっていて、これまでMapReduceなどを用いないと実行出来なかったデータの集計作業などが コマンド一発で出来るようになっているとのこと。 Fluentdを利用してMongoDBに貯めていたapacheのログからvhost毎のトラフィック集計作業を行おうとしてた。

MongoDBに入っているapacheのログデータは下記のような形

1
2
3
4
5
6
7
8
9
10
11
{
  "_id" : ObjectId("515e912431166b166b000002"),
  "host" : "hogemoge.glidenote.com",
  "user" : "192.168.25.84",
  "method" : "GET",
  "path" : "/htdocs_error_Zq9kbQHobRDu8hdp4K06lMGUOLwFoY0dQUSsIqgXLVBYB3gwAIBy9NNcd9coPHRV/css/error.css",
  "code" : "200",
  "size" : "423",
  "referer" : "http://hogemoge.glidenote.com/",
  "agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31", "time" : ISODate("2013-04-05T08:53:50Z")
}

hogemoge.glidenote.comの転送量の集計をするために下記コマンドでsizeで集計をかける。

1
2
3
4
5
db.accesslog.aggregate(
  {$match   :{"vhost":"hogemoge.glidenote.com" } },
  {$project :{"vhost":1, "size":1} },
  {$group   :{"_id":"$vhost", "traffic":{"$sum":"$size"} } }
);

…、集計出来ないッ!

aggregation frameworkで集計出来ない原因

なぜ集計出来ないのか調査すると、sizeが文字列として扱われていた。ちなみに各フィールドのデータ型は下記のような形で調べられる。(ダブルクオートで囲まれているので、その時点でintegerではないんですが調査中は全く気づかなかった…)

1
2
3
4
5
// type 2で抽出されるものはstring
db.accesslog.find( { size : { $type : 2 } } )

// type 16で抽出されるものは32-bit integer
db.accesslog.find( { size : { $type : 16 } } )

数値が文字列として扱われている問題の原因

同じような現象を調べて下記有益情報を発見。

問題が発生した時の構成

問題が発生していたときの構成。(WEBサーバ約200台で、LOGサーバは1台の構成)

結論を言うと今回の現象はLOGサーバ側で利用していたfluent-plugin-parserfixed_parser.rb部分で発生していた。fluentdのparser.rbを利用しても同様に発生する問題(2013年4月8日現在)

なぜ数値が文字列(string)として扱われるのか

解決方法を探るためにソースを見てみると、format apache2の場合はApacheParserが利用されてsizecodeto_iの処理が入っており数値に変換されているが、formatを自分で書くとRegexpParserが利用されてtime以外は文字列として扱われている。今回はformat apache2がそのまま利用出来ないログの形式でformatを自分で書いていたのも一因としてある。

https://github.com/tagomoris/fluent-plugin-parser/blob/master/lib/fluent/plugin/fixed_parser.rb#L178-L187

問題の解決方法

問題の原因がわかり、解決方法をいろいろ試していたら、弊社の@banyan先生からfluent-plugin-typecastというのがあると有益情報をゲット。

早速下記のような形で導入

1
/usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-typecast

td-agent.conffluent-plugin-typecastの部分は下記のような形

1
2
3
4
5
<match get.apache.access>
  type typecast
  item_types size:integer,code:integer
  tag filtered.apache.access
</match>

apacheのログを流してみると、ちゃんとsizecodeが数値(integer)としてMongoDBに入るようになった。

Aggregation Frameworkで再度集計してみる

当初の目的であるMongoDBのAggregation Frameworkを再度試してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
db.accesslog.aggregate(
  {$match   :{"vhost":"hogemoge.glidenote.com" } },
  {$project :{"vhost":1, "size":1} },
  {$group   :{"_id":"$vhost", "traffic":{"$sum":"$size"} } }
);


{
    "result" : [
        {
            "_id" : "hogemoge.glidenote.com",
            "traffic" : 289736716
        }
    ],
    "ok" : 1
}

一瞬で集計が完了。素晴らしい!!($matchを書けるvhost、timeとかにindex貼ってないと多分死にます)

改善後の構成

この構成で1秒に約4000ドキュメント、1日で約3億5千ドキュメントをMongoDBに突っ込んで 数日様子を見てますが、特に大きな問題も無く稼働中です。

当初どこが問題の原因か全く検討も付かなくて調査に半日近く時間を要した。 仕事でガッツリ触らないと覚えないし、勘も働かないなーと改めて感じた。

PuppetのSyntaxをvim(syntastic)とgit hooks(pre-commit)の2重でチェックするようにした

puppetのmanifestを書いていて、我ながらtypo、構文ミスとかヘボいミスが多すぎるので、 vimとgit hooks(pre-commit)とで2重でsyntax checkをするようにした。

具体的なsyntax checkの方法

  • vimからはsyntasticを利用してsyntax check
  • git hooks(pre-commit)からpuppet parser validateを利用して、commitのタイミングでsyntax check。問題がある場合はcommitが出来ないようにする

puppetとpuppet-lintの導入

manifestを書いているマシンにpuppetが入っていないとSyntax Checkが出来ないので導入。 またsyntasticがpuppet-lintを利用するので併せて導入。

私は、最近はmac上でmanifestを書いているのでgemで導入

1
2
gem install puppet
gem install puppet-lint

RHEL系でyumの場合は下記のような感じ。

1
sudo yum -y install puppet rubygem-puppet-lint

syntasticの導入

私はneobundleを利用しているので、下記を.vimrcに書いて:NeoBundleInstall

1
NeoBundle 'scrooloose/syntastic'

puppetのmanifestを編集して、保存したタイミングでsyntaxのcheckが走る。 エラー部分は:Errorsで表示。

構文がおかしい場合は、下記のように表示される。

これでvimからsyntax checkが出来る。

git pre-commitを用意

Vimだけでも良いんですが、puppetのファイルは全てgitで管理しているので、 git hooksでもcheckが走るようにする。

.git/hooks/pre-commitに下記のようなファイルを用意

puppetのversionが2.7以下の場合は、puppet parser validateというコマンドが無いので、下記コマンドを利用するように変更してください。

1
git cat-file blob :0:$indexfile | puppet --color=false --parseonly --ignoreimport > $error_msg ;;

するとcommitしようとしたタイミングにsyntax checkが走るので、エラーがある場合は下記のようにcommit出来ない。

これでヘボいミスも減って、commit履歴を汚さずに済むはず。

参考