Prometheus2とGrafana6によるシステム監視 シングルボードコンピュータの温度表示

Node ExxporterのデータをGrafanaで表示 1

「がとらぼ」の中の人の環境は、インターネットに公開するサービスを提供するサーバは基本的にFreeBSD、LAN内の自分専用機材はLinuxという住み分け。逆もそれぞれ少しずつ混じってるけど。
で、LAN内のLinuxは、PCで動いているもの以外に、シングルボードコンピュータが数枚。それらは「がとらぼ」でも記事を書いたRaspberry Pi ZeroWとかNanoPi NEO/NEO2とかOrangePiとかエトセトラ・エトセトラ・エトセトラ。(ユル・ブリンナー風)

動かす機材が増えるとLANであっても監視するようにしておかないと、知らない内に停まってたり、リソースが不足して調子が悪くなってたりで困ることに。ホストに仕込んでいるシステム監視用エージェントのNode Exporterは簡単にシステムの各種情報を拾ってくれるが、シングルボードコンピュータ(Linux)のメトリクス値の元ネタの在り処がPCのLinuxとはちょっと違うので、PCのLinuxから情報取得することを想定していると思われるNode Exporterの素の状態では取れない値がある。
前回、FreeBSDでメトリクス名が違う場合にPrometheusでそれを読み替えるというのをやったが、今回は普通にNode Exporterを動かしただけだと取れない値を取得する。
シングルボードコンピュータで特に監視したいのはストレージ(MicroSDカード)の空き容量とメモリの使用状況とCPUの温度。この中でNode Exporterでは普通に取得できないのがCPUの温度。シングルボードコンピュータは、理想的な排熱が行われない環境で使うことがあるので、温度の監視は重要。油断してるとCPUがアッチッチになってハングアップしたり、勝手にクロック落ちてノロノロになったりで良いことはない。そこで、今回はシングルボードコンピュータのCPU(SoC)の温度をNode Exporterで取るのだけやる。

2020年10月21日追記:
次の「Node Exporterの設定」以下に関わることだが、Node Exporterのバージョンが進んで、今年前半くらいから温度取得機能がNode Exporterに内蔵された。それ自体はとてもありがたいのだが、システムによっては上手く取得することができずにエラーが発生する。 Armbian 20.08.7 Buster と Node Exporter ver.1.0.1で確認。

Oct 21 07:40:46 localhost node_exporter[609]: level=error ts=2020-10-21T07:40:46.060Z caller=collector.go:161 msg="collector failed" name=thermal_zone duration_seconds=0.002203762 err="read /sys/class/thermal/thermal_zone2/temp: invalid argument"
Oct 21 07:41:01 localhost node_exporter[609]: level=error ts=2020-10-21T07:41:01.070Z caller=collector.go:161 msg="collector failed" name=thermal_zone duration_seconds=0.002234116 err="read /sys/class/thermal/thermal_zone2/temp: invalid argument"

こんなエラーが/var/log/daemonlogに大量に出力されるため、ストレージの小さなシングルボードコンピュータ等ではあっというまにストレージがフルになってしまう。(ログローテーションしてれば避けられるけど)
温度取得のコレクタは collector.thermal_zone なので Node Exporterの設定に --no-collector.thermal_zone を追加して温度取得のコレクタを無効にする。その上で以下の内容を実行。
新しいバージョンのNode Exporterで、ログを見てエラーの発生が無く、温度取得のコレクタが正常に機能しているならこの記事の以下は全て不要です。温度コレクタはデフォルトが「有効」。

Node Exporterの設定

Node Exporterは外部ファイルを読んでメトリクスとして出力する機能を持っている。ただし、外部ファイルの中身はメトリクスの形式を満たしていないといけない。つまり、適切な形式で書いた外部ファイルを用意したら、Node Exporterがそれも一緒に出力しますよというもの。
外部ファイルは普通のPC版のLinuxなら、/var/lib/node_exporter/textfile_collector 辺りに置くことになると思われる。しかし、シングルボードコンピュータのストレージは綿菓子並に耐久性の無いmicroSDカードだったりするので、迂闊に普通のファイルシステムを書き換えまくるとmicroSDカードが速攻でぶっ壊れて使えなくなるのでこのディレクトリは避けたい。また、そこに置くファイル自体は、その瞬間の情報だけであって、それを長期保存する必要は1㍉もない筈。なので、tmpfsの/tmp あたりが無難かしら?そこで、/tmp/node-exporterというディレクトリを使うことにする。(拡張子.promのファイルしか読まないらしいので、専用ディレクトリでなくても良さそう。単に/tmpでも良いかも。)

