はじめに
ネットワーク運用において、スイッチやルーターなどの機器が正常に稼働しているかを把握することは非常に重要です。特に、大規模ネットワークでは、あるスイッチが何らかの理由で障害を起こしても気づかないまま放置されるリスクがあります。
そこで、本記事では SNMP Trap を利用した「スイッチの生存確認」システム を構築する方法を紹介します。各スイッチから定期的に Trap を送信させ、Elasticsearch の Transform 機能で最新受信時刻を集約、さらに Kibana の Alert で「一定時間 Trap が届かないスイッチ」を検知する仕組みです。
これにより、スイッチが止まった瞬間をほぼリアルタイムで把握でき、迅速な対応が可能になります。ブログでは設定例や運用上のポイントも合わせて解説していきます。
仕組み
まずはこの絵のようにSNMP TrapをLogstashで受けて、Elasticsearchへ送ります。各スイッチは一定間隔(今回は1分)でTrapを送信します。

ElasticsearchにはTrapのデータが大量に送られてきますので、それをTransformという機能で整形します。
ポイントは各スイッチ毎に最後にTrapを送ってきたものだけ抽出するということです。
スイッチが4台あれば4件だけ表示されるというわけです。

ここでswitch-1が12:57:00を最後にTrapの送信をしてこなくなったとします。
するとTransformされたテーブルはこのようになります。

switch-1だけ時間が古くなるので、検索のときに現在時刻から数分古いものだけ見つけるクエリ文を使うと、switch-1だけが抜き出されて、switch-1が3分以上送ってきていないことがわかります。
送ってこないだけでは故障したとはなりませんが、調査を行うきっかけにはなると思います。
準備
実際にスイッチを用意するのは大変なので、擬似的にTrapを出します。
コンテナで好きな台数のスイッチからTrapを送れるようにします。
- Elastic
- Elastic CloudやStart Localなどを利用します
- 今回の記事ではElastic CloudのServerless (Observability)を利用しています
- Elastic Cloud
- Start Local
- コンテナ
- docker composeが動く状態
- 今回の記事の環境
- Mac OS 26.1
- Docker 28.5.2
- Docker Compose v2.40.3-desktop.1
手順
設定
必要な設定を入れていきます
リポジトリ
まずリポジトリをCloneします
git clone https://github.com/legacyworld/snmp-trap-monitor-demo
作成されたディレクトリに移動します
cd snmp-trap-monitor-demo
Elastic設定
次にlogstash.confにElastic Cloudの情報を入れます。まず以下のコマンドでコピーします
cp ./logstash/pipeline/logstash.conf.sample ./logstash/pipeline/logstash.conf
入力するのは以下のoutputのcloud_idとapi_keyです。
output {
elasticsearch {
cloud_id => "<cloud id>"
api_key => "<api key>"
data_stream => "true"
data_stream_type => "logs"
data_stream_dataset => "snmp_test"
data_stream_namespace => "default"
}
stdout { codec => rubydebug }
}
-
cloud_id
-
api_key
スイッチ台数
generate.shの以下の部分で台数を変更します
SWITCH_COUNT=10
データ投入
以下の手順です
-
docker-compose.yml作成。これは疑似スイッチの台数によってdocker-compose.ymlの記載が変わるからです -
docker compose up -dで起動すると、自動的にデータ送信が始まります
docker-compose.yml作成
generate.shを実行します
./generate.sh
docker-compose.ymlの構成
-
setup-mibs- Logstashで使うMIBファイルをダウンロードします。これはLogstashコンテナでインストールなどが出来ないからです
-
logstash- SNMP Trapを受信してElasticsearchに送信します
-
switch-??- 疑似ネットワークスイッチで、
SWITCH_COUNTで設定した数だけ記載されているはずです
- 疑似ネットワークスイッチで、
起動
以下コマンドでビルドと起動が行われます
docker compose up -d
データ確認
Discoverに行って、右上にあるTry ES|QLをクリックします。

FROM logs-snmp*
データ加工
では、このデータをTransformを利用して加工してそれぞれのスイッチが最後にアクセスしてきた時間を別のインデックスに保存します
メニュー左下のデータベースアイコンをクリックしてTransformsのページに移動

Create your first transformをクリック

以下のように入力して右下のSave data view to Kibanaをクリック
- Name
- logs-snmp
- Index pattern
- logs-snmp*
少しスクロールダウンして以下のように選択して、右下のNextをクリック
- Unique keys
host.ip
- Sort field
@timestamp
少しスクロールダウンしてTransform details部分で以下のように選択して、右下のNextをクリック
- Transform ID
snmp-transform
-
Continuous modeをONにする- デフォルトでは一回しか実行されないので、継続的に実行するようにする
- Delay
- 0sにする
- データが大きい場合は新しいデータがまだ検索可能な状態になっていない場合もありますが、今回は特に考慮する必要ないです
- https://www.elastic.co/docs/explore-analyze/transforms/transform-usage
最後に一番右下にあるDiscoverをクリックするとDiscoverに移動します

