ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python网络自动化实战:Netmiko批量配置与运维避坑指南

Python网络自动化实战:Netmiko批量配置与运维避坑指南 1. 从手工CLI到脚本下发网络自动化的痛点与Python生态的答案我在甲方运维干了快六年头三年几乎全是“人肉配置”。每次割接、设备上线、批量改端口都是同一套流程客户机开着SecureCRT一台台IP输过去用户名密码打一遍然后对着需求表复制粘贴命令。十台以内的设备还能扛一旦超过三十台后半夜就是拼手速和拼耐力。最要命的是人一旦疲劳极容易犯低级错误——我印象最深的一次某台交换机该配在VLAN 103的端口配到了VLAN 101表面看不出问题第二天业务流量全走错了段排查了一个上午才定位。后来我开始认真研究用Python做网络设备自动配置目的很直接让机器替我干这种重复、机械、高风险的活。这两年走下来从最开始的Paramiko裸脚本到Netmiko封装的连接会话再到把配置备份、下发、校验、回滚串成一条自动化流水线单台设备的配置操作时间从两分钟缩到了两三秒而且每一次操作都会留下日志和配置快照。这篇文章不打算聊那种“自动化运维概念”的空话就把我自己在真实生产环境里做网络设备自动配置的完整经验写下来环境怎么搭、脚本怎么写、哪些坑真的会让你半夜爬起来以及怎么让自动化配置不变成自动化事故。1.1 手工配置的隐性成本很多人觉得手工配置也就多花点时间没什么大不了。但我把真实账单摆出来你就知道问题有多严重。单台交换机做一个简单VLAN配置从登录到输入命令再到验证熟练工最快也要两分钟。二十台设备就是四十分钟起步这还建立在网络稳定、命令没输错的前提下。可实际上人的注意力在两小时后就开始明显下降一次割接窗口通宵干下来错配的概率真的不低。我统计过自己经手的变更单手工阶段几乎每个月都有一次因配错引发的临时故障而用脚本批量配置之后半年都遇不到一次。除了效率手工配置还有一个隐性问题没有可审计的记录。每个人敲了什么命令、什么时候敲的、执行结果如何全凭操作者事后拼截图。一旦出了事故复盘全靠回忆。脚本自动配置天然就有日志每条命令的执行时间和返回结果都可以完整落盘这对事后追溯是决定性差异。1.2 Paramiko、Netmiko、NAPALM怎么选Python做网络设备自动化最常用的三套东西是Paramiko、Netmiko、NAPALM。很多人上来就问哪个最好我的答案是看你的目标离“命令”有多远。Paramiko是一个纯SSH协议库它本身不懂交换机、路由器的任何概念。你给它一台设备的IP和SSH凭据它就能开一个交互式shell然后由你用代码控制“发一条命令、收一段回显”。它的优势是底层、灵活任何支持SSH的设备都能连劣势也明显——你要自己处理命令提示符变化、分页输出、超时重试这些脏活。我最早写网络脚本就是从Paramiko入门的当时连华为设备分页都要手动处理那叫一个痛苦。Netmiko是在Paramiko之上做了一层网络设备适配的封装库它把所有脏活都干了连接时自动识别提示符、关闭分页、处理认证、区分配置模式和普通执行模式。你只需要告诉它设备的厂商型号比如cisco_ios、huawei、hp_comware剩下的交互细节它自己搞定。这是目前做命令行批量配置最顺手的选择也是我日常的主力工具。NAPALM则更往上一层。它把“配置”这件事抽象成了统一API不管底层是思科还是华为你都调用一样的commit方法下发配置。它的价值在于跨厂商一致性尤其适合做配置合规巡检和状态比对。但它对设备命令的掌控力偏弱要下发非常具体的某条CLI命令时反而绕。所以我的选型逻辑是核心做批量下发、日常变更选Netmiko需要自动化对比设备状态、做跨品牌合规检查选NAPALM有些偏门设备Netmiko不支持再用Paramiko手写兜底。工具链不冲突可以混着用。2. 环境搭建Python运行环境与设备连接参数的细节2.1 Python环境与依赖库安装先聊环境。很多新手栽的第一步不是代码而是电脑上的Python压根没装好。由于设备脚本大多跑在Windows跳板机或Linux运维机上我建议你直接用官方安装包装Python 3.10以上版本安装时记得勾选“Add Python to PATH”选项。没有这一步后面在命令行里敲python会直接提示找不到命令这也是技术人员最常遇到的环境问题。装好Python之后建议给项目单独建一个虚拟环境不要把依赖库直接装到全局环境里避免不同项目之间冲突。python -m venv netauto netauto\Scripts\activate # Windows # source netauto/bin/activate # Linux / macOS pip install --upgrade pip pip install netmiko pandas openpyxl装完用一句话验证Netmiko能不能导入python -c from netmiko import ConnectHandler; print(ok)如果看到ok说明环境通了。pandas和openpyxl是后面读设备清单用的现在一起装掉免得后面再折腾。这里我想多说一句千万不要在公司生产环境的系统Python里直接pip install一大堆库你永远不会知道某个服务会不会依赖特定版本的第三方包。虚拟环境虽然多花十几秒但能帮你避开无数脏事。2.2 连接参数详解device_type、超时、密钥与分页Netmiko连接一个网络设备核心就是一个字典类似这样from netmiko import ConnectHandler device { device_type: huawei, host: 192.168.1.10, username: netadmin, password: YourPassword, port: 22, timeout: 30, } conn ConnectHandler(**device) output conn.send_command(display version) print(output) conn.disconnect()这段代码几乎就是所有脚本的地基。里面的字段一个都不能想当然。device_type是最容易填错的一项。它告诉Netmiko对面设备是什么系统Netmiko才能用对应的提示符规则和命令模式逻辑去交互。常见取值有cisco_ios思科IOS、huawei华为VRP、hp_comware华三/HP Comware、ruijie_os锐捷、juniper_junos瞻博网络。选错类型Netmiko连接后识别不了提示符脚本会一直等直到超时报错。遇到“Read timeout”这类错误时先别怀疑网络不通检查一下device_type是不是写对了。password是登录密码仅适用于普通用户模式。但很多思科设备进入特权模式还要单独的enable密码这种情况下需要在设备字典里增加一个secret字段并在连接后调用conn.enable()。华为设备则通常不需要单独的enable密码只要用户权限够大进入system-view直接配。这一段我后面还会专门展开说说因为我在生产环境里确实被它坑过。timeout默认是20秒我建议调成30秒。有些老设备CPU负载高SSH握手和命令回显都比较慢超时太短会导致连接或命令执行阶段直接断掉。连接成功后netmiko内部会自动执行关闭分页的指令比如思科的terminal length 0华为的screen-length 0 temporary。这一步你不用写但需要知道它的存在否则命令输出内容超过一屏设备会停在“-- More --”状态脚本就会一直卡住等提示符。后面排查问题时第一个联想到的就是分页。2.3 连接失败三类典型问题的排查我帮同事排过很多次连接失败的坑总结下来无非三类。第一类Connection timed out。意思是TCP连接都没建立起来。优先检查设备IP是否能ping通、SSH服务有没有开启、ACL是否限制了管理网段来源。很多华为新设备默认只开放了Telnet没开SSH这时候Python脚本连不上但人拿Telnet可以登。解决方法是去设备上开SSH或者改为用Telnet连接不过生产环境建议一律SSH。第二类Authentication failure。用户名或密码不对也可能账号被锁定。这种报错很直观一般就是凭据问题。但有一种情况容易被忽略某些设备会把错误密码尝试记入日志连续失败几次后临时锁IP。所以排错时先看设备日志确认不是自己做测试时把对端账号锁了。第三类Netmiko提示提示符无法识别或者一直卡住。这种通常是device_type写错或者设备是非标准系统比如某款交换机系统是深度定制的Linux但对外接口根本不是标准CLI。遇到这种要么换Paramiko手写要么要求厂商提供标准访问方式。我建议你把三类报错记在案头因为网络自动化百分之八十的问题都发生在连接这一层连接通了后面基本就是顺水推舟。3. 写一个能直接用的批量配置脚本场景、代码与产物3.1 场景目标20台办公网交换机的VLAN配置理论说完了直接上一个真实场景。公司办公网扩容新上线一批接入交换机你需要做三件事创建VLAN 100并命名为OFFICE_VLAN把下联终端的端口配成access口并划入VLAN 100最后保存配置。设备是华为VRP系统共20台IP从192.168.1.11到192.168.1.30统一账号密码。如果你手工做一台设备至少三分钟20台就是一个小时。但用Netmiko跑批量脚本一分钟内全搞定还能自动把每台设备的执行结果写进文件。3.2 send_command与send_config_set的配合逻辑Netmiko最常用的两个方法是send_command和send_config_set。新手最容易分不清它们的区别。send_command用于在普通用户或特权模式下执行单条查询类命令比如display version、display interface brief。它的特点是命令立即返回结果不改变设备的运行配置。send_config_set用于进入配置模式后批量下发一组配置命令。比如华为设备我们需要先system-view进入系统视图然后创建VLAN、进入接口、设置端口模式。send_config_set会一条条发送命令并自动处理每条命令之间的模式切换。实际写脚本时我的习惯是这样的from netmiko import ConnectHandler def config_switch(host: str, username: str, password: str, log_file): device { device_type: huawei, host: host, username: username, password: password, port: 22, timeout: 30, } conn ConnectHandler(**device) commands [ system-view, vlan 100, name OFFICE_VLAN, quit, interface GigabitEthernet0/0/1, port link-type access, port default vlan 100, quit, return, ] output conn.send_config_set(commands) log_file.write(f {host} 配置结果 \n) log_file.write(output \n) save_output conn.send_command(save, expect_stringr\[Y/N\]) log_file.write(save_output \n) if Y/N in save_output: save_output conn.send_command(Y, expect_stringr\) log_file.write(save_output \n) conn.disconnect() return host这里有几个关键点。send_config_set执行完后设备还停留在配置模式我特意在commands末尾放了一个return把设备退回到用户视图这样再执行save时不会因为模式不对而出错。save命令在华为设备上会问“Are you sure to continue?[Y/N]”所以用expect_stringr[Y/N]等待提示符收到后回一个Y再等待设备回到用户视图的提示符。这种做法叫做“交互式应答”在没有人为干预的脚本里非常重要。3.3 批量执行、异常捕获与日志记录单台设备的函数写好之后批量其实就是一个循环加异常捕获的问题。import datetime devices [ {host: f192.168.1.{i}, username: netadmin, password: pass123} for i in range(11, 31) ] log_name datetime.datetime.now().strftime(%Y%m%d_%H%M%S) _batch_config.log with open(log_name, w, encodingutf-8) as log_file: for d in devices: try: result_host config_switch(d[host], d[username], d[password], log_file) print(f[OK] {result_host} 配置完成) except Exception as e: print(f[FAIL] {d[host]} 失败{e}) log_file.write(f[FAIL] {d[host]} 失败{e}\n)我在生产环境里跑这个脚本时最大的感受是设备越多循环越要写得保守。每台设备之间不要追求极致速度因为有时候上一台刚配置完设备还在保存配置写flash紧接着连下一台没有问题但如果你的下一步是开启线程池并发执行几十台后面第四小节我会讲这是怎么把设备SSH拖死的。异常捕获这块必须注意千万不要让一台设备的失败中止整个任务。我会在except分支里记录失败的IP和错误信息全部跑完后统一处理。这样即使有一两台设备密码过期或网络抖动剩下的任务仍然继续执行不会因为一台故障把整批都停了。3.4 配置变更是即时生效的保存步骤不能省很多刚接触自动化的同行会忽略save这一步觉得命令执行完就收工了。这个认知非常危险。网络设备的配置分为“当前运行配置”和“启动配置”两份默认下发的命令只存在于内存里一旦设备重启所有配置全部丢失。批量配置中如果设备后来因为断电重启结果配置全没了你连是哪台设备丢的都不好追溯。所以我要求脚本里一定包含保存步骤并且在每台设备配置结束后立刻保存。顺序不能反过来否则如果设备配置过程崩溃保存的旧配置会覆盖新配置反而造成更大的问题。脚本跑完后你应该能看到一个带时间戳的日志文件里面记录每台设备的每步执行回显。这份日志务必要归档好它就是你这次变更的审计记录。后期一旦出现问题翻日志比翻聊天记录高效一万倍。4. 让自动配置不出事故备份、校验与回滚三板斧4.1 下发前自动备份自动配置最大的心理障碍是“怕改坏”。我第一次用脚本跑几十台设备的配置变更前整整犹豫了一个下午最后派生的经验是给自动配置配上备份、校验、回滚三板斧安全感立刻就有了。所谓备份就是在任何修改性命令下发之前先把设备的当前配置拉下来存到本地文件。Netmiko里做这个非常简单def backup_config(conn, host, backup_dir): conn.enable() config_text conn.send_command(display current-configuration) filename f{backup_dir}/{host}_{datetime.datetime.now().strftime(%Y%m%d_%H%M%S)}.cfg with open(filename, w, encodingutf-8) as f: f.write(config_text) return filename每次变更前先循环调用这个函数确保每台设备的旧配置都有备份。这个习惯成本极低但收益极大。一旦变更后出现异常你可以拿着备份配置直接恢复。备份文件命名我强烈建议用“设备IP日期时间”的组合不要只用IP否则同一天多次变更时文件会被覆盖历史版本就丢了。如果文件很敏感也可以再加密归档。4.2 配置后的结果校验光备份还不够你得确认配置确实生效了。校验的方式是在配置命令执行完后重新查询设备状态和预期结果做比对。比如我们刚才配置了VLAN 100那么校验命令就是display vlan 100脚本解析输出看VLAN名称和VLAN ID是否匹配预期。def verify_vlan(conn, vlan_id100, expected_nameOFFICE_VLAN): output conn.send_command(fdisplay vlan {vlan_id}) return expected_name in output如果返回值是False说明这台设备配置可能没生效需要把这台设备加入“异常清单”人工重点排查。这样可以第一时间发现问题而不是等到业务中断了才被动响应。校验比备份进了一步备份是事后补救校验是事中发现。在批量场景里两者配合使用基本能把风险控制在一个可以接受的范围内。4.3 回滚到底怎么设计才靠谱回滚方案的设计取决于设备能力。华为、思科这类支持“加载启动配置覆盖当前配置”的设备可以用一条命令回滚def rollback_config(conn): conn.send_config_set([rollback] if isinstance(conn, ...) else [ system-view, load configuration laststartup, Y, ]) conn.disconnect()但不同厂商命令差异大我这里不推荐直接粘贴一段通用回滚代码。真正稳妥的回滚是两层第一层是“局部回滚”。比如我们只改了某个接口的VLAN回滚就是把这一段配置恢复成备份前的设置。这种回滚只影响本次变更涉及的接口风险小。实操上就是从备份文件里提取对应接口的配置用send_config_set下发回去。第二层是“整机回滚”。如果本次变更把设备搞得面目全非局部回滚已经不够那就把备份的完整配置文件推送回设备覆盖当前配置后保存。这个动作比较重可能导致设备短暂中断业务所以只能作为最后手段。还有一个特殊的“自动回滚”思路在批量脚本中每台设备配置完成后立即校验如果校验失败就立刻回滚该台设备不让错误配置留在设备上过夜。这个方法我在电信级设备上用过前提是设备支持两阶段配置提交比如思科IOS的archive功能或华为的配置回滚点机制。如果你的设备不支持就用备份校验的方式至少能在事故放大的前一小时发现。5. 运维中踩过的五个坑排查链路与最终解法5.1 跨厂商命令差异华为、思科、锐捷混编环境网络环境很少只有单一厂商。我见过最复杂的办公网络核心是思科接入是华为还有一角落是锐捷。想用一个脚本吃遍所有设备最不现实的假设就是相同命令在不同设备上都能执行。比如查看接口列表思科是show ip interface brief华为是display interface brief。创建VLAN思科是vlan 100华为是vlan 100但接口下要设置port link-type access锐捷则还要先开启端口模式。命令体系差异非常大。我的解决方案是“一个会话层封装多套命令层模板”。会话层统一用Netmiko连接命令层按device_type分别定义不同设备要执行的命令列表放到一个字典里from netmiko import ConnectHandler command_templates { cisco_ios: { create_vlan: [vlan 100, name OFFICE_VLAN], set_access_port: [interface GigabitEthernet0/1, switchport mode access, switchport access vlan 100], }, huawei: { create_vlan: [system-view, vlan 100, name OFFICE_VLAN, quit], set_access_port: [system-view, interface GigabitEthernet0/0/1, port link-type access, port default vlan 100, quit], }, }然后在业务逻辑层根据每台设备的device_type取对应的命令清单。这样做虽然前期要花时间梳理命令但后续扩展新厂商时只需要加一个模板不用动主体脚本。我在维护一套约300台混合厂商设备的时候就是靠这套方式活下来的。5.2 enable密码与特权模式思科设备让我吃过大亏。Netmiko连接其交换机后初始处于用户模式提示符是hostname。这个模式下你几乎什么都干不了必须输入enable进入特权模式。如果设备配置了enable密码而连接参数里没有提供secretNetmiko的send_command在需要特权指令时就会卡住或者报权限错误。排查链路是这样的先看脚本报错位置如果卡在第一个需要特权权限的命令八九不离十是enable没成功。解决方法是连接参数里补secret字段并在需要时手动调用conn.enable()。device { device_type: cisco_ios, host: 192.168.1.10, username: netadmin, password: login_pass, secret: enable_pass, timeout: 30, } conn ConnectHandler(**device) conn.enable()华为设备虽然没有独立的enable密码但它要求登录用户拥有管理级权限。如果你用了一个只读权限账号去执行system-view设备会直接拒绝。这种问题脚本报错不太明显通常是一片权限拒绝信息。所以批量配置前确认账号权限是管理员级别是基本功。5.3 输出乱码、分页死锁与终端宽度华为设备默认输出是中文或者英文这取决于设备的语言配置。我遇到过一批设备的display命令回显夹杂中文乱码就是因为本地终端编码和设备实际输出编码不一致。Netmiko本身以文本方式接收如果设备输出GBK而你的脚本按UTF-8解析就会出现乱码。处理方法是尽量让设备输出英文。华为设备可以执行lang English或类似的命令切换语言思科本身默认英文问题不大。如果实在切不了就在读取结果后用encodinggbk方式做解码转换但你要先确认设备到底输出的是什么编码。分页死锁是另一个高频坑。虽然Netmiko默认会关闭分页但某些设备在非标准配置下可能仍会输出--More--提示符且不退出。排查链路是脚本长时间无响应此时手动到设备上查看是否停在More状态。解决办法在连接后主动补一条关闭分页的命令比如华为的screen-length 0 temporary思科的terminal length 0再执行后续命令。终端宽度问题较少见但如果遇到过长的配置行设备为了适配宽度会自动折行导致配置解析错乱。这个可以在关闭分页时同时设置宽度华为设备是screen-width 0值得一并处理。5.4 并发过高把设备SSH拖死刚开始做批量配置的同行看到几十台设备一台台跑总觉得太慢于是想把ThreadPoolExecutor搬出来并发二十个线程同时连设备。我第一次这么干时效果确实快但一台老式的千兆接入交换机直接就SSH会话数爆满新连接被拒显示Max session limit reached。更麻烦的是有些设备在并发下会panic需要重启才能恢复。排查链路第一批并发连接成功后后续连接大面积失败设备侧日志提示会话数超限。解法很简单控制并发数一般五到八个并发是相对安全的阈值。另外每个线程都要有自己的独立连接绝不能多个线程共用一个连接对象。Netmiko的连接不是线程安全的。如果实在追求速度我的做法是用队列固定worker数from concurrent.futures import ThreadPoolExecutor with ThreadPoolExecutor(max_workers6) as executor: futures [executor.submit(config_one_device, d) for d in devices] for future in futures: future.result()这样既能提速又不至于把设备拖垮。设备性能越差worker数越要调低宁可多等几分钟也不冒设备重启的风险。5.5 脚本中断留下半截配置脚本跑到一半突然断电、SSH断连、或者你手贱按了CtrlC设备可能停留在配置模式或者只执行了一半命令。这种情况最可怕因为没人知道设备当前处于什么状态。我的建议分三层第一脚本内部做断点续跑很困难不如每台设备配置完成后立即打印或记录完成状态跑挂之后从日志看哪些设备已完成、哪些没完成然后手工或再次脚本只补未完成的部分。第二在设备侧让配置变更具有“幂等性”也就是说同一段配置重复执行两遍不会产生副作用。比如创建VLAN并设置端口第二遍执行时设备会提示VLAN已存在但不会影响最终状态。第三所有变更都先备份确保在任何异常情况下都有兜底恢复路径。我自己现在已经养成了一个习惯任何自动变更脚本第一行注释永远写着“先备份后变更再校验”。这句话在实践中救过我很多次。6. 从单次脚本到日常自动化设备清单、定时任务与平台化6.1 用Excel管理设备清单pandas批量读取单次跑脚本时设备信息写在Python列表里没问题。但日常运维要管理几百台设备设备清单就必须结构化。最常见的做法是用Excel维护一张表列为设备IP、设备类型、管理用户名、管理密码、所属机房、变更分组、备注。然后用pandas读取。import pandas as pd df pd.read_excel(devices.xlsx, dtype{host: str}) for row in df.itertuples(): device { device_type: row.device_type, host: row.host.strip(), username: row.username.strip(), password: str(row.password).strip(), timeout: 30, } # 调用你的配置或备份函数这张表平时由运维人员维护脚本只负责读表跑任务。这样设备的新增和下线不需要修改任何代码只要更新Excel就行。密码字段我建议在Excel里用文本格式避免被科学计数法或前导零问题干扰。如果你所在公司已经有CMDB或者资产管理系统完全可以用API把这张设备清单对接给Python。很多企业内网设备清单都存在数据库里用Python连数据库拉取的方式本质上就是把“人维护Excel”换成“系统自动同步”下一篇我会细聊这个方向。这里只需要知道脚本只依赖输入数据数据源怎么变都行。6.2 定时任务的组合每天备份周度巡检设备清单有了下一步就是让任务自动跑起来。我的建议是先从“备份”这种只读任务开始做它风险低、收益明确、领导也容易看到价值。用APScheduler做定时任务非常方便它支持cron表达式可以精确控制执行时间而且不会像crontab那样跟系统环境差异纠缠太多。from apscheduler.schedulers.blocking import BlockingScheduler def daily_backup(): # 读取设备清单逐一备份配置 pass def weekly_inspect(): # 检查所有设备CPU、内存、接口状态 pass if __name__ __main__: scheduler BlockingScheduler() scheduler.add_job(daily_backup, cron, hour1, minute0, idbackup) scheduler.add_job(weekly_inspect, cron, day_of_weeksun, hour2, minute30, idinspect) scheduler.start()定时任务跑起来之后建议把执行报告发送到运维消息群或者发邮件。我早期只把结果写到本地文件结果连续三天没人看后来加了告警推送一条异常配置当天就被我同事发现避免了一次扩大化故障。6.3 下一步对接公司系统自动拉取设备清单聊到这里从单脚本到定时任务已经能解决大部分网络自动化的日常需求了。如果再往前走一步就是把设备清单的来源从Excel变成公司系统数据源。比如公司CMDB里维护了每台设备的责任人、所属业务、维保状态脚本直接查询CMDB接口只提取“需要纳管”的那批设备做自动巡检。好处是不用重复维护Excel设备状态永远和系统一致。这一步从技术实现上讲并不复杂无非就是用requests或SQLAlchemy去拉数据替换掉pandas读取Excel这一段。真正复杂的是组织协作需要和系统负责人确认数据字段含义、账号权限、接口调用频率。我的建议是先用Excel把整个流程跑通再谈接口对接不要一上来就搞平台化很容易陷入需求黑洞。这几年的运维实操下来我的体会是网络设备自动配置真正的价值不在于省下的那点时间而在于它把“人的不确定性”从配置过程里剥掉了。机器不会困不会烦不会把VLAN配错前提是你把备份、校验、回滚这三件事做成固定动作。最后再分享一个小技巧任何自动配置脚本上线前先拿一台空闲测试设备完整跑三遍确认无副作用后再扩大到生产设备池。这一条帮我挡住了至少五次可能演变成重大事故的变更希望你也能用上。
返回列表