1. 从一个不起眼的磁盘告警说起
手里管着一批基于 N100 处理器的迷你节点,用途比较杂:有的跑轻量容器,有的做边缘采集,有的当测试沙箱。这批机器有个共同特点——板载 eMMC 或者小容量 SSD 只有 32GB 到 64GB,出厂预装的 Ubuntu Server 镜像一装完,df -h一看就让人心里发紧:根分区动不动就吃掉 8 到 12 个 G,留给业务的空间捉襟见肘。
真正让我下决心动手的,是某次批量部署时磁盘告警集中爆发。十几个节点同时报根分区使用率超过 85%,排查下来发现罪魁祸首不是业务数据,而是系统里塞了一大堆根本用不上的固件包(firmware)。这些包是 Ubuntu 为了兼容尽可能多的硬件而预装的,里面躺着各种无线网卡、显卡、声卡、蓝牙、打印机的固件二进制文件。而 N100 这类迷你主机,网卡是板载的有线网卡,显卡是核显,声卡基本不用,蓝牙和打印机更是八竿子打不着。
于是我做了一轮系统性的固件包精简,实测下来每个节点稳定省出约 450 MB 的磁盘空间,而且系统运行没有任何异常。这篇文章就把整个思路、操作步骤、踩过的坑和验证方法完整地讲一遍,适合手里管着一批小容量 Linux 节点、想做系统瘦身的朋友参考。不管你是刚接触 Linux 运维的新手,还是已经管过几十台机器老手,这套方法都能直接抄作业。
2. 先搞清楚 Ubuntu 的固件包到底装了什么
2.1 固件包的本质:给硬件用的“驱动程序数据”
很多人把固件(firmware)和驱动(driver)混为一谈,其实两者不是一回事。驱动是内核里运行的代码,负责和硬件对话;固件则是烧录在硬件芯片里或者由系统在启动时加载到硬件里的一段二进制数据,硬件靠它才能正常工作。Linux 内核为了支持某个硬件,往往需要把对应的固件文件放到/lib/firmware目录下,硬件初始化时内核会去这个目录找。
Ubuntu 把这些固件文件打包成了一堆.deb包,统一放在linux-firmware这个元包下面。你装系统的时候,安装器默认会把linux-firmware以及一堆细分固件包全装上,因为它不知道你这台机器到底有什么硬件,索性全都给你备着。这就是空间被吃掉的根源。
2.2 用一条命令看清固件包的家底
动手之前先摸清现状。在 Ubuntu 22.04 或 24.04 上,执行下面这条命令,把所有已安装的固件相关包按占用空间从大到小列出来:
dpkg-query -W -f='${Installed-Size}\t${Package}\n' | grep -i firmware | sort -rn | head -30${Installed-Size}的单位是 KB,所以看到 100000 就是大约 100 MB。我实测的一台 N100 节点上,排在前面的通常是这几个:
| 包名 | 大致占用 | 用途 |
|---|---|---|
| linux-firmware | 300-500 MB | 固件总元包,依赖下面一堆细分包 |
| linux-firmware-intel | 100-200 MB | Intel 平台相关固件 |
| linux-firmware-iwlwifi | 50-100 MB | Intel 无线网卡固件 |
| linux-firmware-realtek | 30-80 MB | Realtek 网卡/声卡固件 |
| linux-firmware-bluetooth | 20-50 MB | 蓝牙固件 |
| linux-firmware-amdgpu / nvidia | 视情况 | 独显固件,N100 用不上 |
这里有个关键点:linux-firmware本身是个“元包”,它通过依赖关系把细分包拉进来。你直接apt remove linux-firmware会把整个固件体系连根拔起,风险很大。正确做法是精准移除那些用不上的细分包,保留核心的。
2.3 为什么不能一刀切全删
我见过有人图省事,直接apt purge linux-firmware*,结果重启后网卡不认了,机器直接失联,只能抱着显示器键盘去现场救。原因很简单:N100 的板载有线网卡(通常是 Intel I225/I226 或 Realtek RTL8111/8168 系列)也需要固件,你把 realtek 或 intel 的固件包删了,网卡初始化就失败。
所以精简的核心原则是:保留有线网卡和存储控制器相关的固件,砍掉无线、蓝牙、独显、声卡、打印机、扫描仪这些用不上的。下面这张表是我总结的取舍清单,可以直接对照:
| 固件类别 | N100 节点是否需要 | 处理建议 |
|---|---|---|
| 有线网卡(Intel/Realtek) | 需要 | 保留 |
| 存储控制器(NVMe/SATA) | 需要 | 保留 |
| 核显(Intel i915) | 需要 | 保留 |
| 无线网卡(iwlwifi/ath) | 不需要 | 移除 |
| 蓝牙 | 不需要 | 移除 |
| 独立显卡(AMD/NVIDIA) | 不需要 | 移除 |
| 声卡 | 一般不需要 | 可移除 |
| 打印机/扫描仪 | 不需要 | 移除 |
| 电视卡/摄像头 | 不需要 | 移除 |
3. 精简前的准备工作:别急着动手
3.1 先确认硬件清单,避免误删
在删任何东西之前,先用命令把当前机器的硬件摸清楚。最关键的是网卡型号,因为它决定了你必须保留哪些固件:
lspci -nn | grep -Ei 'ethernet|network|vga|audio'输出里会看到类似Ethernet controller [0200]: Intel Corporation ... [8086:125c]这样的信息,方括号里的8086:125c就是厂商 ID 和设备 ID。记下有线网卡的厂商 ID,Intel 是8086,Realtek 是10ec。这样你就知道该保留哪个固件包。
同时看一眼当前根分区的使用情况,作为精简前的基线:
df -h /3.2 做好回滚预案,这是保命操作
精简固件包属于“改系统底层”的操作,万一删错了导致硬件不认,你得有办法恢复。我的做法是两条腿走路:
第一,操作前先记录当前所有固件包的完整列表,方便出问题时对照恢复:
dpkg-query -W -f='${Package}\n' | grep -i firmware > ~/firmware-backup-list.txt第二,如果节点支持 IPMI、串口或者你手边有显示器键盘,确保能物理接触。纯远程操作的节点,建议先在一台非关键机器上验证整套流程,确认没问题再批量推。
提示:如果你的节点是远程托管、完全无法物理接触,精简固件包的风险要格外谨慎。至少保留一个可用的带外管理通道,或者确保有线网卡固件绝对不被误删。
3.3 确认内核版本和固件加载机制
Ubuntu 22.04 之后,固件加载走的是内核的request_firmware机制,固件文件放在/lib/firmware。你可以用dmesg看看当前系统实际加载了哪些固件,这能帮你判断哪些是真正在用的:
dmesg | grep -i firmware | head -40输出里会显示类似Direct firmware load for iwlwifi-xxx.ucode的记录。如果某个固件加载失败,说明系统在找它但没找到,这种要留意;如果压根没出现某个硬件的固件加载记录,说明这台机器根本不需要它。
4. 核心实操:一步步把 450 MB 省出来
4.1 第一步:移除无线网卡和蓝牙固件
这是省空间的大头。N100 迷你主机绝大多数没有无线网卡,即使有,做服务器用途也用不上。执行:
sudo apt purge linux-firmware-iwlwifi linux-firmware-atheros \ linux-firmware-brcm linux-firmware-mediatek \ linux-firmware-bluetoothapt purge比apt remove更彻底,会连配置文件一起清掉。执行完apt autoremove把不再需要的依赖也清理掉:
sudo apt autoremove --purge这一步通常能省出 100 到 200 MB。注意包名可能因 Ubuntu 版本略有差异,如果某个包不存在,apt 会提示,忽略即可,不影响其他包。
4.2 第二步:移除独立显卡固件
N100 只有 Intel 核显,AMD 和 NVIDIA 的固件完全用不上:
sudo apt purge linux-firmware-amdgpu linux-firmware-nvidia \ linux-firmware-radeon有些版本里这些固件被打包在linux-firmware主包里而不是独立包,如果 purge 提示找不到包,说明它们被合并了,这时候需要换一种方式处理,见 4.5 节的手动清理法。
4.3 第三步:移除打印机、扫描仪、电视卡等外设固件
这些固件平时几乎没人注意,但加起来也有几十兆:
sudo apt purge linux-firmware-ivtv linux-firmware-i2400m \ linux-firmware-libertas linux-firmware-mwl8k \ linux-firmware-qlogic linux-firmware-siano这里要说明一下,linux-firmware-libertas是某些老无线网卡的固件,linux-firmware-ivtv是电视卡固件,linux-firmware-qlogic和linux-firmware-siano是特定品牌网卡/存储卡的固件。N100 节点用不到这些,放心删。
4.4 第四步:清理旧内核和残留固件
Ubuntu 每次内核升级都会保留旧版本,旧内核对应的固件模块也会占空间。先看看装了哪些内核:
dpkg --list | grep -E 'linux-image|linux-modules' | awk '{print $2}'保留当前正在运行的内核和最近一个备用内核,其余可以清掉。当前内核版本用uname -r查看。清理命令:
sudo apt purge linux-image-<旧版本号> linux-modules-<旧版本号>这一步视你系统升级过多少次,通常能再省 100 到 200 MB。
4.5 第五步:手动清理 /lib/firmware 里的冗余文件
有些固件文件即使对应的包被移除了,也可能残留在/lib/firmware目录里。更常见的情况是,某些固件被合并进了主包,没法通过 apt 单独移除。这时候可以手动清理,但要格外小心。
先看看/lib/firmware里哪些子目录占用最大:
sudo du -sh /lib/firmware/* | sort -rh | head -20你会看到类似amdgpu、nvidia、iwlwifi、mellanox这样的大目录。对于确认用不上的,可以手动删除:
sudo rm -rf /lib/firmware/amdgpu /lib/firmware/nvidia /lib/firmware/mellanox注意:手动删除
/lib/firmware下的文件是不可逆的(除非重装固件包),删之前务必确认该硬件在这台机器上不存在。删完后建议重启一次,观察dmesg有没有固件加载失败的报错。
4.6 精简效果实测对比
我在三台不同配置的 N100 节点上跑了完整流程,记录如下:
| 节点 | 精简前根分区占用 | 精简后根分区占用 | 节省空间 |
|---|---|---|---|
| 节点 A(32GB eMMC) | 9.2 GB | 8.7 GB | 约 480 MB |
| 节点 B(64GB SSD) | 11.5 GB | 11.0 GB | 约 460 MB |
| 节点 C(32GB eMMC) | 8.8 GB | 8.4 GB | 约 420 MB |
三台平均下来每个节点省了约 450 MB,和标题里的数字吻合。这个数字会因为你系统里原本装了多少固件包而浮动,装得越多省得越多。
5. 精简后的验证与常见问题排查
5.1 重启后必须做的三项检查
删完固件包千万别直接收工,重启一次,然后做三项检查:
第一,确认网络正常。这是最关键的,因为网卡固件被误删会直接导致失联:
ip a ping -c 3 网关地址第二,检查内核日志有没有固件加载失败:
dmesg | grep -i 'firmware.*fail\|failed to load'如果出现某个硬件的固件加载失败,而那个硬件你确实在用,就得把对应的固件包装回来。
第三,确认磁盘空间确实释放了:
df -h /5.2 常见问题速查表
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 重启后网卡消失 | 误删了有线网卡固件 | 物理接触机器,重装对应固件包 |
| 屏幕分辨率异常 | 误删了核显固件 | 重装 linux-firmware-intel |
| dmesg 报固件加载失败 | 删了正在用的固件 | 根据报错信息重装对应包 |
| apt purge 提示包不存在 | 固件被合并进主包 | 改用手动清理 /lib/firmware |
| 省的空间没到 450 MB | 系统原本固件装得少 | 属正常,按实际硬件情况浮动 |
5.3 出问题了怎么恢复
万一删错了导致硬件不认,恢复方法取决于你还能不能操作这台机器。如果还能进系统(比如只是声卡没了),直接重装固件包:
sudo apt install --reinstall linux-firmware如果连网卡都没了、远程进不去,就得物理接触机器,用之前备份的firmware-backup-list.txt对照着把包装回来。这也是为什么我在 3.2 节反复强调要先备份列表、先确认能物理接触。
5.4 几个容易踩的坑
第一个坑是apt autoremove误伤。执行autoremove时它会自动判断哪些包“不再被需要”,有时候会把你还需要的东西一起删了。建议执行前先加--dry-run看一眼它打算删什么:
sudo apt autoremove --purge --dry-run确认列表里没有你要保留的包,再去掉--dry-run真正执行。
第二个坑是内核升级后固件包被重新拉回来。Ubuntu 升级内核时,linux-firmware元包可能会被重新安装,把你删掉的细分包又带回来。解决办法是把这些包标记为“手动不安装”,或者在内核升级后重新跑一遍精简脚本。我自己的做法是写了个小脚本,每次内核升级后自动执行一遍清理,省得手动重复。
第三个坑是不同 Ubuntu 版本的包名差异。22.04 和 24.04 的固件包拆分方式不完全一样,有些包在 24.04 里被合并了。所以上面的命令不要无脑照抄,先用 2.2 节的命令看清你系统里实际有哪些包,再针对性地删。
6. 把这套流程做成可复用的脚本
手动敲一遍命令没问题,但如果你手里有几十台节点,逐台操作太累。我把整套流程整理成了一个脚本,核心逻辑是:先检测硬件,再根据硬件决定保留哪些固件,最后批量清理。脚本的关键片段如下:
#!/bin/bash # 固件精简脚本,适用于 N100 类迷你节点 set -e echo "=== 当前固件包占用 ===" dpkg-query -W -f='${Installed-Size}\t${Package}\n' | grep -i firmware | sort -rn | head -10 echo "=== 检测有线网卡厂商 ===" lspci -nn | grep -i ethernet echo "=== 开始清理用不上的固件包 ===" PURGE_LIST="linux-firmware-iwlwifi linux-firmware-atheros \ linux-firmware-brcm linux-firmware-mediatek linux-firmware-bluetooth \ linux-firmware-amdgpu linux-firmware-nvidia linux-firmware-radeon \ linux-firmware-ivtv linux-firmware-libertas" for pkg in $PURGE_LIST; do if dpkg -l | grep -q "^ii $pkg"; then echo "移除 $pkg" apt purge -y "$pkg" fi done echo "=== 清理残留依赖 ===" apt autoremove --purge -y echo "=== 清理完成,当前空间 ===" df -h /这个脚本我实测跑下来很稳,但有两个地方要注意:一是set -e会让脚本在任何一个命令失败时立即退出,如果你希望某个包删不掉也继续往下走,可以去掉这行或者改成set +e;二是脚本里没有包含手动清理/lib/firmware的部分,因为那部分风险较高,建议还是人工确认后再操作。
脚本跑完后,同样要重启验证。我一般会把这套流程和验证步骤串成一个完整的部署前检查清单,新节点上线时先跑一遍精简,再装业务,这样从一开始就把空间留足。
7. 一点个人体会
这套固件精简我前后在几十台 N100 节点上跑过,最大的感受是:省空间只是表面收益,真正的价值在于让系统变得“干净可控”。以前系统里躺着一堆不知道干什么用的固件,排查问题时干扰很大;精简之后,/lib/firmware里剩下的都是这台机器真正需要的,出问题时一眼就能看出是哪个硬件的锅。
另外提醒一句,精简固件包这件事没有“一劳永逸”的方案。内核升级、系统大版本更新都可能把固件包重新带回来,所以最好把它当成一个定期维护动作,而不是一次性操作。我现在的习惯是每次内核升级后顺手跑一遍脚本,花不了两分钟,但能一直保持系统精简。
如果你手里的节点硬件型号比较统一,完全可以针对这个型号定制一份“最小固件清单”,把保留和移除的包固定下来,做成标准镜像。这样新节点部署时直接套用,连检测步骤都省了。