ルーティングツリーとバーンレートのアラート
目標
Alertmanagerの設定を、ルーティングツリーから抑制ルールまで自分で書き、SLOから逆算したバーンレートのアラートを2つ作り、ランブックの欠落をビルドで止めるゲートを作成します。
なぜ重要なのか
アラートの成功基準は、「問題を検知したか」ではなく、人が今、何かをしなければならないかです。この基準を通らないアラートは、正確でも有害です。正確なアラート400個がオンコールの反応速度を壊してしまえば、正確さにはまったく意味がありません。そのため、順序が決まります。ユーザーの症状でSLOを定義し、バジェットからしきい値を逆算し、長いウィンドウと短いウィンドウをANDでつないで感度と誤検知を同時に押さえ、グルーピングと抑制でアラートの件数を人が読めるレベルまで減らし、ページにはランブックを必須にします。しきい値を「過去の最大値の1.2倍」のような方法で決めると、なぜその値なのかを説明できず、説明できないしきい値は、事故が起きるたびに少しずつ上がっていきます。
ステップ
/root/pca-alerting/alertmanager.ymlを作成し、ルートのrouteを書きます。receiver: ticket-queue、group_by: ['alertname', 'cluster', 'slo']、group_wait: 30s、group_interval: 5m、repeat_interval: 4hを設定します。- ルートの
routesの最初の項目に、子ルートを入れます。matchers: ['severity="page"']、receiver: oncall-pager、group_wait: 10s、repeat_interval: 1hを設定します。 receiversに、2つの受信先を定義します。ticket-queueとoncall-pagerのそれぞれにwebhook_configsを置き、urlは、http://で始まる内部アドレスであれば何でもかまいません。inhibit_rulesの最初の項目を書きます。source_matchers: ['alertname="ClusterDown"', 'severity="page"']、target_matchers: ['severity=~"page|ticket"']、equal: ['cluster']を設定します。/root/pca-alerting/burnrate.ymlを作成し、グループの下にアラートCheckoutErrorBudgetBurnFastを書きます。exprは、job:slo_errors:ratio_rate1h{job="checkout-api"} > (14.4 * 0.001)と、job:slo_errors:ratio_rate5m{job="checkout-api"} > (14.4 * 0.001)と、job:http_requests:rate5m{job="checkout-api"} > 1の3つの項をandでつないだもの、for: 2m、labelsにはseverity: pageとslo: checkout-availability、annotationsにはsummaryとrunbook_urlを入れます。- 同じファイルに、アラート
CheckoutErrorBudgetBurnSlowを追加します。exprは、job:slo_errors:ratio_rate6h{job="checkout-api"} > (6 * 0.001)と、job:slo_errors:ratio_rate30m{job="checkout-api"} > (6 * 0.001)をandでつないだもの、for: 15m、labelsにはseverity: ticketとslo: checkout-availabilityを入れます。 /root/pca-alerting/runbook-gate.shを作成します。1つ目の引数でルールファイルのパスを受け取り、labels.severityがpageなのにannotations.runbook_urlがないアラートが1つでもあれば、その名前を出力して0以外のコードで終了し、1つもなければ0で終了します。
参考
- ステップ5と6の
exprは、expr: |ブロックで複数行に書いてもかまいません。採点は空白を無視します。 - ステップ7の検証は、あなたが作成した
burnrate.yml(通る必要があります)と、採点ツールが作成したランブック欠落のファイル(止める必要があります)の2つで行われます。severity: ticketのアラートまで止めると、失敗します。 - ヒント:
yq '.groups[].rules[] | select(...) | .alert' "$1"で一覧を取り出し、空でなければexit 1にします。 - よくある間違い1:
group_byにinstanceを入れてしまうことです。Podの数だけアラートが来ます。 - よくある間違い2: 抑制ルールで
equalを入れ忘れることです。別のクラスターのアラートまで抑制されます。
ルートレベルのrouteを書く
/root/pca-alerting/alertmanager.ymlを作成し、ルートのrouteを書きます。receiver: ticket-queue、group_by: ['alertname', 'cluster', 'slo']、group_wait: 30s、group_interval: 5m、repeat_interval: 4hを設定します。
ルートのreceiverは、マッチする子がないときの既定値です。group_byに何を入れるかがアラートの件数を決める、という点を思い出してください。3つのタイマーは、それぞれ最初の送信の待機、グループの更新間隔、変化がないときの繰り返し間隔です。
重大度別の子ルート
ルートのroutesの最初の項目に、子ルートを入れます。matchers: ['severity="page"']、receiver: oncall-pager、group_wait: 10s、repeat_interval: 1hを設定します。
routesはルートの下のリストで、上から下へマッチします。continueを有効にしなければ、最初のマッチで止まります。子は親の設定を継承し、明示した値だけを上書きします。
受信先の定義
receiversに、2つの受信先を定義します。ticket-queueとoncall-pagerのそれぞれにwebhook_configsを置き、urlは、http://で始まる内部アドレスであれば何でもかまいません。
ルートで名前で参照した受信先がreceiversの一覧になければ、設定が読み込まれません。このラボ環境には実際の送信先がないので、WebhookのURLで形だけ整えます。
抑制ルール
inhibit_rulesの最初の項目を書きます。source_matchers: ['alertname="ClusterDown"', 'severity="page"']、target_matchers: ['severity=~"page|ticket"']、equal: ['cluster']を設定します。
抑制は、原因のアラートが生きているときに、下位の症状のアラートを止めます。equalに書いたラベルの値が両側で同じであるときに成立するので、このラベルを抜かすと、別のクラスターのアラートまで抑制されます。
速い消費のアラート
/root/pca-alerting/burnrate.ymlを作成し、グループの下にアラートCheckoutErrorBudgetBurnFastを書きます。exprは、job:slo_errors:ratio_rate1h{job="checkout-api"} > (14.4 * 0.001)と、job:slo_errors:ratio_rate5m{job="checkout-api"} > (14.4 * 0.001)と、job:http_requests:rate5m{job="checkout-api"} > 1の3つの項をandでつないだもの、for: 2m、labelsにはseverity: pageとslo: checkout-availability、annotationsにはsummaryとrunbook_urlを入れます。
長いウィンドウは消費の速度を、短いウィンドウは今も進行中かどうかを判定します。ここに最小トラフィックのゲートを加えて、3つの項をANDでつなぎます。長いウィンドウをすでに使っているので、forは欠落の吸収用に短くかけます。
遅い消費のアラート
同じファイルに、アラートCheckoutErrorBudgetBurnSlowを追加します。exprは、job:slo_errors:ratio_rate6h{job="checkout-api"} > (6 * 0.001)と、job:slo_errors:ratio_rate30m{job="checkout-api"} > (6 * 0.001)をandでつないだもの、for: 15m、labelsにはseverity: ticketとslo: checkout-availabilityを入れます。
バジェットが漏れてはいるが速度が遅い場合は、人を起こす事柄ではなくチケットです。短いウィンドウは長いウィンドウの12分の1にする慣例に従い、severityはページであってはいけません。
ランブックのCIゲートスクリプト
/root/pca-alerting/runbook-gate.shを作成します。1つ目の引数でルールファイルのパスを受け取り、labels.severityがpageなのにannotations.runbook_urlがないアラートが1つでもあれば、その名前を出力して0以外のコードで終了し、1つもなければ0で終了します。
スクリプトは、1つ目の引数でルールファイルのパスを受け取ります。yqで、severityがpageのルールのうちrunbook_urlのアノテーションがないものを取り出し、1つでもあれば名前を出力して失敗で終わらせれば十分です。チケット等級まで止めてはいけません。