Prometheus Alertmanager SilencesとInhibition Rules:本番環境のアラートノイズを削減する

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

背景:アラートが実際の障害より多い問題

アラート疲労は、監視環境を初めて構築したときに実際に経験した問題です。閾値を10回以上調整した後、問題は閾値にあるのではなく、Alertmanagerの設定方法にあることに気づきました。障害が発生するたびに、CPU高負荷、メモリ高負荷、レスポンスタイム上昇、ヘルスチェック失敗といった数十件のアラートが一斉に届きます——すべて同じ1つの原因から発生しているにもかかわらず。数週間後には、チーム全員がSlackの監視チャンネルを無視するようになっていました。

実はAlertmanagerには、この問題をまさに解決するための2つの機能が用意されています:

  • Silences:ダウンタイムが予定されているときやメンテナンス中に、特定のアラートグループを指定した期間だけ一時的に無効化する
  • Inhibition Rules:メインアラートが発火した際に、関連する二次アラートを自動的に抑制する——根本原因のアラートが発火している間は、症状アラートを削減する

この記事では、この2つの機能を直接取り上げます。すでにAlertmanagerが基本的なreceiverの設定で動作していることを前提とします。

amtoolのインストール — Alertmanager CLIツール

amtoolはAlertmanagerのインストールパッケージに同梱されており、ターミナルから操作するための主要なツールです。まだインストールしていない場合:

# Alertmanagerをダウンロード(amtoolはパッケージに含まれています)
wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz
tar xvf alertmanager-0.27.0.linux-amd64.tar.gz
sudo mv alertmanager-0.27.0.linux-amd64/amtool /usr/local/bin/

# amtoolのデフォルト設定ファイルを作成(毎回URLを入力しなくて済む)
mkdir -p ~/.config/amtool
cat > ~/.config/amtool/config.yml <<EOF
alerting.url: http://localhost:9093
EOF

# 接続確認
amtool alert query

詳細設定

Silences — 意図的なアラートの停止

最もシンプルな方法は、http://your-server:9093のUI、Silences タブ → New Silence から行う方法です。ただし実際には、スクリプトに統合できることからamtoolをより多く使っています。

# webサービスの全アラートを2時間サイレンス
amtool silence add \
  --duration=2h \
  --comment="Deploy v2.1.0 — expected restart" \
  alertname=~".+" \
  service="web"

# アクティブなサイレンス一覧を表示
amtool silence query

# デプロイが予定より早く完了した場合、即座にサイレンスを終了
amtool silence expire <silence-id>

現在はamtoolをCI/CDパイプラインに統合しています。各デプロイ前に、スクリプトが自動的に30分間のサイレンスを作成します。ヘルスチェックが通過した後、即座に終了させることで、リリースのたびに発生する数十件の誤検知アラートを防いでいます:

#!/bin/bash
# deploy-with-silence.sh

SILENCE_ID=$(amtool silence add \
  --duration=30m \
  --comment="CI/CD deploy $(git rev-parse --short HEAD)" \
  environment="production" \
  service="api" \
  --output=json | jq -r '.silenceID')

echo "Silence created: $SILENCE_ID"

# デプロイを実行
./deploy.sh

# ヘルスチェック通過後、サイレンスを終了
amtool silence expire "$SILENCE_ID"
echo "Silence expired"

重要な注意点:サイレンスを作成する際は必ずcommentフィールドを入力してください。2週間後には、なぜそのサイレンスが存在するのか自分でも覚えていませんし、チームの他のメンバーはなおさらわかりません。

Inhibition Rules — 二次アラートを自動的にブロックするロジック

この機能は、アラートノイズの根本的な問題を実際に解決できるにもかかわらず、思った以上に見過ごされています。原理はシンプルです:アラートAがアクティブな場合、指定されたラベルが一致するすべてのアラートBを自動的にブロックします。

最も典型的な例:ノードがダウンすると、そのノード上のすべてのサービスも当然ダウンします。20件の個別アラートを受け取る必要はありません——NodeDownアラート1件で、何をすべきかわかります。

/etc/alertmanager/alertmanager.ymlファイルに追加します:

inhibit_rules:
  # ノードダウン時、そのノードからのwarning/critical severity全アラートをブロック
  - source_matchers:
      - alertname = "NodeDown"
    target_matchers:
      - severity =~ "warning|critical"
    equal:
      - instance

  # criticalアラートが同一サービスのwarningアラートをブロック(criticalが発火中のwarningスパムを防ぐ)
  - source_matchers:
      - severity = "critical"
    target_matchers:
      - severity = "warning"
    equal:
      - alertname
      - namespace
      - service

  # データベースダウンがアプリケーションエラーアラートをブロック(根本原因が明らかな場合に症状をブロック)
  - source_matchers:
      - alertname = "DatabaseDown"
      - severity = "critical"
    target_matchers:
      - alertname =~ "HighErrorRate|SlowResponse|ServiceUnavailable"
    equal:
      - environment

