サーバーを監視するサーバーを立てることをダラダラ考えてみる

今現在のところ私はサーバーを複数台稼働させているのだけれど、数が増えてくると手間がかかるため一台一台順調に動いているかどうかチェックするのが煩わしくなってくる。そこで、その問題を解消するために、サーバーを監視するサーバーを立てるのはどうかと思った。サーバーが1台や2台だったらそんなことをする必要はないのだけれど、3台4台、あるいは5台6台となってくると・・・やはり必要かなと。監視サーバーにアクセスするとすべてのサーバーの状況が一瞬でわかるような構成を考えていて、まあ監視サーバーだから当然だけれども。

ぶっちゃけて言うと、今自分が使っているウインドウズで、サーバーの状況を取得するマクロを作ってそれをバッチファイルで定期的に実行して結果を適当なファイル形式で自分が見やすいように出力するようにしたら監視サーバーを立てることは必要ないような気がする・・・。あるいはそれをWindowsアプリケーションとして作ればもっと使いやすく構築することもできるかもしれない。監視サーバーはあくまで趣味として、勉強として、作る。

監視サーバーとしての必要な要件

  • 24時間常時稼働
  • 稼働中のサーバーが問題無く稼動しているかどうかのチェック

とりあえず最低限の要件を満たせればいい。稼働中のサーバーが稼働しているかのチェック方法は、その監視サーバーからリモートアクセスしてレスポンスが返ってくればとりあえず稼働していると見なす。もっと踏み込んでアプリケーションが正常に処理しているかとかもチェックした方がいいが、それはおいおい考えていくとして。

監視サーバーとして必要な具体的なソフトウェアなど

  • ubuntuかlinuxならなんでも
  • python
  • mysql
  • cron
  • php(※pythonでも可)
  • html,css
  • apache

つまり、監視サーバーは定期的に稼働中の各サーバーにアクセスして、その結果をDBに保存(例えばサーバーの負荷の状態やアクセス可否など)、その結果をウェブアプリケーションとしてHTML出力、ウェブブラウザからアクセスして確認できるようにする・・・みたいな感じ。手間がかかるだけで難しいところは多分ないと思われる。この方法のメリットはウェブサーバーを立てるから外出先からでも容易にチェックすることができるという点。

myriこのシステムを構築するために私が思う最適なマシンは、ラズベリーパイであると思う。現時点では。噂でラズパイはすごいと聞いていたが、実際に使ってみるとそのすごさに衝撃を受けた。ラズベリーパイ3の良さを語らしてもらうと、トランプの箱程の大きさにもかかわらずクアッドコアのCPUと1GBのメモリというスペックを持っていてしかも省電力。さらに標準で無線lanモジュールも搭載されていてその上ファンがないので無音。左が現在稼働中である私のラズベリーパイ3だけれども(これが監視サーバーという事実に今でも動揺してしまう)、電源コード1本挿しているだけのシンプルさで今までタワー型サーバー使っていたのはなんだったのかと思いたくなるくらいだ。肝心の性能はというと、ソフトウェアのインストールで若干もたつくかなと思うくらいでまったくストレスを感じない(HDDの代わりにmicroSDを使用しているのでその書き込み速度がボトルネックになっているのかもしれない)。今のところmysql,php,apacheといったLAMP環境で監視サーバーを構築しているがレスポンスはきびきびして快適な印象。以前似たようなので数年前に玄箱というものに手を出したことがあったが、それとは比較にならないほどに高性能かつ省スペースになっている。

mysqlのインストールとデータベースとテーブルの作成

監視サーバーが監視対象のサーバーにアクセスした結果はデータベースに保存することにする。ssh接続できた時点でサーバーがほぼ正常に稼働中であるのは確認できるが、監視サーバーっぽくするために色々情報を取得する。取得する情報は、私はサーバーOSにUbuntuを利用していて、ログイン時に、

  System load: 0.01               Memory usage: 71%   Processes:       145
  Usage of /:  71.3% of 70.32GB   Swap usage:   0%    Users logged in: 0

  Graph this data and manage this system at https://landscape.canonical.com/

