実践Python:ネットワーク機器SNMPデータ収集と分析自動化
はじめに:Pythonでネットワーク機器のSNMPデータを活用する
システムエンジニアやインフラエンジニアとして、Pythonを用いたインフラ自動化に取り組まれている方も多いことと思います。アプリケーション開発やクラウドインフラの自動化は得意とされている一方で、ネットワーク機器の直接的な操作や、SNMPといったプロトコルについては、まだ馴染みが薄いと感じているかもしれません。
しかし、ネットワーク機器から得られるSNMPデータは、機器のパフォーマンス監視、リソース利用率の把握、障害の早期検知など、システムの安定稼働に不可欠な情報源となります。これらのデータを自動的に収集し、分析・活用することは、運用効率の向上や、プロアクティブな障害対応につながります。
この記事では、Pythonのライブラリを使用してネットワーク機器のSNMPデータを収集し、さらに一歩進んで、収集したデータを自動的に分析・活用するための具体的な手法とスクリプト例をご紹介します。ネットワーク機器に関する深い知識がなくても、Pythonスキルを活かしてネットワーク監視・分析を自動化する方法を習得いただけます。
SNMPとは何か?基本を押さえる
SNMP(Simple Network Management Protocol)は、ネットワーク上の機器(ルーター、スイッチ、サーバーなど)の情報を収集し、管理するための標準的なプロトコルです。SNMPでは、主に以下の要素が登場します。
- マネージャー (Manager): ネットワークを管理する側のシステム(Pythonスクリプトを実行するサーバーなど)。エージェントに対して情報の要求や設定変更を行います。
- エージェント (Agent): 管理される側の機器(ネットワーク機器など)上で動作するソフトウェア。マネージャーからの要求に応じて情報を提供したり、特定のイベント発生時に通知(Trap/Inform)を送ったりします。
- MIB (Management Information Base): エージェントが管理する情報の構造を定義したデータベースです。機器の種類やベンダーごとに様々なMIBが存在します。
- OID (Object Identifier): MIBツリー内の特定の情報項目(例: CPU使用率、インターフェースの送受信バイト数など)を一意に識別するための数値列です。
PythonからSNMPを利用する場合、Pythonスクリプトがマネージャーとなり、ネットワーク機器上のエージェントからMIBに定義された情報をOID指定で取得(GET/GETNEXT/WALK操作)するのが一般的です。
PythonでSNMPデータを収集する主要ライブラリ
PythonでSNMPを扱うためのライブラリはいくつか存在しますが、特によく使われるものに pysnmp
があります。pysnmp
はPythonで書かれており、SNMPv1, v2c, v3に対応し、マネージャーとしてもエージェントとしても機能できる高機能なライブラリです。
この記事では、pysnmp
を使用したデータ収集に焦点を当てます。
まず、pysnmp
ライブラリをインストールします。
pip install pysnmp
pysnmpを使ったSNMPデータ収集スクリプト例
ここでは、pysnmp
を用いてネットワーク機器から特定のOIDの情報を取得する基本的なスクリプト例を示します。
例1:単一のOIDを取得する(GET操作)
ネットワーク機器の特定のOID(例: 1.3.6.1.2.1.1.5.0
は通常sysName、機器名を指す)を取得するスクリプトです。
from pysnmp.entity.rfc3413.oneliner import cmdrsp, context
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
# SNMPv2c Manager設定
snmpEngine = engine.SnmpEngine()
# 対象機器と認証情報
device_ip = 'YOUR_DEVICE_IP' # ネットワーク機器のIPアドレスに置き換えてください
community_string = 'YOUR_COMMUNITY_STRING' # SNMP Community文字列に置き換えてください
port = 161 # SNMPの標準ポート
# SNMPv2c Community-based security name: 'my-area'
# tag: 'my-v2c-tag'
config.addV2cCommunity(
snmpEngine,
'my-area', # securityName
community_string # communityName
)
# UDP over IPv4
config.addTransport(
snmpEngine,
udp.domainName,
udp.UdpTransport().openServerMode()
)
# Remote SNMP agent IPv4/UDP
config.addTransport(
snmpEngine,
udp.domainName + (1,), # Endpoint name
udp.UdpTransport().openClientMode()
)
# GET操作の実行
# OIDを指定します (例: sysName)
oid_to_get = '1.3.6.1.2.1.1.5.0'
errorIndication, errorStatus, errorIndex, varBinds = cmdrsp.getCmd(
snmpEngine,
'my-area', # securityName
context.ContextData(), # contextName
udp.domainName + (1,), # transportTag
(oid_to_get,) # OID(s) to GET
)
# 結果の表示
if errorIndication:
print(f"SNMP Error: {errorIndication}")
elif errorStatus:
print(f"SNMP Error: {errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex) - 1][0].prettyPrint() or '?'}")
else:
for oid, val in varBinds:
print(f"OID: {oid.prettyPrint()}, Value: {val.prettyPrint()}")
スクリプトの解説:
pysnmp.entity.rfc3413.oneliner.cmdrsp.getCmd
を使用してGET操作を行います。- SNMPエンジン、認証情報(Community文字列)、対象機器のトランスポート設定を行います。
errorIndication
は通信レベルのエラー、errorStatus
はSNMPプロトコルレベルのエラーを示します。エラーハンドリングは必須です。varBinds
に取得したOIDと値のペアが含まれます。.prettyPrint()
メソッドで値を人が読める形式に変換しています。
例2:複数のOIDを取得する(BULKGET操作)
複数のOIDを効率的に取得したい場合は、GETNEXTやGETBULK操作が有効です。ここでは、GETBULKに相当する操作の基本的な考え方を示します(pysnmp
では bulkCmd
を使用します)。
from pysnmp.entity.rfc3413.oneliner import cmdrsp, context
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
# SNMPv2c Manager設定
snmpEngine = engine.SnmpEngine()
# 対象機器と認証情報
device_ip = 'YOUR_DEVICE_IP'
community_string = 'YOUR_COMMUNITY_STRING'
port = 161
# SNMPv2c Community-based security name: 'my-area'
# tag: 'my-v2c-tag'
config.addV2cCommunity(
snmpEngine,
'my-area', # securityName
community_string # communityName
)
# UDP over IPv4
config.addTransport(
snmpEngine,
udp.domainName,
udp.UdpTransport().openServerMode()
)
# Remote SNMP agent IPv4/UDP
config.addTransport(
snmpEngine,
udp.domainName + (1,), # Endpoint name
udp.UdpTransport().openClientMode()
)
# BULKGET操作の実行 (例: sysDescrとsysUpTimeを取得)
# nonRepeaters=0: 最初のOIDは繰り返し取得しない (通常0か1)
# maxRepetitions=10: 後続のOIDリストの各エントリに対して最大何回繰り返すか
oids_to_get = ['1.3.6.1.2.1.1.1.0', '1.3.6.1.2.1.1.3.0'] # 例: sysDescr, sysUpTime
errorIndication, errorStatus, errorIndex, varBinds = cmdrsp.bulkCmd(
snmpEngine,
'my-area', # securityName
context.ContextData(), # contextName
udp.domainName + (1,), # transportTag
0, # nonRepeaters
50, # maxRepetitions (一度に取得する最大項目数)
*(oids_to_get) # OID(s) to GETBULK
)
# 結果の表示
if errorIndication:
print(f"SNMP Error: {errorIndication}")
elif errorStatus:
print(f"SNMP Error: {errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex) - 1][0].prettyPrint() or '?'}")
else:
for row in varBinds:
for oid, val in row:
print(f"OID: {oid.prettyPrint()}, Value: {val.prettyPrint()}")
補足:
- 上記のコードは基本的なSNMPv2cの例です。SNMPv3を使用する場合は、認証設定(ユーザー名、認証プロトコル、プライバシープロトコルなど)がより複雑になりますが、
pysnmp
はこれもサポートしています。 - これらのスクリプトを実行するには、対象のネットワーク機器でSNMPエージェントが有効化されており、指定したIPアドレス、ポート、Community文字列(またはv3ユーザー情報)でアクセスできる必要があります。
収集データの分析・活用例
SNMPで取得した生データ(OIDと値のペア)だけでは、その意味を理解したり、傾向を把握したりするのは困難です。Pythonを使って、これらのデータを現場で役立つ形に加工・分析・活用する例をいくつかご紹介します。
1. 閾値監視と通知
特定のOIDの値が、あらかじめ定義した閾値を超えた場合に、何らかのアクション(例: ログ出力、Slack通知、メール送信など)を実行します。
# 例: CPU使用率 (OIDはベンダーや機種により異なる場合があります)
# ここでは仮のOIDを使用します。実際の機器のMIBを確認してください。
cpu_usage_oid = '1.3.6.1.4.1.9.2.1.58.0' # Ciscoなどの例(実際には異なる可能性あり)
threshold_percent = 80 # 閾値: 80%
# 上記のgetCmdスクリプトで cpu_usage_oid の値を取得する処理を記述
# 例として、取得した値が cpu_value という変数に入ったと仮定します
try:
cpu_value = int(cpu_value) # 取得した値が文字列の場合、整数に変換
if cpu_value > threshold_percent:
print(f"ALERT: CPU使用率が閾値を超えました - {cpu_value}%")
# ここに通知処理を追加 (例: Slack Webhookを呼び出す)
# import requests
# requests.post('YOUR_SLACK_WEBHOOK_URL', json={'text': f'ALERT: {device_ip} CPU usage is {cpu_value}%'})
except ValueError:
print(f"WARN: CPU使用率の値'{cpu_value}'が数値ではありませんでした。")
except Exception as e:
print(f"ERROR: 閾値チェック中にエラーが発生しました - {e}")
2. 時系列データとしての保存と簡易レポート
収集したSNMPデータを定期的に取得し、CSVファイルやデータベースに保存することで、時系列データとして蓄積できます。これにより、過去の推移を追跡したり、簡易的なレポートを生成したりすることが可能になります。
import csv
import datetime
import os
# 例: インターフェースの送受信バイト数カウンター (OIDはベンダーや機種により異なる)
# ifInOctets, ifOutOctets のテーブルOID
interface_mib_table_oid = '1.3.6.1.2.1.2.2.1'
# 収集したデータを保存するCSVファイル
csv_file = 'snmp_data.csv'
def append_data_to_csv(data, filename):
"""収集したデータをCSVファイルに追記する"""
file_exists = os.path.exists(filename)
with open(filename, 'a', newline='') as f:
writer = csv.writer(f)
if not file_exists:
# ヘッダー行を書き込む (OIDをヘッダーとする)
header = ['timestamp'] + [str(oid) for oid, _ in data]
writer.writerow(header)
# データ行を書き込む
row = [datetime.datetime.now().isoformat()] + [str(val) for _, val in data]
writer.writerow(row)
# --- データ収集処理(上記bulkCmdなどを利用) ---
# 複数のOID/テーブルからデータを取得し、varBinds に格納したと仮定
# 取得した varBinds (list of list of (oid, val)) をフラットなリスト of (oid, val) に変換する例
flat_data = [(oid, val) for row in varBinds for oid, val in row]
# --- データ収集処理 終了 ---
# 収集データをCSVに保存
append_data_to_csv(flat_data, csv_file)
print(f"SNMPデータを'{csv_file}'に追記しました。")
# 簡易レポート例: CSVからデータを読み込み、最新の値を取得
if os.path.exists(csv_file):
with open(csv_file, 'r') as f:
reader = csv.reader(f)
header = next(reader) # ヘッダー行をスキップ
last_row = None
for row in reader:
last_row = row # 最後の行を保持
if last_row:
print("\n--- 最新のデータ ---")
timestamp = last_row[0]
print(f"タイムスタンプ: {timestamp}")
for i in range(1, len(last_row)):
print(f"{header[i]}: {last_row[i]}")
これは非常に簡易的な例ですが、pandas
ライブラリなどを使用すれば、より高度なデータ分析(平均値、最大値、変動の算出など)や、matplotlibなどによるグラフ化も容易に行えます。
実践的な考慮事項
現場でこれらのスクリプトを運用する際には、いくつかの考慮事項があります。
- 認証情報の安全な管理: スクリプト内にCommunity文字列を直接記述するのは危険です。環境変数、設定ファイル(暗号化)、HashiCorp Vaultのようなシークレット管理ツールなどを利用することを強く推奨します。
- 大規模環境への対応: 数十、数百台といった多数の機器からデータを収集する場合、逐次処理では時間がかかりすぎます。
concurrent.futures
を使った並列処理や、ネットワーク自動化フレームワークであるNornir(SNMPプラグインが存在します)のようなツールを活用することで、効率的に並列実行が可能です。 - エラーハンドリングとリトライ: ネットワーク機器へのアクセスは不安定になることがあります。タイムアウト、接続拒否、SNMPエージェントの応答なしなど、様々なエラーを想定した堅牢なエラーハンドリングと、必要に応じたリトライ処理を実装する必要があります。
- MIBファイルの利用: OIDの数値列は人間にとって分かりにくいものです。ベンダーから提供されるMIBファイルをPythonスクリプトから利用することで、OIDをsysNameやifInOctetsのような名前で指定できるようになり、スクリプトの可読性が大幅に向上します。
pysnmp
はMIBファイルのロード機能をサポートしています。 - データストレージと可視化: 収集した時系列データを効率的に管理し、グラフなどで可視化するには、InfluxDBのような時系列データベースとGrafanaのような可視化ツールとの連携を検討すると良いでしょう。Pythonはこれらのツールとの連携も容易です。
他の自動化ツール/IaCとの連携
PythonによるSNMPデータ収集自動化は、インフラ自動化全体のワークフローの中に組み込むことで、より大きな価値を発揮します。
- IaCツールとの連携: AnsibleなどのIaCツールを用いて、ネットワーク機器上のSNMPエージェントの設定(有効化、Community文字列/v3ユーザー設定、Trap送信先設定など)を自動化します。これにより、監視に必要な基盤設定自体をコードとして管理できます。
- 監視ツールとの連携: 収集したデータをZabbixやPrometheusといった集中監視ツールに連携します。Pythonスクリプトをカスタムメトリック収集エージェントとして動作させたり、収集したデータを監視ツールのAPI経由で登録したりすることで、既存の監視基盤と統合できます。
- CI/CDパイプラインへの組み込み: ネットワーク設定変更を含むデプロイメントパイプラインに、SNMPデータによるヘルスチェックステップを組み込むことができます。例えば、「設定変更後にCPU使用率やエラーカウンターが異常値を示していないか」をSNMPで自動確認し、問題があればデプロイをロールバックする、といった使い方が考えられます。
まとめ
この記事では、Pythonとpysnmp
ライブラリを用いたネットワーク機器のSNMPデータ収集および分析自動化の基本的な手法をご紹介しました。ネットワーク機器の操作に不慣れな方でも、Pythonスキルを活かせば、機器の内部状態に関する重要な情報を効率的に取得し、活用できるようになります。
ご紹介したスクリプト例はあくまで出発点です。これを基に、エラーハンドリングの強化、認証情報のセキュアな管理、並列処理の実装、収集データの長期保存と高度な分析、そして他の運用ツールとの連携を進めることで、より実践的で信頼性の高いネットワーク監視・分析自動化システムを構築することが可能です。
ネットワーク自動化の領域は広く、CLI、API、SNMPなど様々なアプローチがあります。SNMPは機器の状態監視において非常に強力な手段の一つであり、Pythonによる自動化は、その活用を大きく加速させます。ぜひこの記事で得た知識を、日々の運用業務の効率化に役立ててください。