Node Exporterの設定ファイルはLinuxのパッケージでインストールしていればDebian系のディストリビューションなら/etc/default/prometheus-node-exporter、自分でインストールした場合はサービス起動用のファイル /lib/systemd/system/node-exporter.service などに記載したPathになる。/etc/node-exporterとかetc/node_exporterとかその辺りが多いかしら?
そのファイルでARGSを指定するはずなので、その値に--collector.textfile.directory設定を追加する。今回は使用するディレクトリを/tmp/node-exporterにすると決めたので--collector.textfile.directory=/tmp/node-exporterのように書く。(下)

/etc/default/prometheus-node-exporter (変更)
ARGS="--no-collector.nfsd --no-collector.nfs \
      --no-collector.systemd --no-collector.sockstat --no-collector.timex \
      --collector.textfile.directory=/tmp/node-exporter"

黄色部分が今回の追加部分。その他の指定は好みで。大抵は出力不要なコレクタを指定する筈。途中で改行する場合は行末に \ (バックスラッシュ)を付ける。もちろん全て1行で書いても構わない。

Node Exporter本体側の設定はこれだけ。

サービスを再起動する。(これは何時でも任意で)

$ sudo service prometheus-node-exporter restart

サービス名はDebian系パッケージならprometheus-node-exporterだが、手動でインストールした場合は/lib/systemd/system/の中のNode Exporterサービス用のファイル名から.serviceを除いたもの。

温度の出力

Node Exporterが利用する外部ファイルの中身はNode Exporterのメトリクスの形式を満たした状態でなくてはならないらしい。
なので、CPUの温度であれば以下のようなのを出力すれば良いっぽい。

# HELP node_hwmon_temp_celsius CPU temperature
# TYPE node_hwmon_temp_celsius gauge
node_hwmon_temp_celsius 41.53

これは温度を1つだけ摂氏で出力するもの。通常のPC版Linuxであればhwmonコレクタで取得する値。
おそらく、シングルボードコンピュータの場合はコアが複数のSoCであっても温度は1つしか取得できないだろうからこんな感じのファイルを作れば良いはず。

# HELP node_hwmon_temp_celsius CPU temperature
# TYPE node_hwmon_temp_celsius gauge
node_hwmon_temp_celsius{cpu="0"} 37.9
node_hwmon_temp_celsius{cpu="1"} 37.9
node_hwmon_temp_celsius{cpu="2"} 38.9
node_hwmon_temp_celsius{cpu="3"} 38.9

コア毎に複数の温度を計測できるCPUの場合は上のような形式になるので、このような内容でファイルを出力するようにすれば良いはず。

今回はシングルボードコンピュータ用に1つの温度だけ求めることにする。
そして、温度を取得して整形して/tmp/node-exporter/node_hwmon_temp_celsius.prom というファイルに吐き出させたい。
CPUの温度はシングルボードコンピュータのDebian系Linuxなら /sys/class/thermal/thermal_zone0/temp を参照すれば判る。
それを1分毎にcronで実行したい。それだけ。

/usr/local/bin/get_temperature.sh (新規作成)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/sh
met="node_hwmon_temp_celsius"  #出力するメトリクス名
dir="/tmp/node-exporter/"   #出力ディレクトリ
ctemp=$( cat /sys/class/thermal/thermal_zone0/temp )  #CPU温度取得
otempa="`expr $ctemp / 1000`"
otempb="`expr $ctemp % 1000`"
otemp="${otempa}.${otempb}"
line1="# HELP ${met} CPU temperature"
line2="# TYPE ${met} gauge"
/bin/echo "${line1}\n${line2}\n${met} ${otemp}" > ${dir}${met}.prom.$$
/bin/mv ${dir}${met}.prom.$$ ${dir}${met}.prom
/bin/chmod 666 ${dir}${met}.prom    #出力ファイルのパーミッション指定

