ぶていのログでぶログ

思い出したが吉日

サーバの温度を監視するmackerel-plugin-thermalを作った

この記事はMackerelのカレンダーの12/4の記事です。 昨日は@ysetoさんのmackerel でネットワークスイッチのトラフィックを監視するでした。 ネットワーク機器のようなインターフェイスがたくさんあるデバイスの監視をしたい場合、SNMPだと取りこぼしが発生するのはあるあるですね。 その問題を解決するとても面白い取り組みだと思いました!


最近、自宅サーバ熱が戻ってきてk8sクラスタを組んでいたりする。その話は明日のブログ記事にしようと思っているのでお楽しみに。 というのが前置きで、自宅サーバを再開するならもちろん監視はしっかりしたい。 もちろん監視ツールはMackerelで! 今回サーバの筐体として選んだのはRaspberry Pi4とNano Pi R4SとIntelアーキテクチャじゃなくARMアーキテクチャであったが、すんなり入ってとても体験がよい。

で、Mackerelをインストールして最低限のメトリックをとれるようになったが、自宅サーバなら筐体の温度も監視したい。 lm-sensorsを使った監視は先行事例がでてくるのだが、Thermal sysfsを使った事例は見つからなかったのでせっかくなのでMackerelプラグインを作ってみようとなり、作成したのがmackerel-plugin-thermalである。

mackerel-plugin-thermal

github.com

インストールは以下でできる。便利~

mkr plugin install buty4649/mackerel-plugin-thermal

インストール後、mackerel-agent.confに以下のような設定を追加しmacekrel-agentを再起動して数分待つとグラフができるはず。

[plugin.metrics.thermal]
command = "/opt/mackerel-agent/plugins/bin/mackerel-plugin-thermal"

作成されたグラフの例

仕組み

仕組みとしてはシンプルでGeneric Thermal Sysfs driverを介して、対応している温度センサーを読み取っている感じ。 具体的には /sys/class/thermal/thermal_zone*/temp を読んでいる。 同様のことはlm-sensorsなどでも行えるが、Thermal Sysfsの場合カーネル組み込みで追加パッケージが不要というのがメリットだと思う。 ただし、私の調べた範囲だと対応しているデバイスが少なくlm-sensorsよりも取得できるセンサーの種類が少ないと思う。

/sys/class/thermal/thermal_zone*/temp は1000倍された整数で表示されるので実際には1/1000する必要がある。

$ cat /sys/class/thermal/thermal_zone0/temp
50555
# => 50.555℃

温度は取れるようになったが、どこの温度かわからないと意味がないのでそれも調べる。 /sys/class/thermal/thermal_zone*/type にはセンサーの種類が含まれているのでこれを見るのがよい。 以下は手元の環境で実行した結果である。thermal_zone0がCPU温度、thermal_zone1がGPU温度というのがわかる。

$ cat /sys/class/thermal/thermal_zone0/type
cpu-thermal
$ cat /sys/class/thermal/thermal_zone1/type
gpu-thermal

そのほかの詳しいことについては、先に張ったカーネルのドキュメントを参照してほしい。

おまけ: mitamaeでmkr pulgin installするカスタムリソース

自宅サーバはmitamaeで構成管理している。 以下のような定義をしておくと各プラグインをインストールできて便利になると思う。

define :mkr_plugin, version: nil do
  name = params[:name]
  version = params[:version]
  package_name = version ? "#{name}@#{version}" : name
  release_tag_path = "/opt/mackerel-agent/plugins/meta/#{name}/release_tag"
  release_tag = run_command("cat #{release_tag_path} || true")

  if release_tag.stdout.empty?
    # Not installed
    execute "mkr plugin install #{name}" do
      command "mkr plugin install #{package_name}"
    end
  else
    execute "mkr plugin install #{name}" do
      command "mkr plugin install --upgrade #{package_name}"
      not_if { release_tag.stdout.chomp == version }
    end
  end
end

使い方

mkr_plugin 'buty4649/mackerel-plugin-thermal' do
  version 'v1.0.1'
end

明日はid:k1LoWです!