雑記

インフラのことだったりプログラムのことだったりどうでもいいこと書いたり。要は雑記。

CentOS6にtmux1.9をユーザ領域にインストール

Cent6のyumでtmuxをインストールすると1.6系がインストールされるんですが、一部機能が使えなかったりするんで現時点で最新版の1.9系を入れてみます。

問題が

そのままコンパイルするとmake時に以下のエラーがでます。

control.c: In function ‘control_callback’:
control.c:64: warning: implicit declaration of function ‘evbuffer_readln’
control.c:64: error: ‘EVBUFFER_EOL_LF’ undeclared (first use in this function)
control.c:64: error: (Each undeclared identifier is reported only once
control.c:64: error: for each function it appears in.)
make: *** [control.o] Error 1

これはlibeventのバージョンが低いためでるエラーですね。Centで提供されている1.4ではインストールできないのです。

どうするの?

libeventの最新版をインストールしてライブラリを利用する必要があります。 そのまま素直にroot権限でconfigureからのmake && make installしてもいいのですが、root権限がないユーザでは無理ですし、そもそもすでにyumで入っているlibeventと共存するのは避けたいところですね。

というわけで

一般ユーザでlibeventを入れて最新版のtmuxもインストールしちゃいます。

いざ作業

その前に今回は以下のディレクトリにlibeventとtmuxを入れます。

  • libevent
$HOME/local 以下
  • tmux
$HOME/local/tmux

ソースファイルは全て以下におきます。

$HOME/local/src

libeventのインストール

$ cd ~/local/src
$ wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
$ tar zxf libevent-2.0.21-stable.tar.gz
$ cd libevent-2.0.21-stable
$ ./configure --prefix=$HOME/local
$ make
$ make install

tmuxのインストール

※ncursesの依存関係がでるので、インストールされていない場合は事前に「ncurses-devel」をインストールしておいてください。

$ cd ~/local/src
$ wget http://cznic.dl.sourceforge.net/project/tmux/tmux/tmux-1.9/tmux-1.9a.tar.gz
$ cd tmux-1.9a
$ LDFLAGS=-L$HOME/local/lib CPPFLAGS=-I$HOME/local/include ./configure --prefix=$HOME/local/tmux 
$ make
$ make install
$ cd ~/local/bin
$ ln -s ../tmux/bin/tmux tmux  

パスを通す

  • .bash_profile (zshの場合は.zprofile)

以下を追記。

# ライブラリのパスを通す
export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH 

# PATHの設定
PATH=$HOME/local/bin:$PATH

これでtmuxの最新版が使えます。

よく他のブログとかで、tmuxインストール時にlibeventのライブラリのパスが通っていないためエラーとなり、その対処方法としてシンボリックリンクで/usr/libとかに通している方法を見かけます。 でもLDFLAGSとCPPFLAGSでちゃんとパスを指定してあげればインストールできるのです。 (個人的にはライブラリの共存を防ぐためにこっちの方が推奨だったりします。)

それにしても

tmuxいいですね。もっと使いこなしたいものです。

sensuとGrafanaを連携してグラフを自動生成してみる

sensuを使っていて何が不満だったかというと、グラフの生成なんですよね。

監視対象についてはsensu-clientsを設定して起動すれば終わりだったのに対し、グラフの生成だけは毎回ダッシュボードからぽちぽち設定する必要があったのです。これがちょーめんどくさかったのです。

どーにか方法がないかなーと考えていたら同僚の方がGrafanaのscripted dashboardsというのがあるよと教えてくれました。 これとsensu-apiを使ってグラフの生成を自動化してみます。

scripted dashboardsって?

以下を参照。

要はJSを使ってグラフの生成を動的に実現するものです。

どうやって自動生成してるの?

おおざっぱな流れは以下の図を参照(雑です)

f:id:og732:20141118234039j:plain

図の通り、sensuのAPIにアクセスしてclient一覧とその設定を取得し、json.rbというスクリプトで生成するグラフのtemplateを作成、scripted.jsでグラフ化しています。 図では時系列DBがGraphiteですが、InfluxDBでも調整すればいけます。

ちなみに、sensuからGraphiteにデータを送る時にschemaを付与するのですが、そのschemaの先頭がその「ip-xxx-xxx-xxx-xxx」(xxxはIPアドレス)になるようにしてください。EC2ではデフォルトでそうなってるはずです。

json.rbについて