みたいな情報が表示されるのでそれを取得、DBに保存してみる。その情報はpythonで/usr/bin/landscape-sysinfoを実行すれば取得できる。したがってDBに保存する情報はサーバーIP,稼働状況、HDD容量、プロセス数、メモリ使用状況、CPU負荷、日付といった具合になり、テーブル定義としては下記のような感じになった。

create database servers;
create table server_stats(
sId integer unsigned not null primary key auto_increment,
sIp varchar(75) not null,
sIsWork bool not null,
sStorage float,
sProcess integer,
sMem integer,
sCpu float,
sRecDate datetime not null);

・・・正直プロセス数とかメモリ使用状況とかわかっても意味はわからないんだけれども。

check-server.py

上記のテーブルに取得したデータを保存するプログラムは下記のような感じ。結構適当でざっくりとした感じで納品するわけでもないからただ動けばいいやと作ったので参考までに。言語はpythonでparamikoを使用してssh接続している。argvs = sys.argvの部分は監視対象のサーバーIPを引数で取得するようにしているため、このファイルを実行するときは sudo python check-server.py 192.168.1.10 といった感じになる。サーバーのディスク容量とかメモリ使用状況といった情報は正規表現で取り出して変数に入れておいて最後にDBにinsertするといった感じ。ところどころprintがあるのはデバッグの名残で意味はない。それでこのファイルをcronで1分毎に実行するように設定した。SSH接続して軽いコマンドを1回打つだけなので負荷はまったく問題にならないと思われる。そこまで密に監視する必要がなければ10分とか1時間おきとかに設定する。

import sys
import paramiko
import re
import MySQLdb

global sHdd,sMem,sProc,sCpu,sStats,sIp

sStats = 0

argvs = sys.argv
sIp=argvs[1]
port=22
username='user'
password='pass'

cmd='/usr/bin/landscape-sysinfo'

ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:
	ssh.connect(sIp,port,username,password)
	stdin,stdout,stderr=ssh.exec_command(cmd)
	list=stdout.readlines()

	sStats = 1

	for line in list:

		pattern1 = r'.*Usage of /:(.*)% of .*GB.*'
		pattern2 = r'.*Memory usage:(.*)%.*'
		pattern3 = r'.* Processes: .* (.*)'
		pattern4 = r'.*System load:.*(\d+\.\d+).*'

		#storage usage
		if re.match(pattern1,line):
			m = re.search(pattern1,line)
			print 'hdd = %s' % m.group(1).strip(' ')
			sHdd = float(m.group(1).strip(' '))

		#memory usage
		if re.match(pattern2,line):
			m = re.search(pattern2,line)
			print 'mem = %s' % m.group(1).strip(' ')
			sMem = int(m.group(1).strip(' '))

		#current process
		if re.match(pattern3,line):
			m = re.search(pattern3,line)
			print 'prcess = %s' % m.group(1).strip(' ')
			sProc = int(m.group(1).strip(' '))

		#cpu load
		if re.match(pattern4,line):
			m = re.search(pattern4,line)
			print 'cpu = %s' % m.group(1).strip(' ')
			sCpu = float(m.group(1).strip(' '))

	stdout.close()

except:
	print 'server some trouble occured.'

ssh.close()

print 'mysql test start.'
connector = MySQLdb.connect(host="localhost", db="servers", user="user", passwd="pass", charset="utf8")
cursor = connector.cursor()
sql = u"insert into server_stats(sIp,sIsWork,sStorage,sProcess,sMem,sCpu,sRecDate) values('%s',%d,%f,%d,%d,%f,now())" % (sIp,sStats,sHdd,sProc,sMem,sCpu,)
cursor.execute(sql)
connector.commit()
cursor.close()
connector.close()
print 'mysql test end.'


※随時加筆

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)