各フィールドの説明:

  • source_matchers:「親」アラートの条件——inhibitionを引き起こすアラート
  • target_matchers:ブロック対象のアラートの条件
  • equal:sourceとtarget間で同じ値を持つ必要があるラベル——Alertmanagerが2つのアラートが同じインスタンス/サービスに属すると判断するための仕組み

Kubernetesクラスター向けの本番設定例

以下は、Kubernetesマルチクラスター環境で実際に運用している設定です:

inhibit_rules:
  # クラスターネットワーク分断がノードレベルのアラートをブロック
  - source_matchers:
      - alertname = "ClusterNetworkPartition"
    target_matchers:
      - alertname =~ "NodeDown|NodeUnreachable"
    equal:
      - cluster

  # ノード未準備状態がそのノード上のPodアラートをブロック
  - source_matchers:
      - alertname = "KubeNodeNotReady"
    target_matchers:
      - alertname =~ "KubePodCrashLooping|KubePodNotReady|KubeDeploymentReplicasMismatch"
    equal:
      - node
      - cluster

  # PVCフル状態がアプリケーション書き込みエラーをブロック(ストレージが根本原因の場合に症状をブロック)
  - source_matchers:
      - alertname = "KubePersistentVolumeFillingUp"
      - severity = "critical"
    target_matchers:
      - alertname = "AppWriteError"
    equal:
      - namespace
      - persistentvolumeclaim

もう1つよく使うトリック:手動でサイレンスを作成する代わりに、「メンテナンスウィンドウアラート」を定義して自動的にinhibitする方法です。具体的には、MaintenanceWindowという名前のPrometheus recording ruleenvironment="production"ラベルを付け、メンテナンス時間帯だけアクティブになるように定義します。その後、inhibition ruleが自動的にその期間中のすべてのwarning/infoアラートをブロックするため、手動で操作する必要がありません。

確認とモニタリング

Inhibition Rulesが正しく動作していることの確認

# アクティブな全アラートを表示
amtool alert query

# inhibitされたアラートとサイレンスされたアラートも含めて表示
amtool alert query --silenced --inhibited

# 特定のラベルでフィルタリング
amtool alert query severity=critical environment=production

# リロード前に設定ファイルを検証
amtool check-config /etc/alertmanager/alertmanager.yml

アラートが意図せずブロックされている場合は、APIを直接使用してデバッグします:

# inhibit理由を含めてアラートを表示
curl -s 'http://localhost:9093/api/v2/alerts?inhibited=true&silenced=true' | \
  jq '.[] | {alertname: .labels.alertname, state: .status.state, inhibitedBy: .status.inhibitedBy}'

有効性を追跡するAlertmanagerメトリクス

Alertmanager自体のメトリクスをスクレイプします——PrometheusがAlertmanagerを自己監視するための最速の方法です:

# prometheus.yml
scrape_configs:
  - job_name: 'alertmanager'
    static_configs:
      - targets: ['localhost:9093']

最も役立つメトリクス:

  • alertmanager_alerts{state="active"} — アクティブなアラート数
  • alertmanager_alerts{state="suppressed"} — 抑制されたアラート数(inhibitとsilenceの合計)
  • alertmanager_silences{state="active"} — アクティブなサイレンス数
  • alertmanager_notifications_total — 送信した通知の合計数
  • alertmanager_notifications_failed_total — 失敗した通知数

Grafanaで抑制率を監視するクエリ:

# 全アラートに対する抑制されたアラートの割合
alertmanager_alerts{state="suppressed"} / ignoring(state) sum without(state)(alertmanager_alerts)

inhibition rulesを追加した後にこの割合が上昇すれば、それは良い兆候です。チームへの通知数は減りますが、受け取るアラートにはすべて確認する価値があります。

実運用から得た注意点

設定を何度も修正した経験から得た知見:

  • equalフィールドはsourceとtargetの両方に存在する必要がある——どちらか一方のアラートにそのラベルがない場合、ルールはマッチせず、inhibitionは機能しません。初回のデバッグ時にかなりの時間を費やした問題です。
  • inhibitの範囲を広げすぎない——sourceアラートの症状として明らかなアラートだけをブロックし、同じ環境からのすべてのアラートをブロックしないようにする。
  • 設定のリロードに再起動は不要curl -X POST http://localhost:9093/-/reloadで十分。
  • Silenceは長期的な解決策ではない——同じアラートに対して頻繁にサイレンスを作成する必要がある場合、閾値の設定が間違っているか、inhibition ruleを追加すべきサインです。

基本的なAlertmanagerがすでに動作しているなら、inhibition rulesの追加は約30分で完了します。システムによっては、1日あたりの通知数が50〜70%削減されることもあります。さらに重要なのは:すべてのアラートに本当の意味があるため、チームが再び注意を払うようになる点です。

Share: