Ubuntu Weekly Recipe

第359回Muninでサーバーのリソースを可視化しよう

リソース監視の必要性

VPSやクラウドの流行で、安価にサーバーを持てる時代になりました。ところで皆さん、手持ちのサーバーの状態はきちんとモニタリングしていますか? もしもサーバーに障害が発生したら、ただちにサービスを復旧させなければなりません。そのためZabbixやNagios等を使い、Pingに応答するか? 80番ポートにコネクションを張れるか? と言うように、サーバーが生きているかどうかを常に監視していることでしょう。また、外部から特定のURLへの疎通を監視し、応答しなくなった際にアラートメールを送ってくれるようなサービスもあります。

しかし、それだけでは起こり得る障害を未然に防ぐことはできません。たとえばデータが溜まってきてHDDがあふれそうだったり、Webサービスへのアクセスが増えたことによってメモリが不足ぎみになっていたり、DBのスロークエリーが出ていたりといったサーバーのリソースの変化を監視し、障害が起きる前に策を講じることも大切です。また実際に障害が起きてしまった際にも、⁠その時何が起きていたのか」を後から分析できるのは非常に重要です。

Muninは、そんなリソースのモニタリングに特化した監視システムです。今週のRecipeでは、Ubuntu 14.04とMuninを使って監視サーバーを作ってみましょう。

Muninノードのセットアップ

Muninは、監視対象のサーバーにインストールするmunin-nodeと、各ノードから情報を集め、Webページとして表示するmuninサーバーで構成されています。munin-nodeはTCPのポート4949でサーバーからの接続を待ち受け、サーバーはこのポートに接続してノードの情報を取得します。それではmuninサーバーと監視対象のサーバーを作るため、サーバーを2台用意しましょう。なおこの例ではさくらのクラウドを利用しています[1]⁠。

まずは監視対象となるmunin-nodeサーバーです。Ubuntu 14.04が起動したら、以下のように「munin-node」パッケージをインストールします。これだけで基本的な設定は完了で、munin-nodeプロセスが4949ポートをLISTENしはじめます。しかし今回のケースでは、これだけでは設定が足りません。munin-nodeの設定ファイルである/etc/munin/munin-node.confをエディタで開いてみてください。実行図のように「allow」ではじまる行があります。これはmunin-nodeに接続できるIPアドレスの正規表現で、デフォルトでは見ての通りローカルホストのみとなっています。つまりこのままでは別のmuninサーバーからの接続が拒否されてしまいます。ここに「allow」行を書き足して、muninサーバーにするもう1台のサーバーのIPアドレスを記述しましょう。変更を保存した後は、munin-nodeを再起動しておいてください。

munin-nodeのインストール
$ sudo apt-get install munin-node
munin-nodeに接続できるサーバーを追加する
allow ^127\.0\.0\.1$
allow ^::1$
allow ^219\.xxx\.yyy\.zzz$    muninサーバーのIPアドレスを追加
munin-nodeの再起動
$ sudo service munin-node restart
munin-nodeがTCP:4949をLISTENしている状態
$ sudo ss -lntp
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
LISTEN     0      128                       *:22                       *:*      users:(("sshd",882,3))
LISTEN     0      128                      :::4949                    :::*      users:(("munin-node",2118,5))
LISTEN     0      128                      :::22                      :::*      users:(("sshd",882,4))

プラグインの追加と削除

munin-nodeはCPU負荷、ロードアベレージ、ネットワーク転送量など、さまざまな情報を取得することができます。これらの監視項目はプラグインとして実装されており、/etc/munin/plugins以下にあります。正確には/usr/share/munin/plugins以下がプラグインの実体で、/etc/munin/plugins以下にあるのは、使いたいプラグインに対して張られたシンボリックリンクです[2]⁠。

パッケージをインストールした段階で一通り必要と思われるプラグインは有効になっていますが、もしも不要なプラグインがあったらシンボリックリンクを削除してください。また新たにプラグインを追加したい場合は、シンボリックリンクを張ってください。プラグインの追加、削除を行った後は、munin-nodeの再起動が必要です。

プラグインが動作しているかテストしたい場合は、⁠munin-run」コマンドを使いましょう。コマンドの引数にプラグイン名を与えて、⁠プラグイン名.value」として値が返ってきたならば、そのプラグインは正常に動作しています。

ロードアベレージを取得するloadプラグインのテスト
$ sudo -u munin munin-run load
load.value 0.01

muninサーバーのセットアップ

