给服务器做系统升级(yum update、dnf upgrade、apt upgrade)本来是常规操作,但它也是最容易"翻车"的操作之一。可能升级到一半卡住、报依赖冲突、GPG 校验失败、磁盘空间不足半途而废,甚至升级完内核重启后机器再也起不来。老手都知道:生产服务器的升级不是"敲一条命令"那么简单,它是有风险、需要预案、需要回滚方案的变更。 一个没有快照、没读过 release notes、在业务高峰期跑的 apt upgrade,足以让一次本来十几分钟的操作演变成几小时的故障。
这篇文章围绕"升级失败"这个主题,讲清楚几类最常见的失败原因和处理办法:软件源不可用、GPG key 缺失、镜像过期、依赖冲突、磁盘空间不足、内核升级后无法启动,以及最重要的——怎么回滚。同时给出升级前该做的准备(快照、分批、读 release notes)。读完你应该能把"升级"从一件碰运气的事,变成一件有章法、可回退的事。
一、升级前必须做的事
先讲准备,因为很多"升级失败"其实可以在动手前就避免。
- 读 release notes / 变更说明:尤其是大版本升级(如 CentOS 7→8、Ubuntu 20.04→22.04),重大变更、废弃的包、配置文件格式变化都在里面。不要盲升。
- 做快照或备份:云服务器做系统盘快照;物理机/虚拟机做镜像或快照(LVM、VMware snapshot)。这是回滚的底气。
- 确认磁盘空间:升级会下载大量包并保留旧包。
/var、/boot、/都要留够空间(/boot尤其容易满,内核包都放这里)。 - 选维护窗口:升级可能需要重启,安排在业务低峰。
- 分批灰度:多台机器先升一台(最好是非核心或测试环境)验证,没问题再滚动升级其余。
- 记录当前状态:当前内核版本、关键包版本、
uname -r、服务列表,便于对比和回滚。
# 升级前记录基线
uname -r > /root/pre-upgrade.txt
rpm -qa | sort >> /root/pre-upgrade.txt # RHEL 系
dpkg -l | sort >> /root/pre-upgrade.txt # Debian 系
df -h >> /root/pre-upgrade.txt
free -h >> /root/pre-upgrade.txt
风险提示:云快照要确认是"整盘快照"且可回滚;回滚快照通常会丢失快照之后的数据,所以回滚前要先备份"快照之后产生的新数据"。物理机做 LVM 快照要预留足够的 CoW 空间。
二、失败类型一:软件源不可用 / 镜像过期
最常见的报错:
Could not resolve host: mirror.example.com
Failed to download metadata for repo 'base': Cannot download repomd.xml
404 Not Found
原因通常是:镜像源地址失效(老版本发行版被移出主镜像)、DNS 解析不了、网络不通、或者镜像同步不完整。
# RHEL/CentOS/Rocky:查看当前源
cat /etc/yum.repos.d/*.repo
dnf repolist -v # 看各源状态和地址
dnf clean all # 清缓存重来
dnf makecache
# 换源(以 Rocky 为例,改成就近镜像或官方 vault)
# CentOS 7 已 EOL,官方源移到了 vault:
# baseurl=https://vault.centos.org/7.9.2009/os/x86_64/
sudo vi /etc/yum.repos.d/CentOS-Base.repo
# Debian/Ubuntu:查看当前源
cat /etc/apt/sources.list
ls /etc/apt/sources.list.d/
apt update # 看具体哪个源报错
# 换源(Ubuntu 示例,改到就近镜像)
sudo sed -i 's|http://archive.ubuntu.com|https://mirrors.example.com|g' /etc/apt/sources.list
要点:老版本(如 CentOS 7、Ubuntu 18.04)的生命周期结束后,官方源会失效或迁移到归档(vault/old-releases)。这时要么把源改为归档地址,要么升级到受支持的版本。只改源地址不能解决"EOL"的本质问题,长期看要规划版本升级。
验证网络和 DNS:
dig +short mirrors.example.com
curl -I https://mirrors.example.com
ping -c 3 mirrors.example.com
三、失败类型二:GPG key 校验失败
报错:
Public key for package.rpm is not installed
GPG signature verification failed
NO_PUBKEY XXXXXXXXXXXXXXXX
原因:源换了、但对应的 GPG 公钥没导入,或密钥过期。
# RHEL/CentOS/Rocky:导入 RPM 公钥
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-
# 或从源提供的地址导入
sudo rpm --import https://example.com/RPM-GPG-KEY-example
# 查看已导入的 key
rpm -qa gpg-pubkey*
rpm -qi gpg-pubkey-xxxx
# Debian/Ubuntu:导入 apt key(现代方式)
sudo apt install -y ca-certificates curl gnupg
curl -fsSL https://example.com/key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/example.gpg
# 然后在 sources.list 里加上 signed-by=/usr/share/keyrings/example.gpg
风险提示:导入 GPG key 等于信任该源的软件包签名。只从官方或可信渠道获取 key,不要为了"能装上"就随便 --nogpgcheck。--nogpgcheck(RPM)或 --allow-unauthenticated(apt)会跳过签名校验,等于关掉安全防线,极易引入被篡改的包。只有在完全清楚风险、且有其他校验手段时才临时使用。
四、失败类型三:依赖冲突
这是最让人头疼的一类。报错诸如:
Error: Package X requires Y, but none of the providers can be installed
file /usr/bin/foo conflicts between attempted installs of ...
dpkg: error processing package X (--configure): dependency problems
依赖冲突的根因通常是:混用了多个源(如同时启用了官方源和 EPEL/第三方源)、手动装过某些包导致版本打架、或升级跨了大版本。
# RHEL/CentOS/Rocky 侧
# 1. 看到底缺什么
dnf upgrade --best # 严格按最佳版本升级,冲突会明确报出
# 2. 允许替换/降级来解冲突(谨慎!会卸载或降级包)
sudo dnf upgrade --allowerasing
sudo dnf distro-sync # 把包同步到仓库中的版本,可解决版本漂移
# 3. 只更新指定包
sudo dnf update
# 4. 排除某个包
sudo dnf update --exclude=
# Debian/Ubuntu 侧
sudo apt update
sudo apt install -f # 尝试修复损坏的依赖
sudo apt --fix-broken install
sudo dpkg --configure -a # 配置所有未配置完的包
sudo apt full-upgrade # 会安装/移除更多包,比 upgrade 更激进
风险提示:dnf upgrade --allowerasing 和 apt full-upgrade 可能卸载一些包(包括你可能需要的),执行前务必看清它要移除什么,尤其是它是否打算移除关键服务。distro-sync 会把包强制对齐到仓库版本,可能降级,可能影响依赖它的应用。这些操作在有快照的前提下做,或至少先 dnf upgrade --assumeno / apt -s install 模拟一遍看结果。
模拟(不实际执行)是解依赖冲突前必做的一步:
# RHEL 系:模拟升级,看看会做什么
sudo dnf upgrade --assumeno
# Debian 系:模拟
sudo apt -s upgrade
sudo apt -s full-upgrade
五、失败类型四:磁盘空间不足
升级到一半报:
Error: Transaction check error: installing package ... needs X KB on the / filesystem
No space left on device
升级需要下载包、解包、保留旧版本,空间需求往往被低估。
# 看各分区空间
df -h
df -i # inode 也可能满
# 清理包缓存(安全操作)
# RHEL/CentOS/Rocky
sudo dnf clean all
sudo dnf autoremove # 移除不再需要的依赖
# Debian/Ubuntu
sudo apt clean
sudo apt autoremove
# 重点检查 /boot,内核多了会满
ls -lh /boot
df -h /boot
# 删除旧内核(务必保留当前和至少一个可回退的旧内核!)
# RHEL 系
sudo dnf remove --oldinstallonly --setopt installonly_limit=3 # 保留 3 个内核
# Debian 系
sudo apt --purge autoremove
风险提示:清理 /boot 里的旧内核能快速释放空间,但绝对不能把当前正在运行的内核和它的配套文件删掉。保留 uname -r 对应的内核,并至少留一个旧的可用内核(GRUB 里能选)。删内核前先 ls /boot 确认,用包管理器删(dnf remove kernel-<旧版本> / apt purge linux-image-<旧版本>),不要手动 rm。
清理日志和临时文件也能救急:
sudo journalctl --vacuum-size=200M # 限制 journal 占用
sudo journalctl --vacuum-time=7d
# 找大文件(谨慎,确认后再删)
sudo du -xh /var | sort -rh | head -20
六、失败类型五:内核升级后无法启动
最严重的一类。升级内核后重启,卡在 GRUB、黑屏、或 Kernel Panic。常见原因:新内核与驱动(尤其第三方闭源驱动、GPU 驱动、RAID 卡驱动)不兼容、initramfs 生成失败、或磁盘/{boot 分区有损坏。
先想办法启动到旧内核
在 GRUB 菜单选旧内核:
# 先进 GRUB 菜单(重启时按 Esc / Shift)
# 选 "Advanced options for ..." → 选上一个可用内核启动
# RHEL 系可以设默认启动内核
grubby --info=ALL | grep -E 'index|kernel'
grubby --set-default /boot/vmlinuz-<旧版本>
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# Debian/Ubuntu
grep -E 'menuentry|linux' /boot/grub/grub.cfg | head
sudo update-grub
能进系统后,重新生成 initramfs 或修复驱动:
# 重新生成当前内核的 initramfs
# RHEL 系
sudo dracut -f --regenerate-all
# Debian 系
sudo update-initramfs -u -k all
# 查看 dkms 状态(第三方驱动,如 NVIDIA、虚拟化增强驱动)
dkms status
# 如果 dkms 模块没为新内核构建,重新构建
sudo dkms autoinstall
如果连 GRUB 都进不去
用救援模式(安装介质/云控制台):
# 救援模式进入后,挂载原系统
# 检查 /boot 分区是否损坏
fsck -y /dev/sda1 # 注意:对正在使用的设备不能 fsck,救援模式下先 umount
# 重建 GRUB
chroot /mnt/sysroot
grub2-install /dev/sda # RHEL 系 BIOS
grub2-mkconfig -o /boot/grub2/grub.cfg
风险提示:grub2-install、fsck 这类操作直接影响引导,做错会导致系统彻底起不来。操作前尽量对系统盘做快照或镜像。救援模式下操作要格外小心设备名称。
七、回滚:升级失败的后路
回滚是升级方案里必须提前想好的部分。
1. 包管理器的历史回滚
RHEL/CentOS/Rocky 的 dnf/yum 有事务历史,可以撤销某次操作:
# 查看历史
sudo dnf history
sudo dnf history list
# 看某次事务的详情
sudo dnf history info
# 回滚某次事务(撤销它做的更改)
sudo dnf history undo
sudo dnf history rollback # 回滚到该事务之前的状态
注意:history undo 依赖缓存和仓库里还有旧版本包,如果包已被清理或旧版本下架,回滚可能失败。
2. Debian/Ubuntu 的降级
# 查看某个包有哪些版本可用
apt-cache policy
apt list -a
# 安装指定旧版本
sudo apt install =
# 例如:sudo apt install nginx=1.18.0-0ubuntu1
# 使用 apt 的日志找升级前的版本
grep -i 'upgrade' /var/log/apt/history.log | tail -20
注意:apt 没有 dnf 那样的一键 undo。降级要手动指定版本,且可能引发新的依赖问题。降级前看好 apt-cache policy 里的可用版本,最好有快照兜底。
3. 快照恢复(最可靠)
云服务器回滚系统盘快照、虚拟机回滚 snapshot、LVM 回滚。这是最彻底也最可靠的方案。
# LVM 快照回滚(示例,务必确认设备名和快照正确)
sudo lvconvert --merge /dev/vg0/snap_root
# 注意:merge 后该快照会被删除,且需要在相关卷未挂载时进行
# 云平台/虚拟化:在控制台选择快照 → 回滚
风险提示:回滚快照会丢失快照之后写入的所有数据。回滚前,务必先备份"快照时间点之后"产生的新数据(数据库、用户上传文件等)。这是回滚最容易被忽略、代价也最大的一点。
八、一套升级流程建议
把上面内容整理成可执行流程:
| 阶段 | 动作 | 命令/工具 |
|---|---|---|
| 升级前 | 读 release notes | 官方文档 |
| 升级前 | 做快照/备份 | 云快照、VM snapshot、LVM |
| 升级前 | 记录基线 | rpm -qa/dpkg -l、uname -r |
| 升级前 | 检查空间 | df -h、df -i |
| 升级前 | 模拟 | dnf upgrade --assumeno、apt -s upgrade |
| 升级中 | 单台/灰度先升 | 先在测试机或非核心机 |
| 升级中 | 校验服务 | systemctl --failed、业务探活 |
| 升级后 | 重启并验证 | 保留旧内核可回退 |
| 失败时 | 回滚 | dnf history undo、apt install 版本、快照 |
| 失败时 | 内核起不来 | GRUB 选旧内核、救援模式 |
常见问题
Q:dnf update 报依赖冲突,能否直接 --allowerasing?
先不要。--allowerasing 会卸载冲突的包,可能把你需要的组件也卸掉。先用 dnf upgrade --assumeno 模拟,看清它要移除什么,确认可接受再执行,且务必有快照。
Q:apt upgrade 和 apt full-upgrade 有什么区别?
upgrade 不会为了升级而移除已安装的包,遇到需要移除包的升级会保留;full-upgrade 会为了完成升级而安装或移除包,更激进,能解决部分依赖问题。生产环境用哪个都要先 -s 模拟。
Q:升级内核后起不来,最快的恢复办法?
GRUB 里选旧内核启动,进系统后重新生成 initramfs 或重建 dkms 驱动。若 GRUB 也进不去,用云控制台救援模式或安装介质修复。
Q:升级到一半断电/断网中断了怎么办?
先用包管理器修复半完成状态:RHEL 系 dnf check、dnf distro-sync、rpm -Va;Debian 系 dpkg --configure -a、apt --fix-broken install。再决定继续还是回滚。
Q:能直接 yum update 跨大版本(比如 CentOS 7 到 8)吗?
不能。跨大版本要用专门的升级工具(如 leapp、do-release-upgrade),且风险高、需充分测试。直接改源 update 常导致系统损坏。
Q:升级后服务起不来了,一定是升级的锅吗?
大概率是(新版本改了配置格式、默认行为或废弃了参数)。先看服务日志和 /etc 下是否有 .rpmnew/.rpmsave/.dpkg-dist 配置文件,对比新版默认值与旧配置,手工合并。
总结
系统升级失败的处理,核心是"先有准备、后有回滚"。升级前做快照、读变更说明、查空间、模拟一遍、分批灰度,能挡掉大部分事故。
常见失败类型及对策:软件源不可用 → 换源或改归档地址;GPG 校验失败 → 从可信渠道导入 key(不要随便关校验);依赖冲突 → 先模拟,再用 --allowerasing/distro-sync/apt -f install,谨慎操作;磁盘不足 → 清理缓存和旧内核(别删当前内核);内核升级起不来 → GRUB 选旧内核或救援模式。
回滚手段:RHEL 系用 dnf history undo/rollback,Debian 系用 apt install <包>=<版本> 降级,最可靠的是快照/镜像恢复。回滚前务必备份快照之后的新数据。
把升级当成一次正式变更来对待:有快照、有预案、有验证、有回滚,比任何"快速搞定"的技巧都重要。
企业QQ咨询




