Prometheus SNMP ExporterでSNMP WalkのデータをSplunkに送る
はじめに
ネットワーク機器の監視はいまだにSNMPが主流ですよね。
CiscoなどがTelemetryを頑張っているようですが複数の種類が混在する環境ではSNMPに頼らざるを得ないです。
Splunkでも同じくネットワーク機器の状況を分析するにはSNMPが主要な選択肢の一つになります。
※その他にもマネージャーがあればAPIで取れる場合もあります
※ネットワーク通信の分析にはNetflowやStream(パケットキャプチャ)がいいです
じゃあSNMP取ろうかとなると、いくつか選択肢が考えられます。
-
snmpwalkをホスト上で実行ファイル出力し結果をUnivesal Forwarderで送信する
シンプルではありますが、ある程度のスクリプト開発が必要、イベントとして入ってきてしまう、IF名が個別に得られるので結合するのに手間がかかる、と言った懸念点はあります。
台数が多くなる場合のスケーラビリティも注意が必要です。 -
Splunk Connect for SNMPを使う
https://splunk.github.io/splunk-connect-for-snmp/main/
非常に高機能でsnmpwalkを実行したりSNMP Trapを受信もできます。
1で見られたようイベントではなくメトリクスとして送信され、またIF名も自動的に結合されます。MIBも数千種類登録されています。
そして、これはなんとKubernetes (microk8s) 上で動作します。
そのためにスケーラビリティは問題ないのですが、いかんせんKubernetesの運用知識が必要というハードルもあります。
(Docker Compose版もβ版で開発中のようではあります) -
既存の監視ツールから取得
ZabbixとかPRTGとか、いい感じにエクスポートできるものがあれば。 -
Prometheus SNMP Exporterを使う
今回のお話です。
Prometheus SNMP Exporterはsnmpwalkを実行できるPrometheus Exporterの一種です。
ある程度高機能で、メトリクスとして取り込め、IF名も結合されます。拡張MIBはセルフで登録できます。
Prometheus本体を用意せずともこのSNMP ExporterがあればSplunkにデータ送信することができます。
本記事ではその方法を見ていこうと思います。
Prometheus SNMP Exporter
インストール
Docker Imageを利用するか、パッケージを利用します。
バイナリを使用する場合はsystemdで自動起動するようにしておきましょう。
パッケージを使う場合のコマンドはこちらです(Ubuntuの例)。
# パッケージの取得と展開
wget https://github.com/prometheus/snmp_exporter/releases/download/v0.26.0/snmp_exporter-0.26.0.linux-amd64.tar.gz
sudo tar xvzf snmp_exporter-0.26.0.linux-amd64.tar.gz -C /opt/
sudo mv /opt/snmp_exporter-0.26.0.linux-amd64 /opt/snmp_exporter
# prometheusユーザー作成(割愛可)
sudo useradd prometheus
sudo passwd prometheus
# systemd登録 Userは適宜置き換え
sudo tee /etc/systemd/system/snmp-exporter.service > /dev/null <<EOF
[Unit]
Description=SNMP Exporter
After=network-online.target
# This assumes you are running snmp_exporter under the user "prometheus"
[Service]
User=prometheus
Restart=on-failure
ExecStart=/opt/snmp_exporter/snmp_exporter --config.file=/opt/snmp_exporter/snmp.yml
[Install]
WantedBy=multi-user.target
EOF
# 起動
sudo systemctl daemon-reload
sudo systemctl enable snmp-exporter
sudo systemctl start snmp-exporter
# 起動確認
curl localhost:9116/metrics
Generator
次は設定ファイルを作成します。
SNMP Exporterの設定(snmp.yml)自体は非常に長大で複雑です(サンプル)。
たぶん人間が作れる代物ではないので、generatorが用意されています。
Goでのビルドが必要なのでGoが入っていない場合は入れておきます。
wget https://golang.org/dl/go1.22.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
手順通りビルドします。
# Debian-based distributions.
sudo apt-get install unzip build-essential libsnmp-dev # Debian-based distros
# Redhat-based distributions.
sudo yum install gcc make net-snmp net-snmp-utils net-snmp-libs net-snmp-devel # RHEL-based distros
git clone https://github.com/prometheus/snmp_exporter.git
cd snmp_exporter/generator
make generator mibs
次にビルドされたディレクトリにgenerator.ymlを作成します。
見ればだいたい分かると思いますが、auths
で認証情報、modules
でsnmpwalk対象を指定します。
lookups
でifIndexに対してIF名を付与することができます。
(Generatorのページに詳細情報があります)
このように定義を作っておいて、後で取得先デバイスに対して任意に割り当てられます。
auths:
general_2c_auth:
version: 2
community: public
modules:
general_2c_module:
walk:
- sysName
- sysUpTime
- sysDescr
- sysLocation
# IF-MIB系を全部取るなら
# - ifTable
# - ifXTable
- ifNumber
- ifIndex
- ifDescr
- ifAlias
- ifAdminStatus
- ifOperStatus
- ifMtu
- ifSpeed
- ifPhysAddress
- ifInNUcastPkts
- ifOutNUcastPkts
- ifHCInOctets
- ifHCOutOctets
- ifHCInUcastPkts
- ifHCOutUcastPkts
- ifHCInMulticastPkts
- ifHCOutMulticastPkts
- ifHCInBroadcastPkts
- ifHCOutBroadcastPkts
- ifInDiscards
- ifOutDiscards
- ifInErrors
- ifOutErrors
- ifInUnknownProtos
lookups:
- source_indexes: [ifIndex]
lookup: ifAlias
- source_indexes: [ifIndex]
lookup: ifDescr
- source_indexes: [ifIndex]
lookup: ifName
- source_indexes: [ifIndex]
lookup: ifPhysAddress
overrides:
ifAlias:
ignore: true # Lookup metric
ifDescr:
ignore: true # Lookup metric
ifName:
ignore: true # Lookup metric
ifPhysAddress:
ignore: true # Lookup metric
ifType:
type: EnumAsInfo
max_repetitions: 25
retries: 3
timeout: 10s
snmp.ymlを生成します。
make generate
生成したsnmp.ymlをSNMP Exporterのディレクトリに移動します。
sudo cp ./snmp.yml /opt/snmp_exporter/snmp.yml
SNMP Exporterを再起動します。念のためステータスも確認しておきましょう。
sudo systemctl restart snmp-exporter
sudo systemctl status snmp-exporter
最後に実験です。Scrapeしてみます。
(実験できる機器がなければsnmpdをインストールしてtarget=localhostしてください)
curl "http://localhost:9116/snmp?module=general_2c_module&auth=general_2c_auth&target=<IP Address>"
結果例です。
# HELP ifAdminStatus The desired state of the interface - 1.3.6.1.2.1.2.2.1.7
# TYPE ifAdminStatus gauge
ifAdminStatus{ifAlias="",ifDescr="Amazon.com, Inc. Elastic Network Adapter (ENA)",ifIndex="2",ifName="ens5"} 1
ifAdminStatus{ifAlias="",ifDescr="lo",ifIndex="1",ifName="lo"} 1
# HELP ifHCInBroadcastPkts The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were addressed to a broadcast address at this sub-layer - 1.3.6.1.2.1.31.1.1.1.9
<以下省略>
いいですね。
今後定義を変更したい場合も同じように generator.yml変更⇒make generate⇒snmp.ymlコピー⇒snmp-exporter再起動 でOKです。
拡張MIB
拡張MIBに含まれるMIBオブジェクトやOIDを指定し、makeしようとするとOIDが見つからないというエラーが出ます。
caller=main.go:139 level=error msg="Error generating config netsnmp" err="cannot find oid '1.2.3.4.5' to walk"
その際はgenerator/mibs/
に拡張MIBのファイルを置いてあげると反映されます。
それではSplunkにデータを送信してみましょうか。
OpenTelemetry Collector
Prometheus ExporterのScrape結果をSplunkに送信するためにOpenTelemetry Collector(以下、OTel Collector)を使用します。
細かい話はこちら。
本家のOTel Collectorでもいいですが、せっかくなのでSplunk Distribution of OTel Collectorを使います。
Splunk Core (Enterprise / Cloud)へ送る方法とSplunk Observability CloudのInfrastructure Monitoringに送信する方法をそれぞれ見ていきます。
※SplunkならUFとかHFで取れないの?と思われたと思います。
私も思いました。
実際こんなのがあります。
Prometheus Metrics for Splunk
しかし、これはデバイスを1スタンザごとに登録しなければならず、対象が1,000台とかになると破綻するなと思い辞めました。
Splunk Core (Enterprise / Cloud) の場合
事前準備
以下を用意しておいてください。
- MetricタイプのIndex
- HECトークン
OTel Collectorインストール
OTel Collectorをインストールする訳ですが通常はインストールスクリプトが用意されています。
しかし、これはインストールする際にSplunk Observability Cloudへのトークン照会が行われます。今回は照会ができないのでマニュアルインストール方法を取ります。
手順通り、まずはパッケージでインストールします。
インストール先はSNMP Exporterが動いているホストで良いでしょう。
curl -sSL https://splunk.jfrog.io/splunk/otel-collector-deb/splunk-B3CD4420.gpg > /etc/apt/trusted.gpg.d/splunk.gpg
echo 'deb https://splunk.jfrog.io/splunk/otel-collector-deb release main' > /etc/apt/sources.list.d/splunk-otel-collector.list
apt-get update
apt-get install -y splunk-otel-collector
次にHECトークン周りの設定をします。
設定ファイルをコピーして
sudo cp /etc/otel/collector/splunk-otel-collector.conf.example /etc/otel/collector/splunk-otel-collector.conf
/etc/otel/collector/splunk-otel-collector.conf
を以下のように設定します。
SPLUNK_HEC_URL=https://<Splunk Enterprise or Cloudのホスト名>:<Entepriseは8088、Cloudは443>/services/collector
SPLUNK_HEC_TOKEN=<HECトークン>
次に/etc/otel/collector/agent_config.yaml
を以下のように追加します。
scrape_intervalやtarget、paramなどは適宜変更してください。
また、service.pipelinesは不要な設定は削除してしましょう。
receivers:
prometheus/general_demo:
config:
scrape_configs:
- job_name: 'snmp'
scrape_interval: 300s
static_configs:
- targets:
- <デバイスのIPアドレス1>
- <デバイスのIPアドレス2>
metrics_path: /snmp
params:
auth: [general_2c_auth]
module: [general_2c_module]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9116
exporters:
splunk_hec/prometheus:
token: "${SPLUNK_HEC_TOKEN}"
endpoint: "${SPLUNK_HEC_URL}"
source: "snmp-exporter"
sourcetype: "prometheus:metrics"
# 適宜変更
index: "prometheus"
profiling_data_enabled: false
tls:
# Splunk Enterpriseで自己署名証明書の場合
insecure_skip_verify: true
service:
pipelines:
metrics/prometheus:
receivers: [prometheus/general_demo]
processors:
- memory_limiter
- batch
- resourcedetection
exporters: [splunk_hec/prometheus]
最後にOTel Collectorを再起動します。
sudo systemctl restart splunk-otel-collector
sudo systemctl status splunk-otel-collector
データを眺める
| mpreview index=prometheus
メトリクスとして取得できました。
ifIndexに紐づくifNameもDimensionとして追加されています。
メトリクスではなくテキストで得られるMIB(sysDescrなど)はMetric value自体は1で、Dimensionとして得られるようです。
SNMPのデータが特殊なのは大抵が累積値であることです。
例えばifHCInOctetsは取得した時点のそれまでの累積値なので、そのままでは使えません。
そのため差分を計算し取得間隔の秒数で割る必要があります。
SPLは便利なことに、そのためのコマンドrate_avgが用意されています。
| mstats rate_avg(ifHCInOctets) where index=prometheus service.instance.id="127.0.0.1" by ifName span=1m
| rename rate_avg(*) as *
| timechart avg(ifHCInOctets) span=1m by ifName
いい感じですね。
複数のメトリクスを組み合わせることもできます。
IFの使用率:
| mstats rate_avg(ifHCInOctets) rate_avg(ifHCOutOctets) max(ifSpeed) where index=prometheus service.instance.id="127.0.0.1" by ifName span=1m
| rename rate_avg(*) as *
| eval IO=ifHCInOctets+ifHCOutOctets, ifUtil=100*8*IO/ifSpeed
| fields _time, ifName, ifUtil
| where isnotnull(ifUtil)
| timechart avg(ifUtil) as ifUtil by ifName span=1m
破棄率
| mstats rate_avg(ifInDiscards) rate_avg(ifOutDiscards)
rate_avg(ifInErrors) rate_avg(ifOutErrors)
rate_avg(ifHCInUcastPkts) rate_avg(ifHCOutUcastPkts)
rate_avg(ifHCInBroadcastPkts) rate_avg(ifHCOutBroadcastPkts)
rate_avg(ifHCInMulticastPkts) rate_avg(ifHCOutMulticastPkts)
rate_avg(ifInUnknownProtos)
where index=prometheus service.instance.id="127.0.0.1" by ifName span=1m
| rename rate_avg(*) as *
| eval TotalDiscards=ifInDiscards+ifOutDiscards
| eval TotalPackets=ifInDiscards+ifOutDiscards+ifInErrors+ifOutErrors+ifHCInUcastPkts+ifHCOutUcastPkts+ifHCInBroadcastPkts+ifHCOutBroadcastPkts+ifHCInMulticastPkts++ifHCOutMulticastPkts+ifInUnknownProtos
| eval DiscardRate=100*TotalDiscards/TotalPackets
| fields _time, ifName, DiscardRate
| where isnotnull(DiscardRate)
| timechart avg(DiscardRate) as DiscardRate by ifName span=1m
Splunk Observability Cloud Infrastructure Monitoring (IM) の場合
事前準備
以下を用意しておいてください。
- Ingest Access Token
OTel Collectorインストール
OTel Collectorをスクリプトでインストールします。
インストール先はSNMP Exporterが動いているホストで良いでしょう。
curl -sSL https://dl.signalfx.com/splunk-otel-collector.sh > /tmp/splunk-otel-collector.sh;
sudo sh /tmp/splunk-otel-collector.sh --realm $SPLUNK_REALM --memory $SPLUNK_MEMORY_TOTAL_MIB -- $SPLUNK_ACCESS_TOKEN
次に/etc/otel/collector/agent_config.yaml
を以下のように追加します。
scrape_intervalやtarget、paramなどは適宜変更してください。
receivers:
prometheus/general_demo:
config:
scrape_configs:
- job_name: 'snmp'
scrape_interval: 300s
static_configs:
- targets:
- <デバイスのIPアドレス1>
- <デバイスのIPアドレス2>
metrics_path: /snmp
params:
auth: [general_2c_auth]
module: [general_2c_module]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9116
service:
pipelines:
metrics/prometheus:
receivers: [prometheus/general_demo]
processors:
- memory_limiter
- batch
- resourcedetection
exporters: [signalfx]
最後にOTel Collectorを再起動します。
sudo systemctl restart splunk-otel-collector
sudo systemctl status splunk-otel-collector
データを眺める
Metric Finderでsnmp
とサーチするとちゃんと取れていました。
累積値で得られるデータから差分を取るにはRollupをRate/sec rollup
にするだけでOKです。
差分を計算し取得間隔の秒数で割ってくれます。
複数のデータに基づいて計算もできます。
破棄率を計算しています。
ぽちぽち入れるのが面倒な場合はSignalFlowでコードとして記述もできます。
A = data('ifInDiscards', rollup='rate').publish(label='A', enable=False)
B = data('ifOutDiscards', rollup='rate').publish(label='B', enable=False)
C = data('ifInErrors', rollup='rate').publish(label='C', enable=False)
D = data('ifOutErrors', rollup='rate').publish(label='D', enable=False)
E = data('ifHCInUcastPkts', rollup='rate').publish(label='E', enable=False)
F = data('ifHCOutUcastPkts', rollup='rate').publish(label='F', enable=False)
G = data('ifHCInBroadcastPkts', rollup='rate').publish(label='G', enable=False)
H = data('ifHCOutBroadcastPkts', rollup='rate').publish(label='H', enable=False)
I = data('ifHCInMulticastPkts', rollup='rate').publish(label='I', enable=False)
J = data('ifHCOutMulticastPkts', rollup='rate').publish(label='J', enable=False)
K = data('ifInUnknownProtos', rollup='rate').publish(label='K', enable=False)
L = (A+B).publish(label='L', enable=False)
M = (A+B+C+D+E+F+G+H+I+K).publish(label='M', enable=False)
N = (100*L/M).publish(label='N')
その他
スケーラビリティは?
A single instance of snmp_exporter can be run for thousands of devices.
だそうです。
まとめ
SNMPデータを取得する一つの方法としてPrometheus SNMP Exporterとの連携についてまとめました。
Discussion