上記で触れていますが、grafanaのtemplateを生成するためのスクリプトです。リクエストがあると以下の処理を実行します。

  1. sensu-apiにアクセスしてclients一覧を取得する
  2. clients一覧から監視対象一覧のリンクを生成する
  3. どのグラフを生成するかsensuに設定されているsubscriptionsから判断する
  4. json/template/以下にsubscriptionsで設定されているtemplateがあるようなら、そのtemplateにグラフ生成対象のschmeaを埋め込んでtemplateを生成する
  5. 2と4の結果をjson形式にして返却する

動作の注意点として、

  • cgiで動作させます。利用しているwebサーバによって設定してください。
<Directory /opt/grafana/json>
    AddHandler cgi-script .rb
    Options ExecCGI
</Directory>
  • sensu-apiへのURLを設定してください。スクリプト内で設定されています。デフォルトはlocalhostです。

  • rubyのパスが「/opt/sensu/embedded/ruby」となっています。sensuのrubyを利用するためです。sensuのインストール環境と別の環境で実行する場合は変更する必要があります。

細かいことは

ソースを見てくださいw何も難しいことはしてませんから、多分そっちの方がはやいです。

om732/grafana-scripted-dashboards · GitHub

2015/05/07 追記

Githubにあげてるやつがちょっと古いので、別のレポジトリに調整してあげなおしました。試してみたいという方はこちらの方がよろしいかと思います。

sensuのおれおれベストプラクティス

sensuを導入してみました。 で、その導入時に困ったのが、subscriptionsのグルーピング設計や設定ファイルの置き方なんですね。 ネットの情報を見ててもインストールしてみたーや他のサービスとの連携だったりがまとまっていて、実際にどのように設定しているのかは全然まとめられてなかったわけです。

なので自分なりに考えて試行錯誤しながらまとめたわけですが、せっかくなので公開してみたいと思います。

ただし、これが正解とは思ってなくて、環境毎に最適解があると思うので、あくまで参考程度としてくださいねw

環境

  • EC2上でsensu-server、sensu-clientともに構築
  • OSはsensu-serverがAMI、sensu-clientoはAMI、CentOSUbuntuが混在
  • sensuのバージョンは0.14

ディレクトリ/ファイル構成

/etc/sensu/
├── conf.d
│   ├── checks ※checksの設定ファイルの設置ディレクトリ
│   │   ├── mysql ※subscriptions毎にディレクトリを切っている
│   │   │   ├── check_status_mysql.json ※「check_」で始まるファイルは監視用設定ファイル
│   │   │   └── metrics_mysql.json ※「metrics_」で始まるファイルはメトリック収集用の設定ファイル
│   │   ├── nginx
│   │   │   └── check_proc_nginx.json
│   │   └── resource
│   │       ├── check_disk.json
│   │       ├── check_load.json
│   │       ├── check_swap.json
│   │       ├── check_users.json
│   │       ├── metrics_cpu.json
│   │       ├── metrics_disk_usage.json
│   │       ├── metrics_load.json
│   │       ├── metrics_memory.json
│   │       └── metrics_network.json
│   ├── extensions ※extensionsの設定ファイルの設置ディレクトリ
│   ├── handlers ※handlersの設定ファイルの設置ディレクトリ
│   │   ├── default.json
│   │   ├── graphite.json
│   │   └── mailer.json
│   └── mutators ※mutatorsの設定ファイルの設置ディレクトリ
│       └── graphite.json
├── config.json
├── extensions ※extensionsで利用するスクリプトの設置ディレクトリ
├── handlers ※handlersで利用するスクリプトの設置ディレクトリ
│   └── mailer.rb
├── mutators ※mutatorsで利用するスクリプトの設置ディレクトリ
│   └── graphite.rb
├── plugins ※checksで利用するスクリプトの設置ディレクトリ
│   ├── check-disk.rb
│   ├── check-load.rb
│   ├── check-procs.rb
│   ├── check-swap-percentage.sh
│   ├── check-users.sh
│   ├── cpu-pcnt-usage-metrics.rb
│   ├── disk-usage-metrics.rb
│   ├── load-metrics.rb
│   ├── memory-metrics.rb
│   ├── mysql-alive.rb
│   ├── mysql-graphite.rb
│   └── netif-metrics.rb
└── ssl ※rabbitmqとの通信用SSLファイル
    ├── cert.pem
    └── key.pem

subscriptionsの構成

サービス毎にグルーピングするようにしています。 例えば、nginxに関することは全てnginxに含めます。監視もメトリクスもです。

設定ファイルはsubscription名ごとにchecks以下にディレクトリを作成してまとめます。

  • 例) nginxの場合
/etc/sensu/conf.d/checks/nginx/ 以下