ボーンシェルのスクリプトにしたのは、BSD/Linuxほぼ全ての環境でも動くから。Linuxだと/bin/shの実体はdashが多いようだけど、問題なく動く。
10行目、多くのLinuxのechoでは標準で\nが改行として機能する。上のスクリプトはそれが前提。一部のLinuxでは標準では\nが改行ではなくそのまま\nという文字列として表示されるのでecho に-eオプションを付ける。xBSDのechoでは\nが改行にはならず、-eオプションも無いと思われるのでxBSDでは\nの部分はスクリプト側で改行する。
変数を${変数名}形式にしてるのは編集のときにわかりやすいから。
最後の方で出力ファイルを直接上書きでなくて、別ファイルに出して移動させてるのは、以前のbeatsでは直接上書きだと値の更新(ファイルこの更新)を認識してくれなかったから。Node Exporterはどうか知らないけどbeats用と同様にした。
やってることに特に意味はないので好きに書き換えて下さい。

$ sudo chmod +x /usr/local/bin/get_temperature.sh

パーミッションを実行可にしておく。誰が何度実行しても構わないてので全ユーザー実行可能な+xで指定。

気を付けたいのは出力したファイルとファイル置き場の/tmp/node-exporterディレクトリがNode Exporterから読み取り可能なパーミッションでなくてはならないこと。当然だと言えばそうだけど、これが意外とやっかい。
そこで、/etc/rc.localに起動時に自動的にディレクトリを作らせるようにする。1分毎の実行スクリプト側では余計なことはやらせない。

/etc/rc.local (exit 0の前に2行挿入)
/bin/mkdir /tmp/node-exporter
/bin/chmod 777 /tmp/node-exporter
/etc/crontab (1行追加)
*  *    * * *   root    /usr/local/bin/get_temperature.sh >/dev/null 2>&1

cronで1分ごとに実行するようにする。
なお、volumio2の場合は標準状態ではcronがインストールされていないので/etc/crontabを編集する前にcronをインストールする。

$ sudo apt install cron

volumioでcronのインストールはこんな感じで良かった筈。インストール前のパッケージ名確認はapt-cache search cron でも打って下さい。

/etc/crontabは保存したらそれで適用になるのでこれで1分ごとに/tmp/node-exporter/node_hwmon_temp_celsius.promが出力されていることと、ファイルのタイプスタンプが1分ごとに新しくなることを確認する。

ブラウザでそのホストのポート9100のmetricsを開く。 要するにhttp://IPアドレス:9100/metrics を見る。で、たくさんのメトリクスの中に混じって温度が出力されていることを確認する。

Grafanaで温度のグラフを暫く眺めて、温度が変化することを確認する。
温度のグラフは、前から紹介しているhttps://grafana.com/dashboards/1860のテンプレートでは下部で折りたたまれているSystem Detailを開き、その最後のグラフ。

Node ExxporterのデータをGrafanaで表示 2

この温度はNanoPi NEO(無印)で、NTPサーバとNode Exporterだけが動いている。ほぼ仕事はしていないのでだけ、CPUの使用率は0.2%程度。せっかくのH3 SoCが宝の持ち腐れ?
金属ケースに格納したけど、SoCが仕事をしていないのとヒートシンクが付いているのとヒートシンクからケースに熱が逃げるのが効いているのかほぼ気温と変わらないという良好な結果。

Node ExxporterのデータをGrafanaで表示 3
この温度はRaspberry Pi Zero Wで、Volumioが24時間ウェブラジオを再生している。ちなみにこの記事の最初の画像も同じRaspberry Pi Zero W + Volumio。
普通ならRaspberry Pi Zero Wは大して熱くならない筈。しかし、DACと一緒に金属ケースに入れたので自然空冷できないのに発熱するチップ自体にはヒートシンクも何も付けていないのと、さらに、その金属ケースごと電波を外部に出さないための小さな電波のシールドボックスに入れていて熱の逃げ場所が無いということもあってNanoPi NEOよりだいぶ熱くなっている。とはいえ、50度は下回っているのでそんなに心配するほどでもないかなと思う。

ADS-Bの受信用に最近手に入れたOrange Pi Zero Plusは屋外の塩ビパイプの中で稼働という悪い環境で、暑い日中にCPU温度が70度越えてて心配してたんだけど、3日ほど前から無事死亡している模様。通信が途切れる直前までのGrafanaのグラフは特に突然何かが変化したとかはなかったが、電源プラグを挿し直して貰っても復活しないので、どうなっているのか週末に確認しに行く予定。
この記事は9月初旬に公開したつもりが公開し忘れていたものです。

