Prometheus2とGrafana6によるシステム監視 GrafanaのAlertを使う

PrometheusとGrafanaの組み合わせでシステム監視している方々はアラートをどうしてますでしょうか?
「とりあえず」な感じでわかり易い方でやるならGrafanaのAlertingで、設定作るのが取っ付きにくいけど細かく指定したいならAlertmanager、または組み合わせてというのもアリかしら?まぁ、この2つは同じ機能だが全くの別物ってのを理解していればOK.

Grafana Alertingの設定

GrafanaのAlertingの設定は殆どGrafana上でできるが、一部の基本的な内容だけはテキストファイルで行う。アラートの通知にメールを使うならSMTPの設定は必要。
ファイル名は/etc/grafana.confか/usr/local/etc/grafana.conf、grafana.confではなくgrafana.iniも?Grafanaのメインの設定ファイルなのでGrafanaをインストールした時に触っている筈。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[smtp]
enabled = true
host = mx.example.com:587
user = alertuser@example.com
password = hogehoge
;cert_file =
;key_file =
;skip_verify = false
from_address = alert-from@example.com
from_name = Grafana

上は外部SMTPサーバを使用する場合。ローカルのSMTPが使えるならlocalhost:25など。その場合はuserとpasswordは不要だと思われるので行頭に ; を付けてコメントにする。SMTPの設定は簡単そうで意外とハマるので気をつける。

設定ファイルを変更したらGrafanaを再起動する。
FreeBSDの場合。
# service grafana restart

以下はGrafana上で。

Grafana AlertingとAlertmanagerの設定 1
Grafanaの左列のメニューの(Alerting)を押してからタブでNotification channelsを選択する、または(Alerting)にポインタを合わせて表示されるサブメニューからNotification channelsをクリックする。

Grafana AlertingとAlertmanagerの設定 2
Alertingの設定自体が初めてであれば[Add channel]ボタンだけが表示される。既に何かを登録していればリスト表示される筈。新しく通知チャンネルを登録するので[Add channel]をクリック。

Grafana AlertingとAlertmanagerの設定 3
Typeの項目が通知方法の選択。アラートをメールで通知するならEmailを選択する。Nameは通知する内容について何か書くようだが、メールの本文になる項目で、正直要らない。アラート状態から復帰した場合にはメールを送信しないならDisable Resolve Messageのスイッチをオンにする。
設定したら[Save]で保存。正しく送信されるかは[Send Test]をクリック。アラート関係なしのテストメールが送信される。(次)

Grafana AlertingとAlertmanagerの設定 4
指定したメールアドレス宛にこのようなテストメールが届けばOK。メールが届かないならSMTPの設定が間違っているかもしれないのでgrafana.conf(grafana.ini)の設定を見直す。

Grafana AlertingとAlertmanagerの設定 5
メールではなくwebhookを使いたいということはよくある(筈)。メールと同時にwebhookで通知というのもアリだし。
別途Notification channelの追加画面でTypeをwebhookにする。

Grafana AlertingとAlertmanagerの設定 6
webhookなら通知先のURLが重要。あと、POSTかGETかくらい?Nameはメールの時と同じで正直要らない。 [Save]で保存。[Send Test]でテスト通知を実行。もちろん、webhookを受け取る側が用意されていなければならない。(後述)

アラート発報条件の作製

既存のパネルにアラートを追加という方法もあるが、パネルによってはアラートを追加できなかったり意外と制限が多いので今回はアラート用に新しいダッシュボードとパネルを作製する。(ダッシュボードはどうでもいいけど)

Grafana AlertingとAlertmanagerの設定 7
左列のメニューのCreateからダッシュボードを追加する。

Grafana AlertingとAlertmanagerの設定 8
[Add query] [Choose Visualization] [Convert to row]のボタンが表示されるので今回は[Choose Visualization]をクリック。
次にパネルの種類の選択画面。今回はGraphを追加する。

Grafana AlertingとAlertmanagerの設定 9
参照元としてのQueryはPrometheusを指定。 監視対象のメトリクスを指定する。ここでは、とりあえずロードアベレージあたりを表示させる。Node Exporterを使用しているのでjobはnode_exporterとする。なのでMetricsには node_load1{job="node_exporter"}とした。今回はインスタンス(ホスト)は指定しないことにした。(全インスタンスが対象になる)

Grafana AlertingとAlertmanagerの設定 10
Visualizationの設定は普通で。