ちなみにディレクトリを分けた目的は、視認性をよくするためです。 最初は分けずに全てのchecks以下にまとまて置いていましたが、設定ファイルが多くなると、設定ファイル編集時に対象のファイルを探すのが手間になってきまして。名前も似たようなのがあってわかりづらいですし。

plugins

こちらは全て「/etc/sensu/plugins/」以下に置いています。こちらもchecks以下と同様にディレクトリを分けることも考えたのですが、

  • 複数のsubscriptionsで使うpluginも存在する(例えばポートチェック)
  • checks設定時に実行するプライングのパスをcommandで指定するのですが、pluginsをパスの起点としているので、ディレクトリを掘るとそのディレクトリも設定に書く必要があるため
  • そもそもディレクトリを分けるメリットがあまりない(checksをファイルを編集する可能性がありますが、plugins以下に置くファイルは頻繁に編集することは考えづらいため)

といった理由から一括でまとめて置いています。

clientsを追加するとき

clientsを追加するときは、以下の作業をします。

  1. sensuをインストールする
  2. /etc/sensu/plugins/ 以下にプラグインを設置する(自分の場合はsensu-serverに置いてあるpluginsを全てclientsにそのまま同期するようにしています。本来であればそのclientで利用する監視のプラグインが置いてあればよいですが、わざわざ選別するのも手間ですし、全て置くことのデメリットも見当たらなかったためです。)
  3. config.jsonを設置する(詳細は後述)
  4. sensuを起動する

上記を実施すればよいだけです。ただ、いくら手順がそれほどないとはいえ毎回クライアント追加時に手動で実行するのは手間なので、自分の場合はAnsibleで自動化しています。 (余談ですが、sensuの素敵なところは、AnsibleやChefといった自動構成ツールとの相性がよいことだと思います)

config.jsonの設定項目

config.jsonについては環境毎にどのような監視をするか異なる場合があるため、使い回すことができないかと思います(スケールアウトするときはそのまま使いませますが)

とはいえそれほど設定項目はありません。以下のconfig.jsonの以下の値を調整すればOKです。

  • name
    • サーバの名前を設定します
  • address
  • subscriptions
    • サーバの監視項目を設定します

閾値の設定について

閾値は環境によって変更する可能性があることを考慮して、全てconfig.jsonによって環境別の設定をできるようにしています。 例えば、config.jsonには以下の設定をしています。

    "resource": {
      "load_warn": "5,3,3",
      "load_crit": "10,6,6",
      "disk_warn": 70,
      "disk_crit": 80,
      "swap_warn": 90,
      "swap_crit": 70,
      "users_warn": 20,
      "users_crit": 50
    }

上記はresource subscriptionで設定している監視の閾値設定となります。例として、「load_warn」はロードアベレージのワーニングの閾値設定、「disk_crit」はディスク使用率のクリティカル閾値設定を意味します。

環境によって異なる設定について

閾値と同様に環境によって異なる設定も各クライアントのconfig.jsonで設定するようにしています。MySQLの接続情報などはそうですね。

    "mysql": {
      "host": "localhost",
      "user": "example",
      "password": "example",
      "port": "3306",
      "database": "exampledb"
    },

さいごに

言葉だけだとうまくまとめられている自信がないので、Githubにサンプルをおいておきます。設定ファイルの中身は実際に見てもらえればと。

なお、格納されているプラグインsensu-community-pluginsから一部拝借しているものです。

近いうちにAnsibleのplaybookもあげようかと思ってます。

sensuのkeepalive間隔

sensuは30秒毎にクライアント毎にkeepaliveする。 この30秒はハードコーディングされているため、設定できない(おそらく)

  • /opt/sensu/embedded/lib/ruby/gems/2.0.0/gems/sensu-0.14.0/lib/sensu
@timers[:master] << EM::PeriodicTimer.new(30) do

他のchecksと同様にintervalで変更できるのかなーと思ったらできないっぽい。 このぐらい設定できてもいいと思うのだが。

ちなみにバージョンは0.14です。

vagrantでマウントしているディレクトリの注意点

vagrant使うとローカル環境のディレクトリがマウントされているじゃないですか。 その領域をドキュメントルートとした場合、ファイルを更新してブラウザでリロードしても反映されなかったので、その対策めも。

原因

簡単に言うとキャッシュ。webサーバでなく、kernelでキャッシュしてレスポンスを返すようにするみたい。

対策

自分の環境はnginxだったので、「sendfile」ディレクティブをoffにすれば大丈夫だった。

sendfile off;

apacheの場合も似たような設定項目があるので、設定すればよいです。 (EnableSendfileってやつなのかな?)

そういえば

nfs上にドキュメントルートを設定する場合も似たような設定をしていたなーと今更ながらに思い出したのでした