関連記事:

Prometheus2とGrafana6によるシステム監視 FreeBSDのメモリとCPU温度

前々回、PrometheusとGrafanaとNode Exporterのインストールを行った。前回は、既存のGrafanaのNode Exporter用テンプレートを貰ってきて使ったが、Linuxホストの監視用特化なのでFreeBSDのホストではメモリや温度の情報が表示されなかった。
そこで、今回はテンプレートはそのままで、Prometheus側の設定でFreeBSDの情報をLinuxの情報互換にして表示する。
初歩の初歩なので、すでにPrometheus, Grafanaを使いこなしている人にとっては見るところが無いかも。

CPU温度を取れるようにする

FreeBSDではCPUの温度はカーネルの温度関係のモジュールを使えるようにしていないと機能しないかもしれない。まぁ、システム監視をするなら間違いなく有効にしているだろうけど。

手動でカーネルモジュールを読み込んで温度を確認する方法

# kldload coretemp    #←カーネルモジュール読み込み CPUがAMD系ならkldload amdtemp
# sysctl dev.cpu | grep temperature  #←CPU温度表示
dev.cpu.3.temperature: 42.0C    #以下、CPUのコア(仮想含む)の数だけ温度が表示される。
dev.cpu.2.temperature: 42.0C
dev.cpu.1.temperature: 41.0C
dev.cpu.0.temperature: 41.0C
/boot/loader.conf (システム起動時に自動的に読み込む設定を追加)
1
2
coretemp_load="YES"  #Intel系CPU用
amdtemp_load="YES"  #AMD系CPU用

Node Exporterの情報確認

Node Exporterの情報はプル(Pull)なので、送られてくるのではなく取りに行く。つまり「http://Node Exporterホスト:9100/metrics」にアクセスしたらそのホストのNode Exporterの情報を取ることができる。
FreeBSDのホストのNode Exporterの情報を見るとメモリと温度は以下のようなの。つまり、Grafanaで見ると表示はされていないが、それらしいものは出力はされている。ただし、Linuxと比べると取得できる項目はだいぶ少ないっぽい。

メモリ
# HELP node_memory_active_bytes Recently used by userland
# TYPE node_memory_active_bytes gauge
node_memory_active_bytes 1.083392e+07
# HELP node_memory_buffer_bytes Disk IO Cache entries for non ZFS filesystems, only usable by kernel
# TYPE node_memory_buffer_bytes gauge
node_memory_buffer_bytes 1.16641792e+08
# HELP node_memory_cache_bytes Almost free, backed by swap or files, available for re-allocation
# TYPE node_memory_cache_bytes gauge
node_memory_cache_bytes 0
# HELP node_memory_free_bytes Unallocated, available for allocation
# TYPE node_memory_free_bytes gauge
node_memory_free_bytes 1.2384256e+08
# HELP node_memory_inactive_bytes Not recently used by userland
# TYPE node_memory_inactive_bytes gauge
node_memory_inactive_bytes 7.29227264e+08
# HELP node_memory_size_bytes Total physical memory size
# TYPE node_memory_size_bytes gauge
node_memory_size_bytes 1.949618176e+09
# HELP node_memory_swap_in_bytes_total Bytes paged in from swap devices
# TYPE node_memory_swap_in_bytes_total counter
node_memory_swap_in_bytes_total 0
# HELP node_memory_swap_out_bytes_total Bytes paged out to swap devices
# TYPE node_memory_swap_out_bytes_total counter
node_memory_swap_out_bytes_total 0
# HELP node_memory_swap_size_bytes Total swap memory size
# TYPE node_memory_swap_size_bytes gauge
node_memory_swap_size_bytes 0
# HELP node_memory_swap_used_bytes Currently allocated swap
# TYPE node_memory_swap_used_bytes gauge
node_memory_swap_used_bytes 0
# HELP node_memory_wired_bytes Locked in memory by kernel, mlock, etc
# TYPE node_memory_wired_bytes gauge
node_memory_wired_bytes 1.085915136e+09

CPU温度
# HELP node_cpu_temperature_celsius CPU temperature
# TYPE node_cpu_temperature_celsius gauge
node_cpu_temperature_celsius{cpu="0"} 40.9
node_cpu_temperature_celsius{cpu="1"} 40.9
node_cpu_temperature_celsius{cpu="2"} 41.9
node_cpu_temperature_celsius{cpu="3"} 41.9