munin-runコマンドでmunin-nodeの動作確認ができたなら、次はmuninサーバーを構築しましょう。MuninはWebブラウザからグラフを閲覧するタイプのアプリケーションですので、当然Webサーバーが必要です。まずはApache HTTPサーバーをインストールします。またMuninはCGIでグラフを拡大表示することができるのですが、そのために必要となるモジュールもインストールします。CGIを使いますので、ApacheのCGIモジュールも有効にしておきます。モジュールを有効にした後はApacheを再起動しておきましょう。

WebサーバーのインストールとCGIの有効化
$ sudo apt-get install apache2 libcgi-pm-perl
$ sudo a2enmod cgi
$ sudo service apache2 restart

続いてMuninをインストールします[3]⁠。

Muninのインストール
$ sudo apt-get install munin

ところが、これだけではMuninにアクセスすることはできません。Apache用のMuninの設定ファイルの実体は/etc/munin/apache.confですが、アクセス制御にmod_accessが使われています。Ubuntu 14.04のApacheはバージョン2.4ですので、mod_authz_hostを使ってアクセス制御を行わなければなりません。具体的には「Order」「Allow」の行を削除し、⁠Require」に書き換えます。またアクセスできるホストはlocalhostのみになっていますが、自宅のPCからアクセスできないと困るので、ローカルホストからのアクセスは無条件で許可、それ以外のホストからのアクセスはBASIC認証、としました[4]⁠。具体的なdiffは下記のリストのようになります。書き換えるディレクティブは3箇所(<Directory /var/cache/munin/www>、<Location /munin-cgi/munin-cgi-graph>、<Location /munin-cgi/munin-cgi-html>)ありますので、忘れないようにしてください。

BASIC認証用のパスワードファイルは、apache2-utilsパッケージに入っている「htpasswd」コマンドで作ると良いでしょう。作成した後は一般ユーザーに見られないよう、オーナーとパーミッションと変更しておきます。

/etc/munin/apache.confの差分(抜粋)
-   Order allow,deny
-   Allow from localhost 127.0.0.0/8 ::1
+        <RequireAny>
+                Require valid-user
+                Require ip 127.0.0.1 ::1
+        </RequireAny>
+        AuthUserFile /etc/munin/munin-htpasswd
+        AuthName "Munin"
+        AuthType Basic
BASIC認証用のパスワードファイルの作成
$ sudo apt-get install apache2-utils 
$ sudo htpasswd -c /etc/munin/munin-htpasswd munin
$ sudo chown root:www-data /etc/munin/munin-htpasswd
$ sudo chmod 640 /etc/munin/munin-htpasswd

http://(muninサーバーのIPアドレス)/muninにアクセスしてユーザー名とパスワードを入力してください。MuninのWeb画面が表示され、最初から「localhost.localdomain」と言うサーバーが監視されているのがわかると思います。実はmuninパッケージにはmunin-nodeパッケージがRecommendsとして設定されているため、明示的に「--no-install-recommends」を指定しない限り、munin-nodeパッケージも同時にインストールされ、自分自信の監視を開始するのです。

Muninが監視する対象は、/etc/munin/munin.confで設定します。たとえば下記のリストに示した設定が、デフォルトで記述されているlocalhostの監視の設定です。localhostというホスト名はかっこ悪いしわかりづらいので、わかりやすい名前に変更しましょう。先ほどセットアップしたmunin-nodeサーバーも監視対象として追加するのですが、この際、複数のノードをグループとして管理することができます。[]で囲まれた中に「グループ名;ノード名」と、コロンで区切って記述します。ここではUbuntuグループとして、munin.example.comとmunin-node.example.comを設定しました[5]⁠。

デフォルトで設定されているlocalhostの監視設定
# a simple host tree
[localhost.localdomain]
    address 127.0.0.1
    use_node_name yes
localhostとmunin-nodeを監視する設定
[Ubuntu;munin.example.com]
    address 127.0.0.1
    use_node_name yes

[Ubuntu;munin-node.example.com]
    address munin-nodeIPアドレス)
    use_node_name yes

グラフの更新

Muninのグラフの更新は/etc/cron.d/muninによって起動されています。5分ごとにmuninユーザー権限でmunin-cronが実行され、各ノードから情報を収集、HTML化しています。設定が完了したら5分から10分ほど待てば新しくHTMLとグラフ画像が生成されますが、それが待てない場合は、munin-cronコマンドを手動で実行しても構いません。

Muninのアップデートを手動で実行する
$ sudo -u munin munin-cron
図1 新しくHTMLとグラフ画像が生成される
図1 新しくHTMLとグラフ画像が生成される

