手動コマンド入力の悪夢とネットワーク自動化のアプローチ
ネットワーク運用者なら誰もが一度は経験したことがあるでしょう。深夜11時、PuTTYのタブを何十個も開いて、拠点にある50台のスイッチに対してアクセスリスト(ACL)の1行修正、NTPサーバーのIP変更、あるいは設定ファイルのバックアップを行うだけのために画面と睨み合うような状況です。
手動作業は非効率なだけでなく、重大な障害のリスクを常に孕んでいます。IPアドレスの1オクテットを打ち間違えたり、write memory を忘れたり、コマンドの投入途中で回線が切断されたりすれば、一瞬で拠点全体が通信不能に陥ります。こうしたリスクから脱却するため、ネットワーク業界では主に以下の4つのアプローチが採用されています。
- Bashスクリプト+Expect、または素のParamiko: SSHセッションを直接開き、機器のCLIに生の文字列を送信する。
- Ansible Network: ベンダー公式コレクションを介し、YAML形式のPlaybookを用いた宣言的(Declarative)な構成管理を行う。
- Netmiko(Python): Paramikoをベースに構築され、100種類以上の主要なネットワークOSのCLIに最適化された専用ライブラリ。
- RESTCONF / NETCONF(YANGモデル): 最新機器において、JSON/XMLによる構造化データを用いてAPI経由で通信する。
各アプローチのメリットとデメリット
どのツールにもそれぞれの強みがありますが、実際の運用における導入難易度には大きな差があります。
- 素のParamiko:
- メリット: 非常に軽量で、外部ライブラリへの依存が少ない。
- デメリット: ターミナルの制御が極めて困難。
--More--によるページャー処理の自作、バッファ待機のためのtime.sleep()の挿入、プロンプト(#、>、(config)#など)の独自フィルタリングが必要になる。出力が5,000行に及ぶコマンドでは、スクリプトがハングアップしやすい。
- Ansible:
- メリット: エージェントレスで、大規模な設定標準化に極めて強力。冪等性(Idempotency:差分がある場合のみ変更する仕組み)が標準で備わっている。
- デメリット: 単純な状態確認にはオーバーヘッドが大きい。古いファームウェアやマイナーベンダーの機器を扱う場合、Ansibleでカスタムフィルターを書くのはPythonでコードを書くよりもはるかに難易度が高い。
- RESTCONF / NETCONF:
- メリット: JSON/XMLの構造化データで取得できるため、CLI画面の文字列フォーマット変更による影響を受けない。
- デメリット: ハードウェアの制約が大きい。Cisco Catalyst 2960などの旧世代エンタープライズスイッチやISR G2ルーターではサポートされていないか、高価なライセンスが必要となる。
- Netmiko:
- メリット: Paramikoが抱える煩わしさを根本から解消。プロンプトの自動検出、ページネーションの無効化(
terminal length 0)、ユーザーモード・特権EXECモード・コンフィグレーションモード間のスムーズな切り替えを実現。Cisco(IOS, NX-OS)、Juniper(Junos)、MikroTik(RouterOS)からArista、Fortinetまで幅広くサポート。 - デメリット: 本質的にはテキストパース(Text Parsing)であるため、OSの大規模アップデートなどで画面出力フォーマットが変更された場合、正規表現などのパース処理を修正する必要がある。
- メリット: Paramikoが抱える煩わしさを根本から解消。プロンプトの自動検出、ページネーションの無効化(
なぜインフラエンジニアはNetmikoを選ぶのか?
実際の現場では、単一ベンダーだけで統一されたインフラは稀です。データセンターにはJuniper SRXファイアウォールとCisco Catalystコアスイッチを配置し、各拠点の境界ルーターにはコストパフォーマンスに優れたMikroTik CCRを採用するといったマルチベンダー環境が一般的です。このような混在環境において、Netmikoは最も手軽で頼れる解決策となります。
cronによる定期実行スクリプトに組み込めるほど軽量でありながら、タイムアウト処理などを自動でインテリジェントに処理してくれます。何より、Pythonが持つ柔軟性を最大限に活かし、200台分のIPアドレスが記載されたExcelファイルを読み込んでポート状態をスキャンし、即座にTelegramへアラートを通知するといった処理を自由自在に実装できます。
Netmiko実践ステップバイステップガイド
1. 仮想環境のセットアップ
NetmikoはPython 3.8〜3.12で快適に動作します。システム環境とのライブラリ衝突を防ぐため、専用の仮想環境を作成しましょう。
# 仮想環境の作成と有効化
python3 -m venv netauto-env
source netauto-env/bin/activate
# 最新版のNetmikoをインストール
pip install --upgrade netmiko
2. Cisco IOSスイッチでの情報確認コマンド(Show Command)の実行
send_command() 関数は、確認コマンドを送信し、プロンプトの出現を検知してデータ全体の出力を自動的に待機します。
import os
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoTimeoutException, NetmikoAuthenticationException
cisco_switch = {
'device_type': 'cisco_ios',
'host': '192.168.10.2',
'username': os.getenv('NET_USER', 'admin'),
'password': os.getenv('NET_PASS', 'StrongPassword123'),
'secret': os.getenv('NET_ENABLE', 'EnablePassword123'),
}
try:
print(f"{cisco_switch['host']} への接続を開始します...")
with ConnectHandler(**cisco_switch) as net_connect:
# 特権EXECモードへ移行
net_connect.enable()
# インターフェースのIP状態確認コマンドを送信
output = net_connect.send_command("show ip interface brief")
print("--- 機器からの出力結果 ---")
print(output)
except NetmikoTimeoutException:
print(f"エラー: {cisco_switch['host']} への接続がタイムアウトしました。")
except NetmikoAuthenticationException:
print(f"エラー: {cisco_switch['host']} のユーザー名またはパスワードが正しくありません。")
except Exception as e:
print(f"予期せぬエラーが発生しました: {e}")
3. MikroTik RouterOSへの一括設定投入
MikroTikのCLIはメニュー階層構造になっており、[admin@MikroTik] > という形式のプロンプトが使用されます。Netmikoには mikrotik_routeros ドライバーが標準で用意されており、send_config_set() を介して一連のコマンドを正確に投入できます。
from netmiko import ConnectHandler
mikrotik_router = {
'device_type': 'mikrotik_routeros',
'host': '192.168.88.1',
'username': 'admin',
'password': 'MikroTikSecretPassword',
'port': 22,
}
# 投入する設定コマンド一覧
config_commands = [
'/ip pool add name=pool-vpn ranges=172.16.100.10-172.16.100.50',
'/ip firewall filter add chain=input protocol=icmp action=accept comment="Allow Ping"',
'/system ntp client set enabled=yes servers=vn.pool.ntp.org'
]
with ConnectHandler(**mikrotik_router) as net_connect:
print("MikroTikに接続しました。設定コマンドを投入しています...")
output = net_connect.send_config_set(config_commands)
print(output)
print("MikroTikの設定が完了しました!")
4. Juniper Junosでの安全な構成管理
Junosには、Candidate Configuration(候補設定)と厳格なCommitメカニズムが存在します。Netmikoには、本番反映前に構文エラーを検証するための専用メソッドが用意されています。
from netmiko import ConnectHandler
juniper_device = {
'device_type': 'juniper_junos',
'host': '10.0.0.1',
'username': 'noc_admin',
'password': 'JuniperPassword',
}
commands_to_apply = [
'set system services ssh root-login deny',
'set snmp location "Datacenter HaNoi Rack A1"'
]
with ConnectHandler(**juniper_device) as net_connect:
# 候補設定(Candidate Config)モードを開く
net_connect.config_mode()
# setコマンド群を投入
net_connect.send_config_set(commands_to_apply, exit_config_mode=False)
# 反映前に構文チェック(commit check)を実行
check_result = net_connect.commit(check=True)
print(f"commit checkの結果: {check_result}")
# エラーがなければコメント付きで正式にコミット
net_connect.commit(comment="Automated security hardening via Netmiko")
net_connect.exit_config_mode()
print("Juniperへの設定コミットが正常に完了しました!")
5. 本番運用で役立つ3つの実践テクニック
スクリプトの対象を1台から100台規模にスケールアウトする際は、以下のポイントに留意してください。
- Concurrent Futuresによるマルチスレッド化:
forループによる順次処理は避けましょう。100台のスイッチを直列に処理すると約20分かかりますが、concurrent.futures.ThreadPoolExecutor(max_workers=20)を利用して並行処理を行えば、全体の実行時間を1分未満に短縮できます。 - タイムアウト値の適切な延長:
show tech-supportや、90万件以上のプレフィックスを持つBGPルーティングテーブルの確認など、負荷の高いコマンドを実行する際は、send_command(cmd, read_timeout=90)のように待機時間を明示的に延ばし、セッション切断を防ぎます。 - TextFSMを活用した構造化データの抽出: 複雑な正規表現を独自に書く代わりに、
send_command()に引数use_textfsm=Trueを渡します。これにより、NetmikoがCLIのプレーンテキスト出力を扱いやすいPythonの辞書リスト形式に自動変換してくれます。
