サーバのリソース使用状況レポートを作る

数百台のサーバに対して

  • CPU
  • メモリ
  • HDD

の使用状況をサクッとチェックしたいなーと思ったのですが、さすがにmuninのグラフで見るのはダルすぎる。
というわけで日次でこういうページを作ってチェックするようにしました。

上記の情報が数字でダーっと並んでて、ついでに簡単に色付けとか、muninへのリンク張りとか、各項目でのソート機能付けたりとかをやってます。
CPUとメモリの使用率は前日の平均、ディスク使用率はバッチ実行時の値です。


最初はmuninのRRDファイルから作ろうかと思ったのですが(gist)、この程度の情報ならsysstatやdfの結果から作るほうが簡単なので、sshで集めてくることにしました。

とりあえずHTMLに出力してますが、CSVで出したりDBに突っ込んだりすれば各種調査に便利ですよ!

ソースコード

Ruby1.9版です

#!/usr/local/bin/ruby
require 'net/ssh'
require 'json'
require 'erb'
require 'pp'

server_list_file = "/home/mikeda/check_servers/sv.list" # このファイルに調査対象のホストを記載
erb_template_file = "/home/mikeda/check_servers/resource.html.erb"

def summarize_cpu(sar_cpu)
  _, _, user, nice, system, iowait, steal, idle = sar_cpu.split(/\s+/)
  {
    user:   user.to_f,
    nice:   nice.to_f,
    system: system.to_f,
    iowait: iowait.to_f,
    steal:  steal.to_f,
    idle:   idle.to_f
  }
end

def summarize_memory(sar_memory)
  _, kbmemfree, kbmemused, memused, kbbuffers, kbcached, kbcommit, commit = sar_memory.split(/\s+/)
  mem = {
    kbmemfree: kbmemfree.to_i,
    kbmemused: kbmemused.to_i,
    memused:   memused.to_i,
    kbbuffers: kbbuffers.to_i,
    kbcached:  kbcached.to_i,
    kbcommit:  kbcommit.to_i,
    commit:    commit.to_f
  }
  total = ( mem[:kbmemfree] + mem[:kbmemused] ) / 1024
  used = ( mem[:kbmemused] - mem[:kbbuffers] - mem[:kbcached] ) / 1024
  {
    total: total,
    used:  used,
    usage: (100 * used.to_f / total).to_i
  }
end

def summarize_disk(df)
  disk = {}
  df.split("\n").each do |d|
    filesystem, size, used, avail, usage, mount = d.split(/\s+/)
    disk[mount] = {
      filesystem: filesystem,
      size:       size.to_i,
      used:       used.to_i,
      avail:      avail.to_i,
      usage:      usage.chop.to_i
    }
  end

  # /varが個別にマウントされていればその情報、それ以外は/の情報を返す
  disk['/var'] || disk['/']
end


servers = open(server_list_file).readlines.map(&:chomp)
resources = {}
YESTERDAY_SAR = "/var/log/sa/sa#{(Date.today - 1).strftime("%d")}"
servers.each do |host|
  begin
    Net::SSH.start(host, 'mikeda') do |ssh|
      resources[host] = {}

      sar_cpu = ssh.exec!("LANG=C sar -f #{YESTERDAY_SAR} | tail -1")
      resources[host][:cpu] = summarize_cpu(sar_cpu)

      sar_memory = ssh.exec!("LANG=C sar -r -f #{YESTERDAY_SAR} | tail -1")
      resources[host][:memory] = summarize_memory(sar_memory)

      df = ssh.exec!("LANG=C df -lmP | sed 1d")
      resources[host][:disk] = summarize_disk(df)
    end
  rescue => e
    STDERR.puts "#{host}: #{e.message}"
  end
end


### HTML出力用
def color(value, warn, critical)
  if value > critical
    'red'
  elsif value > warn
    'yellow'
  else
    ''
  end
end
def color_cpu_usr(usage); color(usage, 30, 60) end
def color_cpu_sys(usage); color(usage, 5,  10) end
def color_cpu_io(usage);  color(usage, 5,  10) end
def color_memory(usage);  color(usage, 60, 80) end
def color_disk(usage);    color(usage, 60, 80) end

puts ERB.new(File.read(erb_template_file)).result


### JSON出力用
#puts JSON.pretty_generate(resources)

とりあえずコイツをcronで毎日実行してます

7 7 * * * /home/mikeda/check_servers/check_server_resource.rb > /var/www/html/files/check_servers/resource/resource_`date +\%Y\%m\%d`.html
ERBテンプレート

各項目でソートできるようにコレ使ってます

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>サーバリソースチェック</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="/files/js/joequery-Stupid-Table-Plugin/stupidtable.min.js"></script>
<script type="text/javascript">
$(function(){
        $("table").stupidtable();
});
</script>
</style>
</head>
<body>
<table border="1">
<thead>
<tr>
<th data-sort="string">Host</th>
<th data-sort="float">user</th>
<th data-sort="float">system</th>
<th data-sort="float">io</th>
<th data-sort="float">idle</th>
<th data-sort="int">メモリ使用率</th>
<th data-sort="int">ディスク使用率</th>
</tr>
</thead>
<% resources.each do |host, r| %>
<tr>
  <td><a href="http://munin.mikeda.jp/server/<%= host %>/index.html#system"><%= host %></a></td>
  <td align="right" bgcolor="<%= color_cpu_usr(r[:cpu][:user]) %>"><%= r[:cpu][:user] %></td>
  <td align="right" bgcolor="<%= color_cpu_sys(r[:cpu][:system]) %>"><%= r[:cpu][:system] %></td>
  <td align="right" bgcolor="<%= color_cpu_io(r[:cpu][:iowait]) %>"><%= r[:cpu][:iowait] %></td>
  <td align="right" ><%= r[:cpu][:idle] %></td>
  <td align="right" bgcolor="<%= color_memory(r[:memory][:usage]) %>"><%= r[:memory][:usage] %>%</td>
  <td align="right" bgcolor="<%= color_disk(r[:disk][:usage]) %>"><%= r[:disk][:usage] %>%</td>
</tr>
<% end %>
</table>
</body>
</html>

なんでもかんでもmuninやZabbixのグラフで見ようとするのは非効率的ですよ!