尧图精选

Python网络设备自动配置实战:从手工SSH到批量脚本化运维

🕒 发布时间:2026/10/2 15:30:51 📁 来源:尧图网络
干网络运维这些年最让人头疼的其实不是那些复杂的协议原理而是每天重复敲命令。早上上班先登录三十几台交换机看状态、改端口、下发配置手输命令又慢又容易出错稍不留神还会在错误的设备上执行了不该执行的命令。后来我在项目里尝试用Python做网络设备自动配置把日常变更、批量配置、配置备份都写成了脚本设备配置时间从一上午压缩到十几分钟而且每一条命令都有执行日志可追溯、可回滚。这篇文章就围绕使用Python进行网络设备自动配置这件事把我实测过的方案、梳理过的原理、踩过的坑和可以直接抄的脚本都整理出来希望能帮到那些正在跟设备打交道、又不想继续手工敲命令的运维朋友。1. 为什么选择Python做网络设备自动配置1.1 手动配置的痛点效率、错误率与可追溯性先说个真实场景。之前接手过一批接入层交换机新项目上线要求统一修改所有接入口的描述、调整VLAN并关闭不用的端口。如果是手工操作我需要逐台设备SSH登录进入配置模式逐条敲命令再保存配置退出。每台设备大概二十分钟五十台设备就是将近十七个小时的重复劳动。如果中间接个电话或者同事问个问题很可能敲错命令比如把某台设备的端口误关了业务直接中断。这种事故在运维圈太常见了。手工配置的痛点归纳起来就这么几条效率低大量时间花在登录、翻页、等待回显上真正有价值的判断反而没时间做。出错率高人长时间做机械操作会疲劳命令错一个字母、IP写错一位都是炸雷。不可追溯谁在什么时间改了哪台设备、改了什么全靠聊天记录和人脑记忆。配置漂移设备初始配置一样经过几轮手工修改后每台设备的实际配置都不一样以后排障成本成倍增加。Python自动化解决的就是这四件事。脚本把命令批量发到设备速度是人工的几十倍命令写成模板同一批设备用同一套配置天然减少人为拼写错误脚本自带日志谁执行了、执行结果如何都有记录模板管理让设备配置状态可控漂移问题也能通过对比检测出来。1.2 Python生态带来的天然优势可能有人会问做自动化脚本Python、Shell、Expect、TCL不是都能干吗为什么最终选了Python我个人的体会是Python在这个领域已经不是能做而是大家都在做、生态已经成熟到可以少走弯路。网络自动化库齐全Netmiko封装了SSH连接和命令交互的细节NAPALM抽象了不同厂商的配置获取和下发接口Nornir把并行执行做到开箱即用。这些库不是玩具都是社区多年锤炼出来的连Juniper、Arista这类厂商的官方自动化方案里都有它们的身影。和现有运维体系好集成Python可以轻松读写文本、操作数据库、调RESTful API、对接Prometheus监控、生成Excel报表。也就是说配置脚本写完不是孤立的它可以挂在工单系统后面也可以跟资产管理系统联动向下发完配置向上回传执行结果。学习曲线友好网络工程师普遍不是专业程序员Python的语法接近自然语言两三周就能写出能跑的脚本。相比C和GoPython的胶水特性让你不需要关注内存管理和底层细节把精力集中在要对设备做什么上。社区资料足够多遇到问题搜一下基本都有答案网上有大量配置脚本、厂商设备类型对照表、报错解决方案。这意味着即使团队里只有一个人懂Python也能靠社区资源把自动化落地。如果拿手工配置和Python自动配置做对比差别就更直观了对比维度手工SSH配置Python自动配置50台设备批量改端口约8-16小时5-15分钟命令拼写错误风险高完全靠人低脚本统一生成操作留痕依赖手动记录自动生成日志并发能力同时只能操作1台可并发20-50台二次执行一致性很难保证脚本即模板结果一致我的建议是无论你现在是在做企业园区网还是数据中心网络只要设备数量超过二十台Python自动配置就值得投入。哪怕先从一个批量备份配置的小脚本开始也会立刻看到价值。2. 环境准备与工具选型2.1 Python环境搭建的正确姿势做网络设备自动配置第一步当然是装好Python环境。网络上关于Python安装的教程很多但针对运维场景我建议用比较稳妥的方式Python版本装3.8以上我用的是3.10。太老的版本在新库兼容性上会有问题太新的版本偶尔会遇到个别库没有及时适配3.10在该场景下属于稳妥选项。使用虚拟环境不要把依赖全局装进系统Python。网络上有太多装了一个包导致另一个项目跑不起来的教训虚拟环境就是给Python项目各自划一个独立房间。以Windows为例命令行执行python -m venv netauto_env netauto_env\Scripts\activateLinux或macOS则是python3 -m venv netauto_env source netauto_env/bin/activate虚拟环境激活后再安装项目依赖。核心库我一般这么装pip install --upgrade pip pip install netmiko napalm nornir如果你还用pandas处理设备台账、用openpyxl汇总配置结果那就一起装上pip install pandas openpyxl装完之后验证一下python -c import netmiko; print(netmiko.__version__)能正常输出版本号说明环境就绪。这一步看着简单但我见过不少同事栽在pip安装报错上绝大多数是因为网络源不稳定或者版本冲突换国内镜像源基本能解决pip install -i https://pypi.tuna.tsinghua.edu.cn/simple netmiko2.2 主流自动化库的选型思路Netmiko优先Python网络自动化生态里有几个常用库新手容易纠结到底用哪个。我做了几年自动化项目可以明确告诉你日常设备配置优先选Netmiko。先看四个主流选项库定位优点缺点Paramiko底层SSH库灵活、可控性强要自己处理命令交互、等待回显、分页开发量大NetmikoCLI自动化网络库封装了登录、分页、enable、保存等细节支持几十种厂商设备依赖厂商CLI命令变更需要同步更新NAPALM网络设备状态抽象层提供统一API获取配置、状态支持配置对比和回滚概念较重部分厂商支持不完整Nornir并行任务框架基于inventory管理设备天然并发适合大规模场景学习成本更高需要自己搭配Netmiko之类的库执行具体操作单说日常连上设备、敲命令、保存配置Netmiko是最省心的。它把很多容易出问题的细节都帮你处理了比如自动处理设备回显的翻页--More--不让命令卡住。自动识别enable模式下需要输入的密码。自动判断命令发送完毕的时机避免命令还在执行就发下一条。提供send_command和send_config_set两种方法分别对应普通命令和配置命令。Paramiko虽然灵活但你要自己去处理发命令-等回显-判断是否结束这个循环写起来很琐碎而且不同厂商设备的回显方式还不一样。我最早用Paramiko写过一套脚本后来切换到了Netmiko代码直接少了一半。如果做跨厂商的配置管理可以在Netmiko之上再封装一层自己的函数而不是直接上NAPALM。NAPALM适合需要统一获取设备状态、做配置合规检查的场景但它的配置下发依赖的是厂商专有格式实际用起来门槛不低。Nornir则适合设备数量几百台上千台的重度场景它负责并发调度真正连设备干活还是得靠Netmiko。所以我的结论是从Netmiko入手先把单设备配置、批量配置跑通再根据实际需求决定是否引入Nornir和NAPALM。3. 核心细节解析与实操要点3.1 连接设备时的关键参数与厂商适配Netmiko连接设备的入口是一个字典最关键的是device_type。这个参数决定了Netmiko以什么方式跟设备交互包括提示符的正则、命令发送的节奏、是否需要处理enable等。一个典型参数长这样from netmiko import ConnectHandler device { device_type: cisco_ios, host: 192.168.1.10, username: admin, password: StrongPass123, secret: EnableSecret456, port: 22, timeout: 30, session_log: device_192.168.1.10.log, fast_cli: False, }几个参数我展开解释一下device_type不同厂商不同型号对应的写法不同。思科IOS是cisco_ios华为VRP是huawei_vrp华三Comware是h3c锐捷是ruijie_osJuniper是juniper_junos。Netmiko的device_type列表可以在它的文档里查到用错会导致登录后无法正常执行命令这是最常见的坑之一。secret这是进入特权模式enable模式的密码。很多网络设备默认登录后是用户模式需要输入某个命令才能进入特权模式。Netmiko的enable()方法会使用secret这个字段来自动处理。session_log把整个交互过程保存为日志文件。我非常建议大家一开始就加上这个参数配置出问题的时候翻日志比看屏幕记录靠谱得多。fast_cli: 如果设备回显较慢或者网络延迟高把fast_cli设为False同时调大timeout可以避免命令执行超时中断。连接后先做基本探测这是好习惯conn ConnectHandler(**device) conn.enable() print(conn.send_command(show version))实操心得如果公司有堡垒机跳转环境建议先在本地网络内做连通性验证堡垒机本身会拦截直接的TCP连接这种场景下的自动化需要配合专门的API或代理组件不是Netmiko能单独解决的。3.2 普通命令与配置命令send_command和send_config_set的区别很多初学者不明白为什么要有两种命令发送方式直接把所有命令都丢给send_command。这其实是个大问题。send_command用来执行查看类命令比如show running-config、display current-configuration、show ip interface brief。这类命令不会改变设备配置执行结果作为回显返回。send_config_set用来执行配置类命令它会自动帮你在设备上进入配置模式然后把命令逐条下发最后退出配置模式。比如config_commands [ interface GigabitEthernet0/1, description uplink_to_core, ip address 10.0.0.1 255.255.255.0, no shutdown, ] output conn.send_config_set(config_commands)为什么不用send_command发送配置命令因为配置命令必须在正确的配置模式下执行顺序也不能乱比如先进入接口才会生效直接敲ip address会报错。send_config_set的存在就是让你专心写要做什么而不用关心怎么进入对应的配置层级这个底层细节。另外send_config_set支持从字符串或文件读配置适合配置模板比较多的情况# 从文件读取配置 with open(interface_config.txt) as f: config_commands f.read().splitlines() conn.send_config_set(config_commands)注意事项Netmiko发送完配置命令后默认会隐式执行一次end或exit返回普通模式所以随后再次调用send_command不会有还在配置模式里的问题。但如果手动切入了特殊视图比如configure terminal里面的接口视图建议在执行完配置后显式调用conn.exit_config_mode()保证状态干净。3.3 配置保存、备份与自动化的安全边界网络设备配置完毕必须保存否则设备重启后配置就丢了。不同厂商保存命令不一样思科是write memory或copy running-config startup-config华为是save华三是save force。Netmiko贴心提供了save_config()方法它会根据设备类型自动选择对应的保存命令save_output conn.save_config() print(save_output)配置保存之后的另一个重要动作是备份。我的习惯是任何变更操作之前先备份一次变更前的配置变更成功后再保存一份变更后的配置这样万一出问题可以快速对比差异和回滚。备份的核心思路很简单通过send_command抓取设备的完整配置写入本地文件import datetime now datetime.datetime.now().strftime(%Y%m%d_%H%M%S) config conn.send_command(show running-config) with open(fbackup_{conn.host}_{now}.txt, w, encodingutf-8) as f: f.write(config)更完善的做法是把每次备份都带上设备IP和日期戳并按日期归档形成历史配置库。做到这一步配置恢复就不再依赖谁有当时的记事本了。变更安全策略我总结成一句口诀先备份、再变更、后校验、可回滚。尤其是对生产网络设备一定不要在没做备份的情况下直接上脚本改配置。这是Python自动化落地过程中最重要的纪律比代码本身更值钱。4. 实操过程与核心环节实现4.1 单设备自动配置从登录到保存的完整脚本下面是一个可以直接参考的单设备自动配置脚本。假设我需要对一台思科交换机做端口配置完整过程包括登录、进入特权模式、下发配置、保存、断开连接from netmiko import ConnectHandler from netmiko.ssh_exception import NetmikoTimeoutException, NetmikoAuthenticationException device { device_type: cisco_ios, host: 192.168.1.10, username: admin, password: StrongPass123, secret: EnableSecret456, timeout: 30, session_log: switch_192.168.1.10.log, } config_commands [ hostname SW-ACCESS-01, interface vlan 10, ip address 10.10.10.2 255.255.255.0, no shutdown, interface GigabitEthernet0/1, description server-uplink, switchport mode access, switchport access vlan 10, no shutdown, ] try: conn ConnectHandler(**device) print(f成功连接到 {device[host]}) conn.enable() output conn.send_config_set(config_commands) print(配置下发完成输出如下) print(output) save_result conn.save_config() print(保存结果, save_result) conn.disconnect() print(已断开连接脚本执行完成) except NetmikoTimeoutException: print(f连接 {device[host]} 超时请检查网络连通性和端口) except NetmikoAuthenticationException: print(f连接 {device[host]} 认证失败请检查用户名密码) except Exception as e: print(f执行出错{e})这个脚本的执行逻辑很清晰建立连接 - 进入enable - 下发配置命令 - 保存 - 断开。异常处理主要抓了超时和认证失败两类这两类是网络运维自动化里最常见的失败场景。我在实际项目中还会在脚本里加一个input确认环节让操作员在脚本运行时二次确认要下发的设备IP和配置内容防止脚本从参数文件中读到了错误的设备信息。如果脚本是给变更工单系统调的这个确认环节可以换成从工单数据库读取并校验设备资产绑定关系。4.2 批量自动化配置从CSV台账驱动设备变更单台设备的自动化只是起步批量配置才是真正提升效率的地方。我用一个CSV文件维护所有设备的连接信息和要执行的命令然后脚本循环读取用线程池并发执行整体过程跑完只需几分钟。先看CSV台账的格式host,device_type,username,password,secret,commands 192.168.1.10,cisco_ios,admin,Pass123,Secret123,interface GigabitEthernet0/1|description web-server|switchport access vlan 20|no shutdown 192.168.1.11,cisco_ios,admin,Pass123,Secret123,interface GigabitEthernet0/2|description db-server|switchport access vlan 30|no shutdown 192.168.1.12,huawei_vrp,admin,Pass456,,interface GigabitEthernet0/0/1|description core-link|port link-type trunk|port trunk allow-pass vlan 10 20命令之间用|分隔脚本里再拆分成列表。批量脚本如下import csv from concurrent.futures import ThreadPoolExecutor, as_completed from netmiko import ConnectHandler from netmiko.ssh_exception import NetmikoTimeoutException, NetmikoAuthenticationException def configure_device(row): device { device_type: row[device_type], host: row[host], username: row[username], password: row[password], secret: row.get(secret, ), timeout: 30, session_log: flog/{row[host]}_session.log, } commands [cmd.strip() for cmd in row[commands].split(|) if cmd.strip()] try: conn ConnectHandler(**device) conn.enable() conn.send_config_set(commands) conn.save_config() conn.disconnect() return f{row[host]}: 配置成功 except NetmikoTimeoutException: return f{row[host]}: 连接超时 except NetmikoAuthenticationException: return f{row[host]}: 认证失败 except Exception as e: return f{row[host]}: 异常 {e} results [] with open(devices.csv, newline, encodingutf-8) as f: rows list(csv.DictReader(f)) with ThreadPoolExecutor(max_workers5) as executor: futures [executor.submit(configure_device, row) for row in rows] for future in as_completed(futures): results.append(future.result()) for r in sorted(results): print(r)这里有几个设计细节值得注意。并发数的选择max_workers5不是随便写的。并发太高设备CPU会被SSH登录进程打满尤其老设备容易死机并发太低又浪费了批量执行的时间。我一般根据设备型号和CPU配置来定接入交换机可以放到10核心设备建议一次只操作一台或者放在变更窗口外执行。网络设备的并发操作要比服务器自动化更保守复杂的业务系统不会因为SSH登录而卡死但老旧的交换机真会。日志目录脚本里用了log/目录存session日志这个目录要先建好。每个设备的会话日志都独立命名排障的时候直接看对应IP的日志不用到处翻。CSV编码问题CSV文件保存成UTF-8格式不要在Windows记事本里另存为带BOM的UTF-8否则第一行表头会多个看不见的字符导致字段解析出错。我在脚本里显式写了encodingutf-8如果你在Windows下遇到乱码改为encodingutf-8-sig就能兼容带BOM的文件。4.3 配置校验与回滚思路防患于未然批量下发配置后很多人以为脚本跑完就结束了其实真正的重点是校验和回滚。一种简单的校验方式是配置下发后重新抓取设备上的关键配置状态和预期值比对。比如修改了某个接口的VLAN就抓一下show running-config interface GigabitEthernet0/1检查里面是否包含预期的VLAN。Netmiko命令行比对代码如下expected switchport access vlan 20 actual conn.send_command(show running-config interface GigabitEthernet0/1) if expected in actual: print(f{conn.host}: 配置校验通过) else: print(f{conn.host}: 配置校验失败需要回滚)这个做法虽然朴素但在大多数场景下够用。如果要做更严谨的合规检查可以用NAPALM的get_config和compare_config来对比配置差异不过那套体系需要设备支持对应的NETCONF或专用API很多老设备不支持所以我先不展开。回滚的思路更简单就是把变更前的配置再推回去。如果变更前有完整备份那只要把备份里的接口配置提取出来重新下发到设备即可。实践中要注意的是回滚操作本身要快于变更操作因为业务已经受影响越早恢复越好。所以我会在变更前把回滚命令列表准备好而不是等出问题再临时去翻备份文件。我强烈建议在正式左右生产环境设备之前先在测试环境的同型号设备上完整跑一遍脚本包括回滚脚本。测试环境的设备少搞坏了也不影响业务这是成本最低的学习方式。我见过太多人第一版脚本直接上生产遇到设备提示符不匹配、命令被拒等问题时一脸懵幸好有回滚预案才没酿成大祸。5. 常见问题与排查技巧实录5.1 连接失败超时、认证、协议兼容网络设备自动配置最常见的问题就是连不上。我把遇到的典型失败场景和排查思路整理成了一个速查表现象可能原因排查与解决连接超时TimeoutExceptionIP不通、端口不对、防火墙拦截、设备SSH服务未开启先ping设备IP再用telnet或nc测试22端口是否通确认设备开启SSH服务检查管理VLAN和ACL认证失败AuthenticationException用户名密码错误、账户无SSH权限、AAA认证策略限制手工SSH登录一次确认凭据有效检查设备上是否有aaa authentication login限制确认密码字段支持特殊字符设备提示符不匹配device_type选错或设备回显格式特殊检查Netmiko的device_type列表选对厂商设备类型查看session_log里的实际提示符卡在--More--不继续分页未正确处理或设备类型不支持升级Netmiko到最新版如果是老设备设置global_delay_factor2或fast_cliFalse关于超时我再多说一句。有些网络设备开启SSH后第一次连接要做密钥交换慢一点的设备可能要十几秒。脚本里的timeout建议设置在30秒以上不要用默认值。如果是在跨地域的网络上操作延迟高出现超时的概率更大这时可以适当提高timeout或者在循环里加重试逻辑。5.2 命令下发异常乱序、少发、被设备拒绝命令下发的问题比连接问题更隐蔽。我遇到过的典型案例有三个一是设备回显慢导致命令被跳过。Netmiko判断命令是否执行完成的依据是检测设备提示符如果设备CPU繁忙回显迟迟没出来脚本可能认为超时然后继续发下一条结果后面的命令根本没到设备上。解决办法是调整延时参数conn ConnectHandler(**device, global_delay_factor2)global_delay_factor是Netmiko里的全局延时倍率值越大等待回显的时间越长。对老设备或者CPU占用率高的设备设为2或3很有效但不要设置太大否则脚本会变慢。二是配置命令不在正确的配置视图下执行。比如你要配置接口命令列表里先interface Gi0/1然后ip address x.x.x.x理论上没问题。但如果设备默认进入了某个子视图或者前面的命令失败导致当前视图不对后面的命令就会报错。排查方法是看session_log逐条比对设备回显是否出现% Invalid input之类的错误。三是批量模式下个别设备命令被拒但脚本没有停下来。Netmiko默认不会因为设备回显报错而中断脚本它会继续发后面的命令。这意味着如果前十台设备配置成功第十一台设备因为接口编号不同导致命令被拒脚本仍会继续往后跑。所以批量脚本一定要收集每台设备的回显输出等到全部跑完后统一检查而不是只看有没有异常抛出。5.3 脚本健壮性密码安全、执行幂等与日常运维纪律网络自动化脚本通常要存储设备密码这是绕不开的话题。直接写在脚本里最简单但也最不安全。我的建议是脚本里的密码从环境变量读取不要硬编码。CSV台账文件存放在访问受限的目录不要提交到代码仓库。有条件的话可以对接企业的密钥管理系统或堡垒机API让脚本运行时动态获取凭据。脚本的幂等性问题也值得关注。所谓幂等就是同一个脚本执行两次结果应该一致而不是第二次执行把设备搞坏。比如配置接口VLAN时如果设备上已经存在这个VLAN重复配置通常没问题但如果脚本里有no vlan 20这种命令第二次执行就会出问题。所以写配置命令时我习惯先检查设备当前配置再进行变更避免重复下发冲突配置。最后是日常运维纪律。自动化不是拿来炫技的它是运维流程的一部分。无论脚本多完善执行前都要做以下检查确认变更窗口和变更审批流程已走完。确认脚本读取的设备清单是当前准确的资产台账。确认备份已生成回滚方案已准备。执行过程中关注日志输出及时人工介入。我在实际项目中踩过一次大坑当时批量脚本跑了两百台设备中途有一台设备的接口名因型号差异写错了Netmiko没有报错导致那台设备实际没有完成变更但我误以为全部成功。从那以后我在每条配置下发后都加了一段从设备回显中检查配置是否生效的校验代码虽然速度慢了一点但心里踏实得多。网络自动化这件事脚本能力只占一半另一半是流程纪律和对设备细节的理解。写脚本不难难的是把每一步都设计得可验证、可回滚、可解释。这个思路贯穿了我后面所有的自动化项目也建议你从一开始就养好这个习惯。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →