告别手动show run!用Python+Netmiko批量备份Cisco设备配置(附完整脚本)
用Python+Netmiko实现Cisco设备配置的智能备份与管理
网络工程师每天都要面对数十台甚至上百台网络设备的配置管理工作,传统的手工登录每台设备执行show run并保存配置的方式不仅效率低下,而且容易出错。我曾经管理过一个拥有200多台Cisco设备的网络环境,每周手动备份配置就要花费大半天时间,直到发现了Python+Netmiko这个黄金组合。
1. 为什么需要自动化配置备份
网络设备的配置备份是运维工作的基础,但传统方式存在诸多痛点:
- 时间成本高:每台设备手动登录需要3-5分钟,100台设备就需要5-8小时
- 人为错误风险:容易输错命令、漏掉设备或保存到错误位置
- 版本管理混乱:手工备份难以建立规范的版本控制系统
- 应急恢复慢:故障时难以快速找到正确的配置版本
真实案例:去年我们遇到一次核心交换机故障,由于手工备份不及时,最后只能基于3天前的配置进行恢复,导致部分新业务规则丢失,花了整整两天时间才完全修复。
2. Netmiko环境准备与基础配置
2.1 安装Netmiko库
Netmiko是基于Paramiko开发的网络设备连接库,支持SSH和Telnet协议。安装非常简单:
pip install netmiko注意:建议使用Python 3.6+版本,避免兼容性问题
2.2 基础连接测试
先创建一个简单的测试脚本,验证与设备的连接:
from netmiko import ConnectHandler device = { "device_type": "cisco_ios", "ip": "192.168.1.1", # 替换为你的设备IP "username": "admin", "password": "admin123", "secret": "enablepass" # enable密码 } try: with ConnectHandler(**device) as conn: print(f"成功连接到 {device['ip']}") output = conn.send_command("show version") print(output[:200]) # 只打印前200字符 except Exception as e: print(f"连接失败: {str(e)}")常见连接问题排查:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 网络不通/设备未开启SSH | 检查网络连通性,确认SSH服务已启用 |
| 认证失败 | 用户名/密码错误 | 确认凭据正确,检查大小写 |
| 提示符不匹配 | device_type设置错误 | 确认设备型号选择正确 |
3. 实现智能配置备份系统
3.1 单设备配置备份
基础版的配置备份脚本:
from netmiko import ConnectHandler from datetime import datetime def backup_single_device(device_params): try: with ConnectHandler(**device_params) as conn: conn.enable() # 进入特权模式 # 取消分页显示 conn.send_command("terminal length 0") # 获取运行配置 running_config = conn.send_command("show running-config") # 生成带时间戳的文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{device_params['ip']}_config_{timestamp}.txt" # 写入文件 with open(filename, "w") as f: f.write(running_config) print(f"{device_params['ip']} 配置备份成功,保存为 {filename}") return True except Exception as e: print(f"{device_params['ip']} 备份失败: {str(e)}") return False3.2 多设备批量备份
实际工作中,我们需要处理的是设备列表。创建一个CSV文件devices.csv:
ip,username,password,enable_secret,device_type 192.168.1.1,admin,admin123,enablepass,cisco_ios 192.168.1.2,admin,admin123,enablepass,cisco_ios 192.168.1.3,admin,admin123,enablepass,cisco_ios批量备份脚本:
import csv from concurrent.futures import ThreadPoolExecutor def backup_all_devices(csv_file, max_workers=5): success = 0 failure = 0 with open(csv_file) as f: devices = list(csv.DictReader(f)) # 使用线程池并行执行 with ThreadPoolExecutor(max_workers=max_workers) as executor: results = executor.map(lambda d: backup_single_device(d), devices) for result in results: if result: success += 1 else: failure += 1 print(f"备份完成: 成功 {success} 台, 失败 {failure} 台")提示:线程数(max_workers)不宜设置过高,一般5-10为宜,避免对设备造成过大负载
4. 高级功能与最佳实践
4.1 配置差异比较
备份后,我们经常需要比较不同版本的配置变化。使用Python的difflib库可以实现:
import difflib def compare_configs(old_file, new_file): with open(old_file) as f1, open(new_file) as f2: old_lines = f1.readlines() new_lines = f2.readlines() differ = difflib.HtmlDiff() html_diff = differ.make_file(old_lines, new_lines, fromdesc=old_file, todesc=new_file) diff_file = f"diff_{old_file}_{new_file}.html" with open(diff_file, "w") as f: f.write(html_diff) print(f"差异报告已生成: {diff_file}")4.2 自动备份调度
结合操作系统的定时任务功能,可以实现全自动备份:
- Windows:使用任务计划程序
- Linux/macOS:使用crontab
示例crontab配置(每天凌晨2点执行备份):
0 2 * * * /usr/bin/python3 /path/to/backup_script.py4.3 备份文件管理策略
合理的备份管理应包括:
- 命名规范:
设备IP_日期_时间.txt,如192.168.1.1_20230815_143022.txt - 目录结构:
/backups ├── /daily # 每日备份 ├── /weekly # 每周完整备份 └── /monthly # 每月归档 - 保留策略:
- 每日备份保留7天
- 每周备份保留4周
- 每月备份保留12个月
4.4 异常处理与日志记录
健壮的备份系统需要完善的错误处理和日志记录:
import logging from netmiko.ssh_exception import NetmikoTimeoutException, NetmikoAuthenticationException logging.basicConfig( filename='backup.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) def backup_with_logging(device): try: # ...备份逻辑... logging.info(f"{device['ip']} 备份成功") except NetmikoTimeoutException: logging.error(f"{device['ip']} 连接超时") except NetmikoAuthenticationException: logging.error(f"{device['ip']} 认证失败") except Exception as e: logging.error(f"{device['ip']} 未知错误: {str(e)}")5. 安全增强方案
5.1 凭据安全管理
不要在脚本中硬编码密码,推荐使用以下方法:
环境变量:
import os username = os.getenv('NET_USERNAME') password = os.getenv('NET_PASSWORD')加密配置文件:使用python-keyring等库
5.2 备份文件加密
敏感配置应该加密存储:
from cryptography.fernet import Fernet # 生成密钥(只需一次) key = Fernet.generate_key() cipher_suite = Fernet(key) # 加密配置 encrypted_config = cipher_suite.encrypt(running_config.encode()) # 解密配置 decrypted_config = cipher_suite.decrypt(encrypted_config).decode()5.3 备份完整性验证
添加校验和确保备份文件未被篡改:
import hashlib def calculate_checksum(config): return hashlib.sha256(config.encode()).hexdigest() # 保存校验和 checksum = calculate_checksum(running_config) with open(f"{filename}.sha256", "w") as f: f.write(checksum)6. 扩展应用场景
6.1 配置变更自动化
除了备份,Netmiko还可以用于批量配置变更:
def update_ntp_servers(device, servers): commands = [ "configure terminal", "no ntp server", # 移除现有NTP配置 *[f"ntp server {server}" for server in servers], "end", "write memory" ] with ConnectHandler(**device) as conn: conn.enable() output = conn.send_config_set(commands) print(f"{device['ip']} NTP配置更新完成")6.2 设备健康检查自动化
定期收集设备状态信息:
def health_check(device): commands = { "cpu": "show processes cpu", "memory": "show processes memory", "interfaces": "show interfaces summary" } results = {} with ConnectHandler(**device) as conn: conn.enable() for name, cmd in commands.items(): results[name] = conn.send_command(cmd) return results6.3 与CMDB系统集成
将备份的配置信息存入CMDB:
import requests def upload_to_cmdb(device_ip, config): cmdb_url = "https://cmdb.example.com/api/devices" payload = { "ip": device_ip, "config": config, "backup_time": datetime.now().isoformat() } response = requests.post(cmdb_url, json=payload, auth=("api_user", "api_pass")) if response.status_code == 201: print(f"{device_ip} 配置已上传至CMDB") else: print(f"{device_ip} 上传失败: {response.text}")7. 性能优化技巧
7.1 连接池管理
频繁建立SSH连接开销很大,可以使用连接池优化:
from netmiko import ConnectHandler from functools import lru_cache @lru_cache(maxsize=10) def get_connection(device_ip): device = { "device_type": "cisco_ios", "ip": device_ip, "username": "admin", "password": "admin123" } return ConnectHandler(**device) def backup_with_pool(device_ip): conn = get_connection(device_ip) config = conn.send_command("show running-config") # ...保存配置...7.2 异步IO实现
使用asyncio提高并发性能:
import asyncio from scrapli.driver.core import AsyncIOSXEDriver async def async_backup(device): try: async with AsyncIOSXEDriver( host=device["ip"], auth_username=device["username"], auth_password=device["password"], auth_strict_key=False, ) as conn: await conn.send_command("terminal length 0") config = await conn.send_command("show running-config") with open(f"{device['ip']}_config.txt", "w") as f: f.write(config.result) print(f"{device['ip']} 备份成功") except Exception as e: print(f"{device['ip']} 备份失败: {str(e)}") async def main(devices): await asyncio.gather(*[async_backup(d) for d in devices]) # 使用示例 devices = [...] # 设备列表 asyncio.run(main(devices))7.3 内存优化
处理大型配置时优化内存使用:
def backup_large_config(device): with ConnectHandler(**device) as conn: conn.enable() conn.send_command("terminal length 0") # 流式处理,避免大内存占用 with open(f"{device['ip']}_config.txt", "w") as f: # 分块读取 output_gen = conn.send_command("show running-config", read_timeout=30, delay_factor=2) for chunk in output_gen: f.write(chunk)8. 企业级部署建议
8.1 架构设计
对于大型网络环境,建议采用分布式架构:
[调度服务器] → [工作队列] → [多个备份工作节点] → [集中式存储]关键组件:
- 消息队列:RabbitMQ或Redis
- 分布式任务:Celery或Dask
- 集中存储:S3/MinIO或NAS
8.2 监控与告警
实现备份系统的自我监控:
def monitor_backup_system(): # 检查最近备份时间 last_backup = get_last_backup_time() if (datetime.now() - last_backup) > timedelta(hours=24): send_alert("备份系统异常: 超过24小时未备份") # 检查存储空间 if get_disk_usage() > 90: send_alert("备份存储空间不足")8.3 灾备方案
确保备份系统自身的高可用:
- 多地备份:在不同物理位置保存备份副本
- 定期恢复测试:每季度抽样恢复验证
- 系统冗余:备份服务器集群化部署
9. 常见问题解决方案
9.1 设备兼容性问题
不同厂商、型号的设备可能需要特殊处理:
DEVICE_PROFILES = { "cisco_ios": { "cmd": "show running-config", "pre_cmds": ["terminal length 0"] }, "huawei": { "cmd": "display current-configuration", "pre_cmds": ["screen-length 0 temporary"] }, "juniper": { "cmd": "show configuration | display set", "pre_cmds": ["set cli screen-length 0"] } } def get_config(device): profile = DEVICE_PROFILES.get(device["device_type"]) if not profile: raise ValueError(f"不支持的设备类型: {device['device_type']}") with ConnectHandler(**device) as conn: for cmd in profile["pre_cmds"]: conn.send_command(cmd) return conn.send_command(profile["cmd"])9.2 网络延迟问题
针对高延迟链路优化参数:
device = { # ...其他参数... "timeout": 60, # 连接超时(秒) "session_timeout": 120, # 会话超时 "delay_factor": 2, # 命令间隔延迟因子 "global_delay_factor": 2 # 全局延迟因子 }9.3 大规模部署优化
当设备数量超过500台时:
- 分区域部署:按地理位置部署多个备份节点
- 分级备份:核心设备每日备份,接入设备每周备份
- 增量备份:只备份变更的配置部分
10. 从备份到配置管理
成熟的配置管理应该包括:
- 版本控制:使用Git管理配置变更历史
- 合规检查:自动检查配置是否符合安全规范
- 变更管理:任何变更都应有工单和审批记录
- 文档生成:自动生成网络拓扑和配置文档
def git_commit_config(device_ip, config): repo_path = f"/backups/repo/{device_ip}" if not os.path.exists(repo_path): os.makedirs(repo_path) subprocess.run(["git", "init"], cwd=repo_path) config_file = os.path.join(repo_path, "running-config.txt") with open(config_file, "w") as f: f.write(config) subprocess.run(["git", "add", "."], cwd=repo_path) subprocess.run(["git", "commit", "-m", f"Backup {datetime.now()}"], cwd=repo_path)