Grafana AlertingとAlertmanagerの設定 11
Generalの設定はTitle欄にパネル名を指定するだけで良いかと。ここまでは普通のパネル作製と変わらない。

Grafana AlertingとAlertmanagerの設定 12
Nameで任意のアラート名を指定する。
閾値を決めるConditionsが重要。上の例だと5分平均が1(100%)を超えたら発報という条件。IS ABOVEをクリックすると範囲指定なども可能。Send toには通知チャンネルを指定する。先に作製したメールとwebhookの例ではDefault(send on all alerts)のスイッチをオンにしたので登録済みのチャンネル(Emailとwebhook)が最初から入った状態且つオフにできない。
設定ができたら画面上部の保存アイコンで保存する。

これで、指定した条件が発生するとアラート通知が行われる。メール通知であればメールで、webhookならそれで通知が届くことを確認する。通知チャンネルの設定でDisable Resolve Messageのスイッチをオフにしていれば、アラート条件から回復した際にもそれぞれ通知が届く。

次はGrafana上でアラートの発生状態を確認できるようにする。

Grafana AlertingとAlertmanagerの設定 13
ダッシュボード画面でパネル追加アイコンをクリックする。
[Add query] [Choose Visualization] [Convert to row]のボタンが表示されるので[Choose Visualization]をクリック。
Visualization選択画面でAlert Listを選択する。
OptionsでState filterのスイッチを変更する。スイッチオンでそのステータスがAlert Listに表示されるというものなので、基本的にはok状態を非表示にする。アラートが1,2種類であれば表示でも良いが、たくさんあるならOK状態が表示されると邪魔。また、軽微な警告レベルのアラートであるなら非可動のインスタンス(ホスト)は非表示にするのが良いのでNo dataもオフ。

Grafana AlertingとAlertmanagerの設定 14
上部がAlert Listパネルで下部が先に作製したロードアベレージのパネル。
アラート条件に当てはまって暫く(指定時間)はPENDING(黄色)になるのでまだ通知はされない。アラート該当パネルはタイトルの(ハート)が黄色になる。

Grafana AlertingとAlertmanagerの設定 15
PENDINGを過ぎて解決されなければアラート発報になる。アラートリストのその項目が赤になるのはもちろん、アラートが発生しているパネルが細い赤枠になる。パネルタイトル部分の(割れハート)が赤になる。

Grafana AlertingとAlertmanagerの設定 16
画像作成用にアラート解消させるために閾値を変更した。本来は閾値を変えるのではなく問題そのものを解決させる。
アラート状態が解消すると、Alert Listからそのアラートが消える。(OK状態の表示をオフの場合)
アラートが発生していたパネルの赤枠が普通に戻る。(ハート)が緑になる。

Grafana AlertingとAlertmanagerの設定 17
アラート発生時のメール。モザイク部はアラートが発生したインスタンス名(複数)。同じ内容のアラートは発生インスタンスが増減しても追加通知は行われない。

Grafana AlertingとAlertmanagerの設定 18
アラート状態が解消したことを通知するメール。こちらはアラートが解消したインスタンス名は表示されない。また、複数のインスタンスで同じ内容のアラートが発生した場合は、全てのインスタンスでそのアラートが解消されるまで通知されない。

webhookの受け取り

webhookはどこかに用意したウェブサーバに受信用のスクリプトなりを置くだけ。ネットワーク的にGrafanaから到達できること。
下は簡単な受信用PHPスクリプト。

1
2
3
4
5
6
7
8
9
<?php
$logFile = __DIR__ . '/webhook.log';

if($_SERVER['REQUEST_METHOD'] == 'POST') {
  $data = file_get_contents('php://input');
  $json = json_decode($data);
  file_put_contents($logFile, print_r($json, true), FILE_APPEND);
}
?>

$jsonが配列として取り出したもの。あとは煮るなり焼くなり好きにするだけ。上の例ではログファイルに出している。もちろんログにしたところで犬の糞ほども役にも立たない。取得した情報の確認用ね。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
stdClass Object
(
    [evalMatches] => Array
        (
            [0] => stdClass Object
                (
                    [value] => 100
                    [metric] => High value
                    [tags] => 
                )

            [1] => stdClass Object
                (
                    [value] => 200
                    [metric] => Higher Value
                    [tags] => 
                )

        )

    [message] => Someone is testing the alert notification within grafana.
    [ruleId] => 0
    [ruleName] => Test notification
    [ruleUrl] => http://localhost:3000/
    [state] => alerting
    [tags] => stdClass Object
        (
        )

    [title] => [Alerting] Test notification
)

