はじめに
SNMPを利用したモニタリングは昔から行われていて
MRTG Munin Cacti Zabbix などなど、いくらでもツールがありますよね。
でもなんか最近はやりのOSSなモニタリングツールで気軽に拾いたい!とか思ったので試してみようと思った次第です。
具体的には collectd, fluentd, prometheus を比べてみました。
collectd, fluentd はデータをルーティングするものなので、データストアとしてgraphite, influxdbなどを利用することを想定しています。
がその設定はとりあえずここでは関係がないので記載していません。
collectd
Pluginで対応可能です。
設定は
LoadPlugin snmp
<Plugin snmp>
<Data "dataname">
Type "tipename"
Table true
Instance "IF-MIB::ifDescr"
Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
</Data>
<Data "dataname">
Type "users"
Table false
Instance ""
Shift -1
Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
</Data>
<Host "Hostname">
Address "192.168.1.1"
Version 2
Interval 60
Community "another_string"
Collect "dataname" "dataname" "dataname"
</Host>
</Plugin>
Pluginの読み込み、
データの定義、(indexものならTable true)Instanceで指定したものがindex名として使用される
ホストの定義 (収集するデータの指定)
みたいな形です。
データ定義とホストの定義が分かれているので、設定はそこまで多く増えません。
ただ、データ定義をグルーピングしたりできない(?)ので、
ホストの Collect がすごく、長くなる可能性はあります。
fluentd
Pluginで対応可能です。
設定は
<source>
type snmp
tag snmp.hostname
host "192.168.1.1"
Community "another_string"
mib ifDescr, ifInOctets, ifOutOctets
method_type walk
polling_time 1
out_executor "/path/of/exec.rb"
</source>
<source>
type snmp
tag snmp.hostname
host "192.168.1.1"
Community "another_string"
mib "hrSystemNumUsers.0"
method_type get
</source>
ホスト名とデータの定義 をセットで行うので、
収集したいデータとホストが多くなると、source定義がどんどん増えていきます。
つらい。
何もしないと収集したデータはValue={Name=hoge,Value=fuga} のような形で届くので
exec.rb を用意して加工しないとつらいかも。
interfaceは ifDescr.ifInOctets=value, ifDescr.ifOutOctets=valueのように加工して吐き出すようにしてみました。下記
module Fluent
class SnmpInput
def out_exec manager, opts={}
manager.walk(opts[:mib]) do |row|
time = Time.now.to_i
time = time - time % 5
record = {}
data = {}
row.each do |vb|
data["name"] = vb.value.to_s if vb.name.to_s =~ /Descr/
data["InOctets"] = vb.value.to_s if vb.name.to_s =~ /InOctets/
data["OutOctets"] = vb.value.to_s if vb.name.to_s =~ /OutOctets/
end
if data.has_key?("name")
record["#{data['name']}.InOctets"] = data["InOctets"] if data.has_key?("InOctets")
record["#{data['name']}.OutOctets"] = data["OutOctets"] if data.has_key?("OutOctets")
end
if record
router.emit opts[:tag], time, record
end
end
end
end
end
また収集データタイプがカウンタだとかそういうのを気にせず値だけ拾うので、差分計算などは
別途fluentdのフィルタなどもしくはデータストア側が処理できればカウンタ値として放り込む必要があります。
Prometheus
Exporterで対応可能です。
設定は
snmp_exporterとPrometheusでそれぞれ行います。
データ定義はsnmp_exporter、ポーリング設定はPrometheusです。
specialnode:
version: 2
auth:
community: "another_string"
walk:
- 1.3.6.1.2.1.2
- 1.3.6.1.2.1.25.1.5
metrics:
- name: ifInOctets
oid: 1.3.6.1.2.1.2.2.1.10
indexes:
- labelname: ifDescr
type: Integer32
lookups:
- labelname: ifDescr
oid: 1.3.6.1.2.1.2.2.1.2
- name: ifOutOctets
oid: 1.3.6.1.2.1.2.2.1.16
indexes:
- labelname: ifDescr
type: Integer32
lookups:
- labelname: ifDescr
oid: 1.3.6.1.2.1.2.2.1.2
- name: hrSystemNumUsers
oid: 1.3.6.1.2.1.25.1.5
以上がsnmp_exporter側のデータ定義。
ここではspecialnode という名前で1つ定義しています。
この状態で、snmp_exporterを動かして
curl "http://snmp_exporterhost:9116/snmp?targer=hostname&module=specialnode"
とやると、データが拾えるのがわかります。
scrape_configs:
- job_name: 'snmp'
scrape_interval: 60s
target_groups:
- targets:
- 192.168.1.1
metrics_path: /snmp
params:
module: [specialnode]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9116
Prometheus側ではjobとして登録し、Prometheusからsnmp_exporterに定期的にデータ収集しに行きます。
Prometheusもfluentdと同様、Counterデータについて、そのままだと差分計算などを行ってくれないため、加工をする必要があります。
が、そのあたりはまだ調べていないのでどのくらい面倒なのかはわかりません。
Prometheusでの差分計算
Prometheusでの差分計算方法としては、rateという集計関数が用意されています。
上記設定にて収集すると、60秒ごとのifInOctetsなどが収集されていますので、
rate(IfInOctets[5m]) とGraphのExpressionに記載すると、5minでの差分が表示されます
また設定ファイルに
rule_files:
- prometheus.rule
と収集ルールを記載するファイルを記載し、そのファイル(prometheus.rule)に
ifInOctets_5min_rate = rate(ifInOctets[5m])
と記載すると、ifInOctets_5min_rate
という名称で5分の差分値が保存されます。
rateの計算には2個のデータが必要になりますので、1minの差分値を計算しようと思うと、scrape_interval = 30s
とするなど、何らかの手当てが必要です。
ifInbps_5min_average = rate(ifInOctets[5m])*8/300
このようにbps計算させることもできます。
おわりに
SNMPを利用したモニタリングに必要な設定の差を確認しました。
設定ファイルの記述の面倒くささという意味ではfluentd単体ではこの用途に使うのはなんだかなぁ?という感じがしました。
どのみちそんなのジェネレータ作るから一緒でしょ?と言われればそれまでですが。