Linuxと比べるとFreeBSDではメトリクス名が違うのが判るはず。LinuxとFreeBSDで明らかに対応しそうな似たメトリクス名があってもそれに値が入っていない場合は別のメトリクスから探さなければならなかったり、複数のメトリクス値から計算する必要があったり。

node exporter 1
Grafanaで使用しているテンプレートから、メモリのグラフ表示のためにの何のメトリクスを使っているかを編集モードで確認する。クエリーの全文を確認する。1つのメトリクスしか使われていないとは限らない。

FreeBSD           ⇔    Linux
メモリ
node_memory_free_bytes   ⇔ node_memory_MemAvailable_bytes
node_memory_inactive_bytes ⇔ node_memory_MemFree_bytes
node_memory_size_bytes   ⇔ node_memory_MemTotal_bytes
スワップ
node_memory_swap_size_bytes ⇔ node_memory_SwapTotal_bytes
node_memory_swap_used_bytes ⇔ node_memory_SwapCached_bytes
node_memory_swap_size_bytes - node_memory_swap_used_bytes(差分) ⇔ node_memory_SwapFree_bytes
CPU温度
node_cpu_temperature_celsius ⇔ node_hwmon_temp_celsius

「がとらぼ」の中の人はFreeBSDではスワップを使わない方針のため、ちょこっと試しただけでテキトーに書いてます。間違っていたらスミマセン。

Prometheusの設定変更

対応を調べたら、メトリクス名の書き換えをPrometheusに設定する。
このときに、ルールを書く設定ファイルを分ける。

メインのPrometheusの設定ファイル
/usr/local/etc/prometheus.yml (追記)
1
2
rule_files:
   - "prometheus_node_exporter.yml"

2行を追加する。すでに別のルールファイルを指定して使っているなら既存のルールファイルの指定行の次の行に上の2行目を指定する。
YAMLファイルは行頭の字下げに意味があるのでむやみに字下げしたり、逆に行頭のスペースを取らないこと。
ファイル名だけを指定したら設定ファイルと同じディレクトリという意味なので/usr/local/etc/prometheus_node_exporter.ymlになる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
groups:
- name: node_exporter-FreeBSD-metrics  #何か名前をつける
  rules:
  - expr: node_memory_free_bytes                #書き換え元のメトリクス名
    record: node_memory_MemAvailable_bytes    #書き換え後のメトリクス名
  - expr: node_memory_inactive_bytes
    record: node_memory_MemFree_bytes
  - expr: node_memory_size_bytes
    record: node_memory_MemTotal_bytes
  - expr: node_memory_swap_size_bytes
    record: node_memory_SwapTotal_bytes
  - expr: node_memory_swap_used_bytes
    record: node_memory_SwapCached_bytes
  - expr: (node_memory_swap_size_bytes{job="node_exporter"} - node_memory_swap_used_bytes{job="node_exporter"})
    record: node_memory_SwapFree_bytes
  - expr: node_cpu_temperature_celsius
    record: node_hwmon_temp_celsiu

Linuxのnode_memory_SwapFree_bytes (スワップの空き容量)に相当する値はFreeBSDでは取得できないようなので、node_memory_swap_size_bytes (スワップの全容量)とnode_memory_swap_used_bytes (スワップ使用量)の差分を求めて、その値がスワップの空き容量だろうとした。何台かのFreeBSDホストでスワップを使っていたらこのメトリクス名と計算が正しいのか確認できたんだろうけど、空いてた1台に急遽スワップを作って、スワップがほぼほぼ使われない中で「これかな?」で出したので正しいかは判らない。

Grafanaでグラフ表示を確認する

Prometheusを再起動またはリロードする。

# service prometheus restart
または
# service prometheus reload

暫く待ってGrafanaにメモリ、スワップ、CPU温度が表示されればOK.

node exporter 2
前回のテンプレートではCPU温度は 下部で折りたたまれたSystem Detailを展開した最後のグラフ。

このようにメトリクス名を変換、或いは、複数のメトリクスから計算した値を渡すようにすることで、Linuxとは違う名前のメトリクスで出力されるシステムでも簡単に表示できるようになる。今回の場合はテンプレートを弄っていないので当然Linuxホストはそのまま正常に表示できる。

関連記事:
Up