これはNotification channelの設定画面のテスト送信のデータを受信したもの。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
stdClass Object
(
    [evalMatches] => Array
        (
            [0] => stdClass Object
                (
                    [value] => 1.36397879464286
                    [metric] => node_load1{instance="192.168.41.158:9100", job="node_exporter"}
                    [tags] => stdClass Object
                        (
                            [__name__] => node_load1
                            [instance] => 192.168.41.158:9100
                            [job] => node_exporter
                        )

                )

            [1] => stdClass Object
                (
                    [value] => 1.11364397321429
                    [metric] => node_load1{instance="192.168.41.239:9100", job="node_exporter"}
                    [tags] => stdClass Object
                        (
                            [__name__] => node_load1
                            [instance] => 192.168.41.239:9100
                            [job] => node_exporter
                        )

                )

        )

    [message] => 何かメッセ
    [ruleId] => 1
    [ruleName] => System Load alert
    [ruleUrl] => http://localhost:3000/d/GTd9zVyZk/alert-manager?fullscreen&edit&tab=alert&panelId=2&orgId=1
    [state] => alerting
    [tags] => stdClass Object
        (
        )

    [title] => [Alerting] System Load alert
)

上で作成したロードアベレージのアラートはこんなの。

webhookでの通知を書いといてなんだけど、webhookで受け取るようにするとアラートの状態を管理する何かを作らないとアラート状態からの復帰時の処理が大変かもなので、webhookを受け取ったらGrafanaから curl http://grafana_user:grafana_password@grafana_server:3000/api/alerts/ でアラートのステータスを受け取る方が処理は簡単になるかも。(grafana_user, grafana_password, grafana_serverは自身のものに置き換え)

関連記事:

cronのログをauth.logやsyslogに出したくない

Debuan系のLinuxではログがrsyslogで管理されていて、cronのログが/var/log/syslogや/var/log/auth.logに出力される。これが正直凄い邪魔。cronで何か実行される度にログが出力されるので大量に溜まる。大容量ストレージがあるシステムでもこんなのが溜まるのはイヤだけどシングルボードコンピュータだともっとイヤ。

/var/log/syslog (該当ログの例)
Jan 15 10:06:01 localhost CRON[5066]: (root) CMD (実行コマンド)
/var/log/auth.log (該当ログの例)
Jan 15 10:06:01 localhost CRON[5065]: pam_unix(cron:session): session opened for user root by (uid=0)
Jan 15 10:06:01 localhost CRON[5065]: pam_unix(cron:session): session closed for user root

こんなの。

/etc/rsyslog.conf (変更)
1
2
3
4
5
6
#
# First some standard log files.  Log by facility.
#
:programname, isequal, "CRON" stop
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv,cron.none             -/var/log/syslog

syslog側だけの出力の抑制は簡単だけどauth.logへの出力の抑制が意外と手こずる。
4行目が元々は存在しない筈で、プロパティ型のフィルタでプロセス名CRONのログを抑制。多くのプロセス名は小文字だが、cronは何故か大文字のCRONなので注意。(syslogやauth.logでもプロセス名はCRONで出力されている)
行末部分、古くはstopではなく~と書かれてたみたい。
これをauth,authpriv.*の行(5行目)より前に追加。これを書いたら6行目の変更は不要。
6行目はauth.logにcronのログが出なくてsyslogだけにcronのログを出力させない場合。*.*;auth,authprivの直後に,cron.noneを追加。4行目を書いていたら要らない筈。

/etc/rsyslog.confを書き換えたらサービスを再起動。

$ sudo service rsyslog restart

こんだけ。
rsyslogは設定次第でいろい出来て凄いんだろうけど書き方のクセがすごくて解りにくいのよね。

Nexus 7 2013にLineageOS 17 (Android 10)をインストール

すでに発売されてから6年という古いタブレットのNexus 7 2013だが、大きさが手頃ということもあってベッドのお供になっている。
このタブレットは発売開始直後から言われていたことだが、ゴーストタッチが多いというか北斗百烈拳が頻繁に発生する。開発者オプションで「タップをオーバーレイ表示」して見ていると、画面全体をまんべんなく百烈拳というのの他に、画面の下辺近くを集中的に突きまくるというのが発生しているのが見える。画面を回転表示させた状態でもその表示時の下辺が突きまくられる。また、ファームウエアのバージョンやカスタムロムによっても発生頻度が変わるのでタッチパネルの不具合というハードウエアの問題だけではないと思われる。で、百烈拳が発生すると表示中のアプリが滅茶苦茶に操作されたりホーム画面に戻ったりタスクリストが表示されるだけでなく、自分の操作を受け付けてくれなくなるので電源ボタン長押しで電源断しかないことも。
だからイライラさせられることもあるけど、まぁ壊れるまでは使おうと思っていたら意外と壊れないまま現在に至る。バッテリーも持ちも良いし。

このNexus 7 2013は、まあまあ売れたということもあってか未だに開発がそれなりに。
標準のAndroidよりはLineageOSの方が好みなので比較的長い期間LineageOS 14 (Android 7 Nougat相当)を入れて使っていた。LineageOS 15.1 (Android 8.1 Oreo相当)が遅れたというのもあったし。
2019年になってLineageOS 16 (Android 9 Pie相当が)出たが、メモリ不足なのもあってかアプリの切替えが難でプチフリーズしたり再起動したりであまり良く思わなかった。12月になって、いよいよLineage 17.1 (Android 10 Q相当)の開発版が登場したが、その動きは既にLineageOS 16より若干良い感じで使い物になりそうな感じ。Nexus 7 2013はメモリが2GBしかないのでいろいろツライ部分があるけど、まぁ我慢すればなんとか。それで、糞古い端末で最新Android(相当)が使えるのだから凄い。

パーティション変更

LineageOS 16からだったか、いよいよ標準のsystemパーティションでは容量が足りないということで領域を拡張する。一度変更してしまえば再度パーティションを変更しなければ他のカスタムロムでもそのサイズで使えるので拡張しておくのがオススメ。(というかLineageOS 16, 17では拡張必須)

XDAの[REPARTITION] Nexus 7 (2013) Repartition [FLO/DEB] [16GB/32GB] [UA TWRP]スレッドの#1で提供されているRepartitioning package (flo-deb_clamor_repartition.zip)と、TWRP3.3.1-4_UAをダウンロードしてくる。Repartitioning packageはFLO(Nexus 7 2013 Wi-Fi版),DEB(Nexus 7 2013 LTE版)の両方で使用できるが、TWRP3.3.1_UAはFLO,DEBの区別ありなので手持ちのモデルに合った方を使う。

  1. 最初は普通のTWRP 3.3.1をリカバリ領域にインストール。(さんざん既出なので手順省略)
  2. 音量↑を押しながら電源をオンにしてTWRPを起動。
  3. TWRPが起動したらPCとUSBケーブルで接続
  4. PCからNexus 7 2013の内部ストレージにflo-deb_clamor_repartition.zipをコピー
  5. TWRPメニューから[Install]を押す。
  6. ファイルリストからflo-deb_clamor_repartition.zipを選択。
  7. 右下の[Install Image]を押してイメージを書き込み。
  8. ホームボタンを押してTWRPメイン画面に戻る。
  9. 左下の[Advanced]を押す。
  10. [Terminal]を押す。
  11. コマンドライン画面になるので「modify」と入力してチェック。
  12. 終了したらホームボタンを押してTWRPメイン画面に戻る。
  13. 右下の[Reboot]を押す。[Bootloader]を押す。
  14. PCのターミナル/コマンドラインからadbでTWRP3.3.1_UAをリカバリ領域にインストール。
  15. 音量↑を押しながら電源をオンにしてTWRP3.3.1_UAを起動。
  16. TWRPメニューから[Wipe]を押す。
  17. [Format Data]を押す。入力画面で「yes」と入力してチェック。
  18. ホームボタンを押してTWRPメイン画面に戻る。
  19. TWRPメニューから[Wipe]を押す。
  20. 右下の[Format Data]を押す。
  21. 入力画面で「yes」と入力してチェック。
  22. もう一度「Wipe」画面に戻り、左下の「Advanced Wipe」を押す。
  23. リストのチェックボックスに全てチェックする。画面下のスライダーを右に。
  24. 入力画面で「yes」と入力してチェック。

17か21でMount関係のエラーが赤文字で幾つも表示されるが、これは問題ないので無視する。

LineageOS 17のインストール 1
上の手順の10番。

LineageOS 17のインストール 2
上の手順の11番。

