ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python网络设备自动配置实战:从SSH连接到批量下发

2026/9/9 21:02:47 拓冰建站 浏览量
Python网络设备自动配置实战:从SSH连接到批量下发 最近有朋友问我能不能用Python把网络设备的自动配置跑起来。其实这个需求我印象很深早年给客户维护几十台交换机每天的工作就是开SecureCRT登录设备、敲命令、复制粘贴配置一台一台弄到怀疑人生。后来我花了一周时间把整个流程改造成了Python脚本从那以后批量改端口、统一下发配置、做配置备份基本就是一条命令的事。这篇文章就基于这个项目梳理一下我的完整思路包括工具选型、环境搭建、代码实现、并发批量执行、回滚机制和一大堆实际踩过的坑适合网络工程师、运维人员以及学了Python基础但想找个真实场景练手的朋友。先说清楚这个项目到底在解决什么问题。网络设备的自动配置本质就是把“人坐在终端前登录设备敲命令”这个动作替换成“程序通过SSH连接设备并下发命令”。它解决的痛点是设备数量多、人工操作慢、容易打错命令、变更过程没有记录、出了事不知道是谁改的。自动化之后配置效率可以提升一个量级而且每一次变更都有日志、可审计、可回滚。这篇文章不会只给一堆代码就完事我会把为什么这么选、每一个环节的坑点以及可复现的方案都写出来。1. 项目立项为什么是Python来做网络设备的自动配置1.1 手工配置的痛点与自动化刚需先聊聊我接触过的真实场景。有一年我负责一个园区网的维护核心层加汇聚层加上接入层林林总总一百多台设备。平时的需求很多是重复性的比如给某几个楼层的新办公室划分VLAN、统一调整STP优先级、批量修改SNMP社区字符串、给所有交换机开启NTP同步。这些操作如果靠人工一台设备平均要3到5分钟一百台就是五六个小时中间还不能出一点岔子。更麻烦的是如果操作到一半有人打断很容易漏设备、漏命令后面排查起来非常痛苦。这种场景下自动化的刚需非常明确。它能解决三件事一是把重复劳动变成脚本执行省时间二是把人工容易犯的低级错误敲错命令、漏配置、重复配置通过程序化的方式规避掉三是把变更过程记录下来哪台设备、什么时间、执行了哪些命令全部留痕。这个价值在等保、审计以及故障回溯时特别明显。1.2 工具选型Paramiko、Netmiko、NAPALM到底怎么选很多初学者上来就问我用哪个库我的答案是如果只做配置下发首选Netmiko如果要做配置审计和标准化可以考虑NAPALMParamiko可以作为底层学习工具但实际项目里没必要从头封装。我把这几个库的对比整理成了表格方便你快速决策库定位上手难度主要能力适用场景ParamikoSSH协议底层库较高建立SSH连接、发送命令、接收输出学习SSH协议原理、自定义封装特殊功能Netmiko网络设备SSH封装库低多厂商设备连接、交互式配置、命令超时控制批量执行命令、配置下发日常主力NAPALM网络自动化高级库中获取配置、对比配置、回滚、标准化操作配置一致性检查、自动化回滚、多厂商兼容我的选型逻辑很简单Netmiko底层虽然也是Paramiko但它把“设备连接”这件事做了大量封装屏蔽了不同厂商之间的交互差异。比如思科的设备登录后要等或#提示符华为的设备可能显示Huawei锐捷、H3C又各有不同Netmiko通过设备类型参数自动适配这就省掉了很多恶心的适配工作。NAPALM功能更强但上手成本和硬件兼容性要求也更高如果只是做配置下发Netmiko的性价比是最高的。1.3 整体设计思路脚本不是写到一半就能用的这个项目我采用的架构是一个典型的分层结构不求花哨但求稳定可维护设备信息层用YAML或JSON统一管理设备IP、用户名、密码、设备类型、端口等连接参数。命令模板层把要执行的配置命令放在独立的配置文件中和代码分离。执行核心层基于Netmiko封装连接、登录、进入配置模式、执行命令、保存配置。结果记录层把每一台设备的执行结果、日志、出错信息写进文件方便审计和复盘。回滚辅助层在执行变更前先备份设备当前配置变更失败时可以恢复。这样设计的原因很简单网络设备自动化最大的敌人是“不可控”。如果代码和设备信息、命令内容耦合在一起改一台设备就要改一次代码后期维护成本会爆炸。分离之后新加一台设备只需要在设备清单里加一行下发新配置只需要改命令文件代码本身基本不用动。这也是我在做了几个自动化项目之后总结出来的经验脚本不是写到能跑就行而是要能长期用、好维护。2. 环境准备与基础踩坑把Python这台“执行引擎”先跑起来2.1 Python安装与多版本管理这个项目的核心依赖是Python 3.6以上版本我建议直接用3.8到3.11之间的稳定版本太老的版本有些新库不支持太新的偶尔会有依赖兼容问题。安装这块Windows用户去Python官网下载安装包时有一个非常关键的选项安装向导第一页最下面有个“Add Python to PATH”复选框一定要勾上。我见过太多人装完Python之后在命令行敲python提示找不到命令十有八九就是没勾这个。如果你像我一样机器上既有Python 2.7的老项目又要跑Python 3.x的新脚本多版本管理就很重要。Windows下我推荐用pyenv-winLinux下用pyenv它可以在不同目录之间自由切换Python版本比手动改环境变量靠谱得多。手动改系统PATH的方式我已经弃用了因为很容易把不同版本的路径混在一起后面装包时会出现装到了旧版本解释器里的诡异问题。2.2 依赖安装的正确姿势与pip换源环境装好后建议先建一个虚拟环境把项目的依赖隔离起来不要一股脑往系统全局装。我在项目目录下执行python -m venv venvWindows下激活虚拟环境venv\Scripts\activateLinux或macOS下source venv/bin/activate然后安装Netmiko它会自动把Paramiko、scp等依赖一起拉下来pip install netmiko如果你的网络环境访问默认PyPI源不稳定这里分享一个实用技巧配置国内镜像源。我一般用阿里云的PyPI镜像在用户目录下创建一个pip.iniWindows或pip.confLinux内容如下[global] index-url https://mirrors.aliyun.com/pypi/simple/ trusted-host mirrors.aliyun.com配完之后pip install的速度能快好几倍。另外如果你在公司内网环境可能需要使用离线安装包可以先在能联网的机器上执行pip download netmiko -d ./packages再把整个目录拷到内网机器上用pip install --no-index --find-links./packages netmiko安装。2.3 环境层面的常见坑从控制机到虚拟网卡环境配置阶段有几个问题非常典型我几乎每次带新人都会遇到。第一个坑是“设了静态IP但还是有自动配置”。这种情况听起来像是设备配置问题但很多时候问题出在执行自动化脚本的控制机上。比如Windows的网卡如果同时开启了DHCP和静态IP或者有多个网卡存在系统会自动分配一个169.254.x.x的APIPA地址路由表会乱掉导致脚本连接设备时走了错误的接口。解决办法是把控制机上不用的网卡禁用掉只保留和管理网络相通的那块网卡并且把DHCP、DNS等设置理顺不要混着来。第二个坑和USB网络共享设备有关。有些笔记本通过USB连接手机或者某些专用设备时系统会自动虚拟出一块NDIS远程网卡这块网卡会莫名其妙地抢路由导致脚本连接设备时请求走了这块虚拟网卡结果就是连不上或者连上了但卡死。排查方法是在命令行执行route print看看默认路由是不是指向了一个奇怪的接口如果是就把对应的NDIS网卡禁用。第三个坑是pip install时报“请安装缺失的包”之类的错误。这个通常不是因为缺包而是因为你把项目代码放在一个没有激活虚拟环境的终端里或者当前Python解释器和pip不是同一个。检查方式是在命令行执行where python和where pip看看路径是不是在同一个虚拟环境目录下。如果不在激活虚拟环境再装一次就好了。3. 核心功能实现从“能连”到“能配”的完整链路3.1 设备连接参数的标准化管理设备连接参数是整个自动化脚本的地基。我推荐用YAML文件来管理因为它的可读性比JSON好而且支持注释。下面是我在实际项目中用的设备清单示例devices: - host: 192.168.10.1 username: admin password: Cisco123 device_type: cisco_ios port: 22 - host: 192.168.10.2 username: huawei password: Huawei123 device_type: huawei port: 22这里面的device_type非常关键Netmiko就是靠它来决定用哪一套设备交互逻辑。常见的取值包括cisco_ios、cisco_xe、huawei、hp_comwareH3C、ruijie_os、mikrotik_routeros等。选错设备类型最常见的表现是登录之后程序等不到提示符直接超时。在读取YAML配置时我建议用yaml.safe_load而不是yaml.load后者在旧版本的PyYAML里存在反序列化安全风险。项目里用到的依赖最好都固定版本比如PyYAML我一般固定在5.4以上版本。下面这段代码负责加载设备清单import yaml def load_devices(filepathdevices.yaml): with open(filepath, r, encodingutf-8) as f: data yaml.safe_load(f) return data[devices]3.2 批量执行配置命令一次性下发与交互式配置掌握了连接参数之后核心实现就来了。Netmiko的基础用法非常简洁我把执行配置分为两种模式命令发送模式和配置模式。命令发送模式适合执行非交互式的查看命令比如show running-config、display current-configuration。配置模式适合进入设备的全局配置态批量下发配置条目。下面的代码演示了如何连接一台设备并进入配置模式from netmiko import ConnectHandler device { host: 192.168.10.1, username: admin, password: Cisco123, device_type: cisco_ios, } conn ConnectHandler(**device) conn.enable() # 进入特权模式 output conn.send_config_set([ vlan 100, name office_network, interface vlan 100, ip address 10.10.100.1 255.255.255.0, no shutdown, ]) print(output) conn.save_config() # 保存配置 conn.disconnect()这里有个细节send_config_set会自动进入配置模式、逐条下发命令、然后退出配置模式。如果你用的是老版本的Netmiko也可以手动调用conn.config_mode()进入配置模式下发完再调用conn.exit_config_mode()退出。save_config()方法是Netmiko对不同厂商“保存配置”命令的封装思科会执行write memory华为会执行save。对于华为设备命令模板会有些差异比如VLAN配置的写法不同要把配置模板抽离出来huawei_vlan_config: - system-view - vlan 100 - name office_network - interface vlanif 100 - ip address 10.10.100.1 24 - quit不要小看这个模板化的思维网络设备的命令差异是自动化项目里最大的隐性成本。有的厂商进入系统视图需要先执行system-view有的不需要有的命令用空格分隔参数有的用括号。把这些差异全部收敛到模板文件里代码侧的复杂度会直线下降。3.3 配置回滚与审计改坏了怎么办自动化配置最怕的一件事就是批量执行时改坏了设备。所以我做项目的第一步就是把回滚机制设计好。这里提供两种思路。第一种是“变更前备份”。在执行任何配置变更之前先把每台设备的当前running-config完整抓下来存成文件。如果变更后发现问题再把这份备份通过Netmiko重新下发。代码逻辑如下import datetime def backup_running_config(conn, device): timestamp datetime.datetime.now().strftime(%Y%m%d_%H%M%S) output conn.send_command(show running-config) with open(fbackup/{device[host]}_{timestamp}.cfg, w, encodingutf-8) as f: f.write(output)第二种是用设备的原生回滚机制。思科的IOS设备可以开启Archive功能执行变更后如果发现问题可以在几分钟内用rollback回到变更前的配置。在Netmiko中你可以先发送配置变更命令再做验证如果验证失败再调用回滚。# 开启archive conn.send_command(archive) conn.send_config_set([path flash:rollback, maximum 5]) # 执行变更前记录当前配置版本 before conn.send_command(show archive config differences) # 执行变更 conn.send_config_set([snmp-server community MySecret ro]) # 变更后做验证 after conn.send_command(show running-config | include snmp-server community) if MySecret not in after: # 回滚 conn.send_command(configure replace flash:rollback force)回滚机制之所以要提前做是因为一旦变更过程出现问题网络可能已经中断你连不上设备再好的回滚脚本也白搭。所以我的习惯是远程设备自动化配置之前一定要确认设备的带外管理方式比如console服务器是可达的否则就属于高风险操作脚本再漂亮我也建议先做小范围灰度。4. 从单台到批量并发执行与结果校验4.1 串行 vs 并发不要让一百台设备花掉一个小时如果你只是对一台设备做自动化配置前面的代码已经够用了。但实际项目中我们面对的是几十上百台设备。这个时候如果一台接一台串行处理一台花30秒五十台就是25分钟体验很差。所以我们用Python的concurrent.futures线程池来实现并发执行。下面这段代码展示了如何批量处理多台设备from concurrent.futures import ThreadPoolExecutor, as_completed def configure_device(device): 执行单台设备的配置任务返回结果状态 try: conn ConnectHandler(**device) conn.enable() output conn.send_config_set(CONFIG_TEMPLATE) conn.save_config() conn.disconnect() return {host: device[host], status: success, output: output} except Exception as e: return {host: device[host], status: failed, error: str(e)} def batch_configure(devices, max_workers10): results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map {executor.submit(configure_device, dev): dev for dev in devices} for future in as_completed(future_map): result future.result() results.append(result) print(f{result[host]}: {result[status]}) return results这里的max_workers参数是关键。并发数太小速度提升不明显并发数太大设备本身承受不住。我实测的经验是对常见的中低端交换机并发数控制在10到20之间比较稳如果设备CPU性能较弱降到5左右。如果并发过大会出现设备SSH连接数超限、CPU飙高甚至设备直接重启的情况这个代价比慢一点大得多。4.2 结果解析与验证批处理不能只管“跑完”批量执行的一大风险是程序跑完了但你以为它成功了实际上某台设备的某条命令并没有生效。因此自动化配置必须包含结果校验环节。我的做法是在执行每台设备的核心配置命令之后再用send_command读取关键配置项通过关键词或者正则表达式做断言。例如下发VLAN后紧接着查询show vlan id 100判断输出中是否包含预期的VLAN名称或接口信息。如果匹配成功才把该设备标记为“变更成功”否则标记为“失败并告警”。def verify_vlan(conn, vlan_id100, nameoffice_network): output conn.send_command(fshow vlan id {vlan_id}) if name in output: return True return False另外一个非常实用的技巧是使用ntc_templates库配合Netmiko的send_command解析半结构化输出。它通过TextFSM模板把设备的show命令输出解析成结构化数据列表和字典这样你就可以像操作JSON一样去判断某个接口的状态。比如output conn.send_command(show ip interface brief, use_textfsmTrue) for interface in output: if interface[status] up: print(interface[interface], interface[ip_address])这个用法在处理“批量检查接口状态”或“批量核对配置是否生效”时非常省事比纯字符串匹配稳定得多。4.3 把脚本封装成可复用工具从一次性脚本到小型平台脚本跑通之后我很快就发现一个尴尬的问题每次要换一批设备下发不同的配置就要去改代码。于是我把脚本升级成了一个可通过命令行参数驱动的工具。核心思路是通过argparse接收参数再结合配置文件动态加载这样就能做到“改配置不改代码”。import argparse def main(): parser argparse.ArgumentParser(descriptionNetwork Device Auto Config Tool) parser.add_argument(--devices, requiredTrue, helpPath to devices YAML file) parser.add_argument(--template, requiredTrue, helpPath to config template file) parser.add_argument(--dry-run, actionstore_true, helpDry run, only print config) parser.add_argument(--max-workers, typeint, default10, helpConcurrency) args parser.parse_args() if args.dry_run: # 干跑模式只打印将要执行的命令不实际下发 with open(args.template, r, encodingutf-8) as f: print(f.read()) return devices load_devices(args.devices) config_template load_template(args.template) results batch_configure(devices, config_template, max_workersargs.max_workers)--dry-run这个参数特别推荐加上。它让你在批量变更之前可以完整地检查每台设备将要执行的命令列表确认没有写错IP、没有配置错端口心理会踏实很多。我实际使用中干跑模式至少帮我拦下过三次低级错误比如把VLAN写错、把接口名写错这类问题。5. 实战问题与排查技巧实录5.1 连接失败问题定位先从这五个方向入手网络设备自动配置最常见的故障就是连不上设备或者连上了但脚本卡住。我按经验概率排个序你遇到问题时可以按这个思路排查。第一个是认证失败。Netmiko会直接抛出AuthenticationException说明用户名或密码不对或者账号被锁定。这时候先手动用SSH工具登录一下确认凭据是否还有效同时看一下设备上是否有限制登录IP的ACL。第二个是设备类型配置错误。比如你连的是华为设备但device_type填写的是cisco_iosNetmiko会一直等不到匹配的提示符直到超时。解决方法是查Netmiko官方文档的device_type列表逐一核对。第三个是网络不可达。这个不用多说先ping设备确认链路通。第四个是SSH服务未开启。有些设备默认只开启Telnet没有开启SSH需要用show ip ssh思科或display ssh server status华为确认。如果只开了TelnetNetmiko也支持device_type为cisco_ios_telnet但你需要在设备上配置transport input telnet并且要明确Telnet本身明文传输的风险建议仅在隔离的运维网段使用。第五个是网卡干扰。这个我前面提到过尤其是Windows控制机上如果有多个网卡或USB虚拟网卡路由会混乱。排查命令是route print -4看默认路由是否走了正确的接口。5.2 命令执行异常与设备兼容性为什么同一套脚本不同设备结果不同另一个高频问题是脚本在一台设备上正常换了一台设备就报错。原因往往是设备软件版本或命令语法不一致。比如有些老版本交换机不支持某些命令或者命令提示符格式不一样。我的建议是在设备清单里增加一个device_type字段的同时也增加一个version或者notes字段方便针对不同型号微调命令模板。还有一个隐蔽的坑是分页输出。默认情况下设备执行show running-config这类命令时如果内容超过一屏会进入分页交互模式底部出现--More--脚本会卡在这里。解决办法是在下发命令前先执行一条关闭分页的命令例如思科的terminal length 0华为的screen-length 0 temporary。conn.send_command(terminal length 0) conn.send_command(screen-length 0 temporary)如果设备始终无法完全关闭分页Netmiko的send_command也支持expect_string参数你可以让它匹配--More--然后自动发一个空格继续翻页但这种方式效率低且容易出错不建议作为首选。再来说说特殊字符的转义问题。在配置命令中如果包含!、%、$等特殊字符某些设备的CLI解析会出问题。另外Python字符串中的反斜杠、双引号也要特别小心。我的建议是所有命令优先使用列表格式传入send_config_set不要拼长字符串因为列表里每条命令就是设备上的一行输入逻辑清晰而且能避免很多转义问题。5.3 环境与依赖故障速查表下面这个表格是我在实际项目中整理的环境和依赖问题排查速查表遇到类似问题可以直接对照处理症状可能原因解决方案命令行敲python提示不是内部或外部命令Python未加入PATH重装Python并勾选“Add Python to PATH”或手动添加环境变量pip install安装包时提示“请安装缺失的包”当前终端未激活虚拟环境或pip与python解释器不匹配执行where python、where pip核对路径激活对应虚拟环境安装Netmiko时提示依赖冲突全局Python环境版本过旧或包混装用python -m venv venv创建全新虚拟环境再安装脚本连接设备一直卡住直到超时未关闭设备分页或device_type选择错误先手动SSH登录执行terminal length 0核对设备类型Windows下脚本连接正常但偶尔掉线多网卡或USB虚拟NDIS网卡抢路由禁用不使用的网卡检查route print默认路由运行时提示ModuleNotFoundError: netmiko虚拟环境未激活或依赖未安装激活虚拟环境后执行pip install netmiko设备能ping通但SSH连接失败设备未开启SSH或ACL限制检查show ip ssh、ACL、VTY配置最后再分享一个我个人的经验网络自动化项目的排查顺序永远遵循“先网络层、再认证层、再协议层、最后才是代码层”。先确认设备通不通、账号能不能登录再去看代码逻辑。很多人一上来就翻代码结果问题根本不在代码里。这个习惯能帮你省掉大量无效排查时间。这个项目其实只是一块敲门砖网络自动化的后续还能往很多方向延伸配置合规检查、配置变更工单联动、定时备份并用Git管理历史版本、把脚本封装成Web平台让同事自助操作。但无论扩展到哪里核心思路都是一样的把不可控的人工操作变成可控、可记录、可回滚的自动化流程。我实际用下来最大的感受就是自动化并不能消除网络故障但它能让你面对故障时手里多一张“能快速恢复现场”的底牌。最后再补一个小技巧批量执行完配置后一定要生成一份执行报告哪怕只是简单的TXT文件记录每台设备是成功还是失败、失败原因是什么。这既是给领导看的交付物也是给自己留的复盘材料。