以下のように表示されます。Documentが10個になっているのがわかります。各スイッチから最後に送られてきたSNMP Trapだけが表示されています。

フィールドを絞って見やすくしましょう。host.ipフィールドの上にポインタを持っていくと右側に+が出てきます。それをクリックするとフィールドとして表示されます。同様にiso.org.dod.internet.private.enterprises.8072.2.3.2.2もフィールドとして追加します。

スイッチ故障シミュレーション
ではスイッチを故障させてSNMP Trapを送れないようにします。
このコマンドを実行します
docker compose stop switch-11
これでswitch-11がTrapを送ってこなくなります。1分に一回送る設定になっているので、しばし待ってからDiscoverの画面をリフレッシュします
switch-11(host.ip:172.25.0.11)だけ時間が古くなっています
switch-11 => 13:00:41が最後
それ以外 => 13:03付近が最後

アラートを作る
少しスクロールダウンしてElasticsearch queryをクリック

ES|QLに以下を入力
FROM snmp-transform
| WHERE @timestamp <= NOW() - 3 minute
| KEEP @timestamp, host.ip, `iso.org.dod.internet.private.enterprises.8072.2.3.2.2`
Test queryをクリックすると試すことが出来ますが、switch-11を止めたのがだいぶ前だと何も表示されない可能性が高いです。
Set the time windowはデフォルトで5分になってますが、これは検索範囲が5分前までになっているので、スイッチを10分前に落としていたら検索対象に入らないわけです。

そんな場合はSet the time windowを長くしても良いですが、Alertが出続けることになるので、switch-11をもう一度立ち上げてから落としましょう
docker compose up -d
で立ち上げてから数分待ち、再度
docker compose stop switch-11
一旦Actionは飛ばしてDetailsで名前だけ入力して右下のCreate ruleをクリックして保存します

ではスイッチを回復させましょう
docker compose up -d
メールで通知する
ずっとKibanaを眺めていられないので当然メールやSlackなどの手段で通知が必要です
この通知機能はPlatinum以上のライセンスが必要です
スクロールダウンしてActionsにあるAdd actionをクリック

送付先のメールアドレスと題名を適当に入力します。
Messageには以下のように入力します。
{{#context.hits}} - {{_source.@timestamp}} {{_source.host.ip}} {{_source.iso.org.dod.internet.private.enterprises.8072.2.3.2.2}}
{{/context.hits}}
これはmustacheという記法です。
_sourceには以下のQueryの結果が入っています。
FROM snmp-transform
| WHERE @timestamp <= NOW() - 3 minute
| KEEP @timestamp, host.ip, `iso.org.dod.internet.private.enterprises.8072.2.3.2.2`
なので、それをメール本文に出力します。
{{#context.hits}} は複数スイッチが同時に障害が発生した際にループで全てを記載する部分です(要はForループ)

最後に一番下までスクロールダウンして右下のSave ruleをクリック

では複数スイッチを止めましょう
docker compose stop switch-13 switch-12
まとめ
本記事では、実機スイッチを用意せずにコンテナだけで SNMP Trap ベースの「スイッチの生存確認」仕組みを構築する方法を紹介しました。
やったことを整理すると:
-
疑似スイッチコンテナで任意台数の SNMP Trap を定期送信
-
Logstash で Trap を受信し、Elastic Cloud / Start Local 上の Elasticsearch に Data stream として格納
-
Transform で
- スイッチごとの「最後に Trap を受信した時刻」だけを抽出
- 継続実行(Continuous mode)して、ほぼリアルタイムで更新
-
Kibana の Alert で
- 「一定時間 Trap が届いていないスイッチ」を ES|QL で条件判定
- Kibana の画面上で Active / Recovered の状態を確認
-
さらに Action を追加して
- メール通知(Elastic Cloud の SMTP) で障害検知を自動連絡
- Mustache を使って、影響を受けているスイッチ一覧を本文に整形
この仕組みを入れておくと、
-
スイッチが「生きていること」を前提にするのではなく
「定期的に生存信号(Trap)が来ていること」を前提に監視できる -
通信経路のどこかで問題が起きた場合も、
「最後に Trap が来た時間」から 問題発生のおおよそのタイミングを特定 しやすい
実際のネットワーク機器に置き換える際は、Trap の送信間隔や、Transform / Alert 側のしきい値(NOW() - 3 minute の部分)を、運用ポリシーや許容ダウンタイムに合わせて調整してください。
「とりあえず ping が通っているか」ではなく、
「いつから応答が止まっているか」「どのスイッチが沈黙しているか」を、Elasticsearch と Kibana で見える化する ——
その一つの実装例として、本記事の内容が参考になれば幸いです。


















