1. 为什么批量升级固件这件事值得认真对待
手里管着几十台接入层交换机,每次固件升级都是一场硬仗。厂商发来安全通告说某个版本修复了若干缺陷,你看着机房里那一排排设备,心里盘算的是:一台一台手动传固件、改启动项、重启、验证,每台至少十五分钟,中间还容易因为手抖敲错命令导致设备起不来。更麻烦的是,有些设备在偏远的分支节点,去一趟现场的成本比设备本身还高。
这个项目要解决的就是这个场景下的效率和安全问题。核心思路是利用华为S5700系列交换机支持的SFTP文件传输和自动化脚本执行能力,通过一台跳板机批量完成固件上传、校验、启动项切换和重启验证的全流程。适合手里有华为S5700系列设备、需要定期做固件维护的网络运维人员参考。不管你是刚接手网络运维的新手,还是已经管过几年设备的老手,这套方法都能帮你把升级窗口从半天压缩到一两个小时以内。
我自己的习惯是,每次升级前先把所有设备的当前版本、运行时间、Flash剩余空间拉一遍清单,确认没有设备处于异常状态再动手。这个习惯救过我至少两次——有一次发现一台设备的Flash只剩不到10MB,根本放不下新固件,如果直接批量推上去,那台设备必然升级失败。
2. 升级前的环境摸底与风险排查
2.1 设备型号与固件兼容性确认
华为S5700系列下面细分了很多子型号,比如S5700-28C-SI、S5700-52C-EI、S5700S-28P-LI等等。不同子型号支持的固件文件可能不同,SI版本和EI版本的功能集差异很大,固件包不能混用。我见过有人把EI的固件推到SI设备上,结果设备重启后直接进入异常状态,只能通过Console口恢复。
确认兼容性的方法很简单,登录设备后执行:
display version输出里会显示设备的具体型号和当前运行的固件版本。把型号记下来,去厂商的固件发布说明里核对支持的型号列表。这一步不能偷懒,因为有些固件包的文件名很相似,比如S5700_V200R019C10SPC500.cc和S5700SI_V200R019C10SPC500.cc,差一个后缀就是不同平台。
另外要注意固件的补丁依赖关系。有些新版本固件要求先升级到某个中间版本才能继续升到目标版本,不能跨版本直接升级。这个信息通常在固件发布说明的"升级注意事项"章节里,升级前一定要通读一遍。
2.2 Flash空间与文件系统检查
S5700系列不同型号的Flash容量差异很大,低端型号可能只有64MB,高端型号有128MB甚至更大。新固件包通常在30MB到60MB之间,加上系统预留空间,如果Flash剩余空间不足,上传会直接失败。
检查命令:
dir flash:/输出会列出当前Flash里的所有文件和剩余空间。重点看两个东西:一是剩余空间是否大于固件包大小的1.5倍(留出解压和临时文件的空间),二是当前系统文件的名字,后面切换启动项的时候要用到。
如果空间不够,需要先删除旧版本的固件文件。但注意,不要删除当前正在运行的固件文件,否则设备重启后会找不到系统。安全的做法是先把新固件传上去,确认校验通过后再删除旧文件。
2.3 配置备份与回退方案
升级前必须做配置备份,这是铁律。备份分两步:一是把当前配置文件导出到本地,二是确认设备上保留了配置文件的副本。
导出配置的命令:
display current-configuration把输出完整保存到本地文件。更稳妥的方式是用SFTP把vrpcfg.zip文件下载下来:
sftp 192.168.1.100 put vrpcfg.zip backup/vrpcfg_20250101.zip回退方案也要提前想好。如果升级后设备异常,需要能快速恢复到旧版本。这就要求旧固件文件在升级后不要立即删除,至少保留到新版本稳定运行一周以上。同时确认设备的启动项可以手动切换,万一新版本起不来,通过Console口连上去改启动项还能救回来。
3. 自动化升级的核心机制拆解
3.1 SFTP传输通道的建立逻辑
S5700系列交换机支持作为SFTP客户端主动连接外部服务器,也支持作为SFTP服务器被连接。批量升级的场景下,通常是把跳板机作为SFTP服务器,交换机作为客户端去拉取固件文件。
为什么选SFTP而不是FTP?因为SFTP基于SSH协议,传输过程加密,而且可以复用SSH的认证体系。在设备上配置SFTP客户端只需要几条命令:
sftp client-transfile然后指定服务器地址、用户名、密码和文件路径。实际配置的时候,我建议把密码用密文形式存储,避免配置文件里出现明文密码。华为设备支持用cipher参数对密码进行加密:
sftp client-transfile username admin password cipher %^%#xxxxx%^%#传输大文件的时候,建议加上timeout参数,防止因为网络抖动导致传输中断后设备一直卡在那里。我一般设成300秒,超过这个时间没传完就自动断开,然后脚本可以重试。
3.2 固件校验的三种手段
固件传上去之后不能直接切启动项,必须先校验。校验手段有三种,建议至少做前两种:
第一种:文件大小比对。上传完成后执行dir flash:/,看新固件文件的大小是否和本地源文件完全一致。差一个字节都不行,说明传输过程中可能出了错。
第二种:MD5校验。华为设备支持对Flash里的文件计算MD5值:
md5sum flash:/S5700_V200R019C10SPC500.cc把输出和本地文件的MD5值比对。这个步骤能发现文件内容层面的损坏,比单纯比对大小可靠得多。
第三种:CRC校验。部分固件包自带CRC校验文件,上传后设备可以自动校验。这个取决于固件包的格式,不是所有版本都支持。
我自己的流程是:先比对大小,再算MD5,两个都过了才继续下一步。有一次传输过程中网络闪断,文件大小对上了但MD5不对,幸好做了双重校验,否则切了启动项重启后设备直接变砖。
3.3 启动项切换与重启策略
校验通过后,修改启动项指向新固件:
startup system-software flash:/S5700_V200R019C10SPC500.cc这条命令执行后,设备会提示确认。确认后启动项就改好了,但还没有生效,需要重启才会加载新固件。
重启策略要分场景。如果是单台设备,直接reboot就行。如果是批量设备,建议分批重启,每批之间留出足够的观察时间。我的做法是每批不超过5台,重启后等5分钟,确认这批设备都正常起来了再推下一批。这样万一新固件有问题,影响面可控。
重启命令执行前,务必确认配置已经保存:
save然后:
reboot设备重启过程中,可以通过Console口或者带外管理口观察启动日志。如果新固件加载失败,设备会自动回退到备用启动项(前提是配置了备用启动项)。所以升级前建议配置好备用启动项:
startup system-software flash:/old_version.cc backup4. 批量执行的脚本化实现
4.1 用Python Paramiko做SSH批量操作
批量升级的核心工具是Python的Paramiko库,它可以通过SSH协议连接设备并执行命令。相比Expect脚本,Paramiko的异常处理更完善,适合生产环境。
先安装依赖:
pip install paramiko然后写一个基础的连接和执行函数:
import paramiko import time def execute_commands(host, username, password, commands): client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: client.connect(host, username=username, password=password, timeout=30) shell = client.invoke_shell() time.sleep(2) output = "" for cmd in commands: shell.send(cmd + "\n") time.sleep(3) while shell.recv_ready(): output += shell.recv(65535).decode('utf-8', errors='ignore') return output except Exception as e: return f"ERROR: {str(e)}" finally: client.close()这个函数的关键点是invoke_shell(),它模拟了一个交互式终端,可以处理需要确认的命令(比如save和reboot)。time.sleep(3)是给设备留出执行命令的时间,具体数值根据设备响应速度调整。
4.2 设备清单与并发控制
设备清单建议用CSV文件管理,每行包含IP、用户名、密码、当前版本、目标版本:
ip,username,password,current_version,target_version 192.168.1.1,admin,password1,V200R019C00,V200R019C10 192.168.1.2,admin,password2,V200R019C00,V200R019C10读取清单的代码:
import csv def load_devices(csv_file): devices = [] with open(csv_file, 'r') as f: reader = csv.DictReader(f) for row in reader: devices.append(row) return devices并发控制很重要。不建议一次性对所有设备发起连接,因为跳板机的资源有限,而且设备侧也可能限制并发SSH会话数。我的做法是用线程池,最大并发数设成10:
from concurrent.futures import ThreadPoolExecutor with ThreadPoolExecutor(max_workers=10) as executor: futures = [executor.submit(upgrade_device, dev) for dev in devices] for future in futures: print(future.result())4.3 升级流程的完整脚本框架
把前面的模块串起来,形成一个完整的升级脚本:
def upgrade_device(device): ip = device['ip'] username = device['username'] password = device['password'] target_fw = device['target_version'] # 第一步:检查当前版本 output = execute_commands(ip, username, password, ["display version"]) if target_fw in output: return f"{ip}: already on target version, skip" # 第二步:检查Flash空间 output = execute_commands(ip, username, password, ["dir flash:/"]) # 解析剩余空间,判断是否足够 # 第三步:上传固件 upload_cmd = f"sftp client-transfile get {target_fw}.cc flash:/{target_fw}.cc" output = execute_commands(ip, username, password, [upload_cmd]) # 第四步:校验MD5 output = execute_commands(ip, username, password, [f"md5sum flash:/{target_fw}.cc"]) # 比对MD5值 # 第五步:切换启动项 output = execute_commands(ip, username, password, [ f"startup system-software flash:/{target_fw}.cc", "y" ]) # 第六步:保存配置 output = execute_commands(ip, username, password, ["save", "y"]) # 第七步:重启 output = execute_commands(ip, username, password, ["reboot", "y"]) return f"{ip}: upgrade initiated"这个框架里每一步都有检查点,任何一步失败都会记录错误并跳过该设备,不影响其他设备的升级。实际使用的时候,建议把每一步的输出都写到日志文件里,方便事后排查。
5. 升级后的验证与异常处理
5.1 重启后的连通性验证
设备重启完成后,第一件事是验证连通性。用ping测试管理IP是否可达:
ping -c 5 192.168.1.1如果ping不通,先别慌。S5700系列重启后需要几分钟才能完全启动,期间管理口可能不响应。等5分钟再试。如果还是不通,通过Console口连上去看启动日志,确认是卡在哪个阶段。
连通性恢复后,登录设备检查版本:
display version确认输出的版本号是目标版本。同时检查运行时间:
display version | include uptime运行时间应该是几分钟,说明设备确实重启过了。
5.2 配置完整性与业务验证
版本确认后,检查配置是否完整。重点看几个方面:
- 管理IP是否还在
- VLAN配置是否正常
- 上行口和下行口的状态是否正常
- 如果有堆叠配置,堆叠状态是否正常
命令示例:
display ip interface brief display vlan display interface brief display stack业务验证方面,如果设备下挂了终端,确认终端能正常获取IP、能访问网关。如果是接入层设备,确认上行链路的光模块或电口状态正常。
5.3 常见异常与回退操作
升级后最常见的异常有三种:
第一种:设备起不来。表现是Console口有输出但一直卡在启动阶段,或者反复重启。这种情况通常是固件文件损坏或者启动项配置错误。处理方法是通过Console口进入BootROM菜单,手动指定启动文件或者回退到备用启动项。
第二种:版本回退。设备起来了,但版本还是旧的。原因是启动项没改成功,或者设备有多个启动项配置,实际加载的不是你改的那个。检查命令:
display startup看Current startup system software和Next startup system software是否一致。
第三种:配置丢失。设备起来了,版本也对了,但配置没了。这种情况通常是升级前没保存配置,或者新固件不兼容旧配置。如果有备份,通过SFTP把备份的vrpcfg.zip传回去,然后:
startup saved-configuration flash:/vrpcfg.zip reboot回退操作的关键是提前准备好旧固件文件和配置文件,并且确认Console口可用。我自己的习惯是,升级前把旧固件和配置文件放在跳板机的一个固定目录里,命名规则是设备IP_旧版本_日期,这样万一需要回退,能快速找到对应的文件。
6. 实操中积累的几个关键经验
6.1 升级窗口的选择与时间预估
升级窗口建议选在业务低峰期,比如凌晨或者周末。但要注意,有些设备承载着监控、门禁等7x24小时业务,这些设备的升级需要单独协调。
时间预估方面,单台设备的完整升级流程(上传、校验、切换、重启、验证)大约需要10到15分钟。批量升级的时候,因为可以并发操作,总时间大约是单台时间 × 批次数。比如50台设备,分10批,每批5台,总时间大约是15分钟 × 10 = 150分钟,加上中间的观察时间,预留3到4个小时比较稳妥。
6.2 密码管理与安全审计
批量脚本里会用到设备密码,这些密码不能明文写在脚本里。我的做法是用环境变量或者加密的配置文件存储密码,脚本运行时读取。另外,跳板机本身要限制访问权限,只有运维人员能登录。
安全审计方面,每次升级操作都要记录:谁操作的、什么时候、升级了哪些设备、结果如何。这些日志保留至少半年,方便事后追溯。
6.3 固件文件的版本管理
固件文件建议统一存放在跳板机的一个目录里,按型号和版本号组织:
/firmware/S5700/S5700-EI/V200R019C10/ /firmware/S5700/S5700-SI/V200R019C10/每个版本目录里放固件包、MD5校验文件、发布说明。这样升级的时候不容易拿错文件,也方便回退的时候找旧版本。
6.4 批量升级的批次划分策略
批次划分不能简单按IP顺序切。我的做法是按业务重要性分组:先升级非核心业务设备,观察一天没问题后再升级核心业务设备。同一批次里,尽量包含不同型号的设备,这样万一某个型号有问题,能快速定位是型号相关还是普遍问题。
另外,每批设备里留一台作为"哨兵",先升这一台,等15分钟确认没问题再升同批的其他设备。这个做法虽然会拉长总时间,但能有效控制风险。
7. 从手动到自动的过渡建议
如果你之前一直是手动升级,不建议一上来就全自动化。可以分三步走:
第一步,先用脚本做信息采集。把所有设备的当前版本、Flash空间、运行时间拉一遍,生成报表。这一步不涉及任何变更操作,风险为零,但能让你对设备现状有清晰的认识。
第二步,用脚本做单台设备的完整升级。选一台非核心设备,用脚本走完上传、校验、切换、重启、验证的全流程。这一步的目的是验证脚本的可靠性,同时积累异常处理经验。
第三步,才是批量升级。从少量设备开始,逐步扩大范围。每次升级后都做完整的验证,确认没问题再继续。
这个过渡过程可能需要几周时间,但比直接上批量要稳妥得多。我见过太多人一上来就写个循环把所有设备刷一遍,结果中间出了点问题,几十台设备同时失联,那场面想想都头疼。
最后分享一个我自己的小习惯:每次升级前,把跳板机的系统时间同步一下,确保日志里的时间戳是准确的。这个细节看起来不起眼,但事后排查问题的时候,准确的时间戳能帮你快速定位到具体是哪一步出了差错。