ノードへの疎通確認

munin-node.confでアクセスが許可されているサーバーから、munin-nodeの4949番ポートにtelnetすると、対話的にmunin-nodeから値を取得することができます。muninサーバーからmunin-nodeサーバーへの疎通ができているか、プラグインが正常に稼動しているか、と言ったトラブルシューティング時に便利です。たとえばファイアウォールやmunin-node.confのallowの設定が間違っていると、ローカルホストでのmunin-runは正常に完了しますが、muninサーバーからのtelnetは拒否されてしまう、と言った具合です。

munin-nodeへtelnetして、手動で情報を取得する
$ telnet munin-nodeサーバーのIPアドレス) 4949
fetch (プラグイン名)

Native SSH Transport

Webサービスを運用するにあたって、すべてのサーバーをグローバルに晒すということはまずありません。下記の図のように、インターネットから直接アクセスできるのはフロントエンドとなるWebサーバーやリバースプロキシ、ロードバランサーなどのみで、アプリケーションサーバーやデータベースサーバーはローカルな空間に置いて裏で繋ぐ、という構成が一般的でしょう。このような構成の場合、muninサーバーがローカルな空間のmunin-nodeに直接到達できないため、監視することができません。そんなときに役立つのが、Muninのバージョン2系から実装されたNative SSH Transport機能です。これはSSHを利用してフロントエンドのサーバーを踏み台とし、バックエンドのサーバーに接続するための機能です。

図2 SSHを利用してフロントエンドのサーバーを踏み台とし、バックエンドのサーバーに接続する
図2 SSHを利用してフロントエンドのサーバーを踏み台とし、バックエンドのサーバーに接続する

まず、muninサーバーからプロキシとなるmunin-nodeサーバーへ、muninユーザーがパスワードなしでSSH接続できるようにする必要があります。muninサーバー上でmuninユーザーのSSH鍵ペアを生成し、公開鍵をメモしてください。

muninユーザーのSSH鍵ペアの作成
$ sudo -u munin ssh-keygen
$ sudo cat /var/lib/munin/.ssh/id_rsa.pub

次にmunin-nodeサーバー上で、muninユーザーがログインできるよう設定します。デフォルトでmuninユーザーのログインシェルは/bin/falseになっていますので、これをbashに変更します。ホームディレクトリになる/var/lib/muninを作り、そこにSSH公開鍵を設置してください。

munin-nodeサーバー上での、muninユーザーの設定
$ sudo chsh -s /bin/bash munin
$ sudo install -d -m 755 -o munin -g munin /var/lib/munin
$ sudo -u munin -i
$ install -d -m 700 .ssh
$ echo (公開鍵の中身) > authorized_keys
$ chmod 600 authorized_keys

muninサーバーから以下のコマンドを実行して、munin-nodeサーバーにSSH接続ができれば準備は完了です[6]⁠。

muninサーバーからmunin-nodeサーバーへSSH接続する
$ sudo -u munin ssh 153.120.xxx.xxx

あとはmuninサーバーの/etc/munin/munin.confに、以下のようにデータベースサーバーを監視対象として登録するだけです。これでまずmunin-nodeサーバーへSSH接続し、そこでncコマンドを起動し、データベースサーバーへ接続することが可能になりました[7]⁠。

SSH Native Transportを利用した監視設定例
[Ubuntu;database.example.com]
    address ssh://(踏み台サーバーのIPアドレス)/bin/nc (対象のローカルIPアドレス) 4949
    use_node_name yes

プラグインを自作する

Muninのプラグインは、Muninの望むフォーマットに従って文字列を出力するだけ[8]です。そしてプラグインを自作すれば、数値化できるものならなんでもMuninでグラフ化することが可能です。最近はメールやTwitterにデータを送れる体重計がありますので、体重や体脂肪率を記録して、閾値を越えたらアラートを出すなんてこともできそうです[9]⁠。スマートフォンの歩数計アプリを使って、毎日の歩いた歩数を記録してみるのも良いでしょう。

私事ですが、筆者は昨年秋、北海道に移住しました。はじめての北海道の冬、やはり気になるのはその寒さです。そこでUSB温度計を使い、室温を記録してみることにしました[10]⁠。

コマンドラインから温度を取得するプログラムはGitHubで公開されています。しかしこのプログラムは、出力時の時刻がGMTでハードコーディングされているうえ、フォーマットも日本式ではありません。この問題を修正した日本向けのforkがありますので、今回はこのリポジトリを利用しました[11]⁠。

READMEに従い、コンパイルとインストールを行います。単純なプログラムですので、特にハマる部分はないでしょう。USB温度計から温度を読み取るにはroot権限が必要なのですが、それでは都合が悪いため、udevのルールを変更してmuninユーザーから読み取れるようにします。/etc/udev/rules.d/60-temper.rulesというファイルを作成し、リストの内容を記述してください[12]⁠。温度計を挿抜しなおせば、muninユーザーから読み取れるようになっています[13]⁠。

Muninプラグインは、リストの内容を/etc/munin/plugins/temperとして作成しました。シンボリックリンクでなくシェルスクリプトそのものを/etc以下に配置してしまっていますが、ここでしか使わない自作プラグインなので良しとしておきます。シェルスクリプトですので、実行権限を付けておくのを忘れないようにしましょう。あとはmunin-nodeを再起動し、munin-runやtelnet経由でtemperプラグインを叩き、⁠temper.value 17.023663」のような出力が得られれば成功です。5分待ってから、Web画面でグラフが描画されていることを確認しましょう。

muninユーザーが温度計にアクセスできるよう、udevのルールを設定する
# TEMPer1 USB thermometer
ATTR{idVendor}=="1130", ATTR{idProduct}=="660c", OWNER="root", GROUP="munin", MODE="0660"
ATTR{idVendor}=="0c45", ATTR{idProduct}=="7401", OWNER="root", GROUP="munin", MODE="0660"
コンパイルしたtemperコマンドで温度を取得できるか確認する
$ sudo -u munin /usr/local/bin/temper
2015-01-12 13:04:35,18.180950
Munin用temperプラグイン
#!/bin/sh

if [ "$1" = "autoconf" ]; then
    if [ -x /usr/local/bin/temper ]; then
        echo yes
        exit 0
    else
        echo no
        exit 1
    fi
fi

if [ "$1" = "config" ]; then
    echo 'graph_title Room Temperature'
    echo 'graph_vlabel Temp'
    echo 'graph_category Temper'
    echo 'temper.label Temp'
    echo 'temper.warning 20'
    echo 'temper.critical 26'
    echo 'temper.info Room Temperature'
    exit 0
fi

echo -n "temper.value "
/usr/local/bin/temper | cut -d',' -f2
図3 室温を記録した結果
図3 室温を記録した結果

障害時にアラートを出す

Muninには、計測されたデータがあらかじめ設定した閾値を越えた時に、アラートを出す機能(contact)が備わっています。この機能を利用して、暖房をつけて部屋が暑くなりすぎた時にアラートを発するように設定してみました[14]⁠。通常のサーバーアラートであればSMS、メール、Twitterなどで通知をしますが、今回のプラグインは筆者が在室時に暖房つけすぎの警告を出すのが目的ですので、すぐに気付けるよう、警告音を再生することにしました[15]注16⁠。

munin.conf(あるいはmunin-conf.d以下の設定ファイル)に以下のような内容を追記します。

障害時にアラートを発生させる設定例
contact.sound.command aplay /var/lib/munin/sound/temp.wav
contact.sound.always_send critical

[Ubuntu;munin.example.com]
        address 127.0.0.1
        use_node_name yes
        temper.temper.critical 24
        contacts sound

まず1行目は、soundというグループを定義し、実行するコマンドとして「aplay(再生する音声ファイル⁠⁠」を設定しています。2行目は、どのような状態の際にアラートを発生させるかの設定です。ここにはwarningとcritical(あるいはその両方)が選択できますが、今回はcriticalだけとしました。その後は前述の監視対象の設定です。⁠temper.temper.critial 24」は閾値の設定で、このホストでtemperプラグインのtemperの値が24を越えたらcriticalとするという意味です[17]⁠。最後の「contacts sound」は、このホストで障害が発生した際に、アラートを送信するコンタクトグループの設定です。まとめると「munin.example.comで監視しているtemperプラグインのtemper(室温)が24℃を越えたら、定義されているコマンドを実行して音声を再生する」という意味になります。

実際の動作状況は以下の動画を見るとわかりやすいでしょう[18]⁠。

実際の動作状況

現在は音声で警告を発するだけですが、パトライトを回してみるのも良いでしょう。Ejectコマンドと組み合わせれば自動での電源OFFも実現できそうです。夢が広がりますね[19]⁠。

皆さんもMuninで快適なリソース監視を実現してみてはいかがでしょうか。

おすすめ記事

記事・ニュース一覧