LineageOS 17.1のインストール

  1. XDAの[ROM][flo|deb][UNOFFICIAL][AospExtended-v7.0][Lineage-17.1](変更)[ROM][UNOFFICIAL][10] LineageOS 17.1 [deb][flo]からFLOまたはDEBのLineageOS 17.1をダウンロード。
    2020年1月22日にAospExtended-v7.0とLineageOS 17.1の共同スレッドだったのが分離し、旧スレッドはAospExtended-v7.0が引き継ぎました。
  2. XDAのGAPPS ARM10.0のリンクからGAPPSをダウンロードする。
  3. TWRPは前の作業から引き続きでもNuxus 7 2013を再起動してリカバリモードでも可。
  4. (TWRPが起動したら)PCとUSBケーブルで接続
  5. PCからNexus 7 2013の内部ストレージにLineageOS 17.1とをGAPPSの2ファイルをコピー。
  6. TWRPメニューから[Install]を押す。
  7. ファイルリストからLineageOS 17.1のファイルを選択。
  8. 選択したファイル名が表示されていることを確認して画面下部のスライダーを右に。
  9. イメージ書き込みが終了したらホームボタンを押してメイン画面に戻る。
  10. 通常はここでGAPPSをインストールだが今回はこのタイミングではインストールしない2020年1月24日追記: LineageOS17.1 1月22日版とOpenGAPPS Android10 Arm用 nanoの組み合わせではエラーにならなかったのでここでOpenGAPPSインストールして問題ありません。また、下の12番からの手順もシステム起動後にセットアップウィザードが走るので不要。
  11. 右下[Reboot]を押す。[System]を押す。
  12. LineageOS 17.1が起動する。何も操作しないで数分待つ。
  13. 電源ボタンを2秒押して右に表示される電源オプションから「電源を切る」か「再起動」(英語で表示される)を押す。
  14. 音量↑を押しながら電源ボタンで起動、または音量↑を押しながら再起動してTWRPを起動させる。
  15. TWRPメニューから[Install]を押す。
  16. ファイルリストからGAPPSのファイルを選択。
  17. 選択したファイル名が表示されていることを確認して画面下部のスライダーを右に。
  18. イメージ書き込みが終了したらホームボタンを押してメイン画面に戻る。
  19. 右下[Reboot]を押す。[System]を押す。
  20. LineageOSが起動したらLineageOS(Android)設定画面から「System」を選択する。
  21. 言語設定で日本語を追加してから追加した日本語行の一番右を上にスライドしてリストの一番上にする。
  22. 引き続き「システム」メニューから「日付と時刻」を開く。
  23. 「ネットワークから提供されたタイムゾーンを使用する」をオフにしてタイムゾーンを「東京」(+9:00)にする。
  24. LineageOS(Android)設定画面から「ネットワークとインターネット」を選択する。
  25. Wi-FiやLTEの設定を行いインターネットに接続する。
  26. LineageOS(Android)設定画面から「アカウント」を選択する。
  27. 「アカウントを追加」から「Google」を選択。
  28. 自身のGoogleアカウントを登録する。

LineageOS 17.1のイメージとGAPPSを焼いてから初起動させるとブートループになるのでGAPPSは後から焼くという手順。

2020年1月11日時点ではOpenGAPPSが使えなかったので今回は個人提供のGAPPSを使用した。 他のGAPPSを入手できるならAndroid 10用のARM版を取る。(Nexus 7 2013はARM64版ではない)

2020年1月24日追記: OpenGAPPSのAndroid 10のARM版はpicoとnanoが利用可能になっている。

通常であればOS初起動時にGoogleアカウントのセットアップウィザードが表示されるのだが、今回はその部分が未完成のため表示されない。必要な設定はLineageOS(Android)設定画面から行う必要がある。

LineageOS 17のインストール 3
GAPPSのインストールまで完了した状態のホーム画面。

LineageOS 17のインストール 4
Android 10相当であることやセキュリティパッチが2020年1月1日まで当たっていると表示されている。本当かどうかは不明。

ベッドのお供に使っていると書いたが、Android 10相当なのでダークモードが使えるのがありがたいかも。

LineageOS 16ではタスク切替えやタスクリスト表示でもたついたりプチフリーズになったり、酷いと再起動が発生したり。今回インストールしたLineageOS 17ではその部分の動作はキビキビと。しかし、ロック画面の解除時にもたついたりプチフリーズが発生してやり直しがしばしば。つまりロック解除してしまえばまあまぁ。
そして、LineageOS 14使用時にはベラボーに頻発した百烈拳がLineageOS 16と今回のLineageOS 17では発生していない。寒い時期だから?